GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - NyxCode/proxy-enum: Emulate dynamic dispatch and sealed classes using a proxy enum, which defers all method calls to its variants.

BranchesTags
Open more actions menu

Latest commit

 

History

11 Commits
11 Commits

Folders and files

NameName
Last commit message
Last commit date
src
src
 
 
.gitignore
.gitignore
 
 
Cargo.toml
Cargo.toml
 
 
README.md
README.md
 
 

Repository files navigation

proxy-enum

Crate API

Emulate dynamic dispatch and "sealed classes" using a proxy enum, which defers all method calls to its variants.

Introduction

In rust, dynamic dispatch is done using trait objects (dyn Trait). They enable us to have runtime polymorphism, a way of expressing that a type implements a certain trait while ignoring its concrete implementation.

let animal: &dyn Animal = random_animal();
animal.feed(); // may print "mew", "growl" or "squeak"

Trait objects come with a downside though: getting a concrete implementation back from a trait object (downcasting) is painfull. (see [std::any::Any])

If you know there are only a finite number of implentations to work with, an enum might be better at expressing such a relationship:

enum Animal {
    Cat(Cat),
    Lion(Lion),
    Mouse(Mouse)
}

match random_animal() {
    Animal::Cat(cat) => cat.feed(),
    Animal::Lion(lion) => lion.feed(),
    Animal::Mouse(mouse) => mouse.feed()
}

Some languages have special support for such types, like Kotlin with so called "sealed classes".

Rust, however, does not.

proxy-enum simplifies working with such types using procedural macros.

Usage

#[proxy_enum::proxy(Animal)]
mod proxy {
    enum Animal {
        Cat(Cat),
        Lion(Lion),
        Mouse(Mouse)
    }

    impl Animal {
        #[implement]
        fn feed(&self) {}
    }
}

This will expand to:

mod proxy {
    enum Animal {
        Cat(Cat),
        Lion(Lion),
        Mouse(Mouse)
    }

    impl Animal {
        fn feed(&self) {
            match self {
                Animal::Cat(cat) => cat.feed(),
                Animal::Lion(lion) => lion.feed(),
                Animal::Mouse(mouse) => mouse.feed()
            }
        }
    }  

    impl From<Cat> for Animal { /* ... */ }
    impl From<Lion> for Animal { /* ... */ }
    impl From<Mouse> for Animal { /* ... */ }
}

This, however, will only compile if Cat, Lion and Mouse all have a method called feed. Since rust has traits to express common functionality, trait implentations can be generated too:

#[proxy_enum::proxy(Animal)]
mod proxy {
    enum Animal {
        Cat(Cat),
        Lion(Lion),
        Mouse(Mouse)
    }

    trait Eat {
        fn feed(&self);
    }

    #[implement]
    impl Eat for Animal {}
}

Since the macro has to know which methods the trait contains, it has to be defined within the module. However, implementations for external traits can be generated too:

#[proxy_enum::proxy(Animal)]
mod proxy {
    enum Animal {
        Cat(Cat),
        Lion(Lion),
        Mouse(Mouse)
    }

    #[external(std::string::ToString)]
    trait ToString {
        fn to_string(&self) -> String;
    }

    #[implement]
    impl std::string::ToString for Animal {}
}

About

Emulate dynamic dispatch and sealed classes using a proxy enum, which defers all method calls to its variants.

Resources

Readme
Activity

Stars

18 stars

Watchers

2 watching

Forks

2 forks
Report repository

Releases

Packages

Used by

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.