Giter Site home page Giter Site logo

declarative_enum_dispatch's Introduction

Declarative generation of enum dispatch

Crates.io docs.rs

Generate boilerplate code for dynamic dispatch of a trait using an enum. Also generates From for every enum variant

This is a fully declarative version of enum_dispatch macro

For benchmarks look at enum_dispatch benchmarks crate

use declarative_enum_dispatch::enum_dispatch;

enum_dispatch!(
    /// Supports trait inheritance + lifetime (although single and after traits)
    pub trait ShapeTrait: Clone + std::fmt::Debug + 'static {
        /// No return + default implementation
        fn print_name(&self) {
            println!("name: `{}`", self.name());
        }
        /// Basic call without arguments
        fn name(&self) -> String;
        fn area(&self) -> i32;

        /// Mutable self + arguments
        fn grow(&mut self, numerator: i32, denominator: i32);

        /// Kinda supports generics :) Bot not generic parameters, only `impl Trait`
        fn greater(&self, other: &impl ShapeTrait) -> bool;
        
        /// Supports async methods
        async fn send(&self);

        /// Works with attributes
        #[cfg(feature = "platform_specific")]
        fn platform_specific(self);
    }

    #[derive(Debug, Clone)]
    pub enum Shape {
        Rect(Rect),
        Circle(Circle),
        #[cfg(feature = "platform_specific")]
        Cube(Cube)
    }
);

#[derive(Debug, Clone)]
pub struct Rect{ w: i32, h: i32 }

#[derive(Debug, Clone)]
pub struct Circle { r: i32 }

impl ShapeTrait for Rect {
    fn print_name(&self) {
        println!("rect name: `{}`", self.name());
    }
    fn name(&self) -> String {
        "Rect".to_string()
    }

    fn area(&self) -> i32 {
        self.w * self.h
    }

    fn grow(&mut self, numerator: i32, denominator: i32) {
        self.w = self.w * numerator / denominator;
        self.h = self.h * numerator / denominator;
    }

    fn greater(&self, other: &impl ShapeTrait) -> bool {
        self.area() > other.area()
    }

    async fn send(&self) {}
}

impl ShapeTrait for Circle {
    fn name(&self) -> String {
        "Circle".to_string()
    }

    fn area(&self) -> i32 {
        // close enough PI approximation :)
        3 * self.r * self.r
    }

    fn grow(&mut self, numerator: i32, denominator: i32 ) {
        self.r = self.r * numerator / denominator;
    }

    fn greater(&self, other: &impl ShapeTrait) -> bool {
        self.area() > other.area()
    }

    async fn send(&self) {}
}


assert_eq!(Shape::Rect(Rect { w: 1.0, h: 1.0 }).name(), "Rect".to_string());
assert_eq!(Shape::Circle(Circle { r: 1.0 }).name(), "Circle".to_string());

Roadmap

  • Support generic params
  • Support lifetimes
  • Support trait inheritance
  • Support async functions

Why?

Because I can... Well... RustRover indexing doesn't work with enum dispatch and in one of the threads about this problem I've read

enum_dispatch is a rare example of absolutely IDE-unfriendly macros. It breaks every imaginable rule. With current design, enum_dispatch will never be supported. (source)

So it got me wondering if it can be implemented using declarative macro for "perfect" IDE support, and so... it can)

Yes, I am fixing crate to make it index correctly in my paid IDE.

I WANT MY DAMN AUTOCOMPLETION

declarative_enum_dispatch's People

Contributors

zettroke avatar

Stargazers

Dexter Chen avatar nsfoxer avatar  avatar Wasif avatar Trent avatar  avatar Luxalpa avatar Mikhail Zagurskiy avatar ripytide avatar

Watchers

Wasif avatar  avatar

declarative_enum_dispatch's Issues

doesn't support trailing comma in trait function signature

if the line with function parameters gets too long, rustfmt will separate it onto multiple lines and end each line with a comma like in the example below:

  trait Deserializable {
      fn des_run_in_server(
          self,
          asdfasdfasdfasdfasdf: i32,
      ) -> Pin<Box<dyn Future<Output = ()> + '_>>;
  }

Unfortunately this gives an error:

error: method des_run_in_server should receive self

Multiple implementation

It's possible that a trait might have serveral different sets of implementation, like:

declarative_enum_dispatch::enum_dispatch! {
	trait T { ... }

	enum ImplA { ... }
	
	enum ImplB { ... }
}

Current implementation doesn't support this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.