constduck: compile-time duck typing and reflection

Overview

crates.io docs

constduck: compile-time duck typing and reflection

constduck provides a procmacro that can enable compile time duck typing and reflection on arbitrary struct types. It supports three main features:

  • Accessing fields of any struct, using the field name
  • Constructing instances from a mapping of fields to values
  • Reflecting over field types at compile time

Usage

Derive ConstDuck on a struct:

#![feature(adt_const_params)]
use constduck::*;

#[derive(ConstDuck)]
struct Donald {
    money: i64,
}

Accessing fields

When deriving ConstDuck, the trait Field<"fieldname"> is implemented for all fields of the struct. You can use the trait to write generic implementations. For example:

>(t: &mut T) where N: Clone, N: Sub , N: From { t.set(t.get().clone() - N::from(5i8)); } ">
fn deduct_money
     >(t: 
     &
     mut T) 
    
     where N: 
     Clone,
        N: Sub
     
      ,
        N: 
      From<
      i8> {
    t.
      set(t.
      get().
      clone() 
      - N
      ::
      from(
      5i8));
}
     
    

deduct_money will work for any struct that has a field money and derives ConstDuck.

You should just write a custom trait for the example above. It's not always possible to write a custom trait. For example, consider the following macro:

macro_rules! make_getter {
    ($struct:ident.$field:ident) => {
        impl $struct {
            pub fn $field(&self) -> &/* What to write here? */ {
                &self.$field
            }
        }
    }
}

struct Foo {
    bar: String,
    baz: u32,
}

make_getter!(Foo.bar);

In this case the function definition requires a return type, but you don't have enough information to specify the type. Using constduck, you can write this macro as:

macro_rules! make_getter {
    ($struct:ident.$field:ident) => {
        impl
    $
   struct
            
   where 
   Self: 
   Field<{ stringify!($field) }, Ty = T> {
            
   pub fn $
   field(
   &
   self) 
   -
   > 
   &T {
                
   <
   Self 
   as Field
   <{ 
   stringify!($field) }
   >>
   ::
   get(
   self)
            }
        }
    }
}

#[derive(ConstDuck)]

   struct 
   Foo {
    bar: 
   String,
    baz: 
   u32,
}


   make_getter!(Foo.bar);
  

Constructing instances

If you're storing arbitrary expressions in a new struct in a macro, you cannot use the type of the expression for the field. For example:

macro_rules! create_struct {
    ($struct:ident; $($name:ident: $value:expr),*) => {{
        // For some good reason we want to generate a separate wrapper struct first and return that instead of collecting directly into `$struct`.
        struct WrapperStruct<$($name,)*> {
            $($name: $name,)*
        }

        impl<$($name,)*> From
   <$($name,)*>> 
   for $
   struct {
            
   fn 
   from(wrapper: WrapperStruct<$($name,)*>) -> 
   Self {
                
   // wrapper.counter is not guaranteed to be a u32
                
   // So we cannot do this:
                $struct {
                    counter: wrapper.counter,
                    text: wrapper.text,
                }
            }
        }

        WrapperStruct {
            $($name: $value,)
   *
        }
    }}
}
  

We cannot write a correct implementation for From here, because it's normally not possible to express "type must have two fields counter: u32 and text: String" as a constraint.

By implementing WithField for the wrapper struct, we can write the implementation in the macro like this instead:

impl<$($name,)*> From
   <$($name,)*>> 
   for $
   struct 
    
   where $
   struct: 
   ConstructFrom
   
    <$($name,)*>> {
    
    fn 
    from(wrapper: WrapperStruct<$($name,)*>) -> 
    Self {
        $struct
    ::
    construct(wrapper)
    }
}
   
  

See constduck/examples/construct-instances.rs for a full example.

Reflecting over field types at compile time

Using ConstDuck::Reflect you can implement traits for any type (like #[derive(..)]) without needing a procmacro. See constduck/examples/debug-print.rs for an example.

(In)stability

This project requires Rust nightly, and uses the incomplete adt_const_params feature. You might encounter ICEs. The current API will likely break when support for tuple structs and enums is added.

License

constduck is licensed under the Mozilla Public License 2.0 (MPL2.0). See the LICENSE file.

You might also like...
This is a Telegram bot I'm working on in my free time to learn Rust.

Maldness Bot This is a Telegram bot I'm working on in my free time to learn Rust. Building docker build -t . should be enough.

Rust bindings for the KING OF TIME API

Rust bindings for the KING OF TIME API Example Prints if you are at work or not at work. $ cargo run --example tc -- status Record the time you start

Building a better screen reader for the Linux desktop, one step at a time.

Building a better screen reader for the Linux desktop, one step at a time.

A library and tool for automata and formal languages, inspired by JFLAP
A library and tool for automata and formal languages, inspired by JFLAP

Sugarcubes is a library and application for automata and formal languages. It is inspired by JFLAP, and is intended to eventually to be an alternative to JFLAP.

A stupid macro that compiles and executes Rust and spits the output directly into your Rust code

inline-rust This is a stupid macro inspired by inline-python that compiles and executes Rust and spits the output directly into your Rust code. There

This is a Discord bot written in Rust to translate to and from the Bottom Encoding Standard using bottom-rs and Serenity.
This is a Discord bot written in Rust to translate to and from the Bottom Encoding Standard using bottom-rs and Serenity.

bottom-bot This is a Discord bot written in Rust to translate to and from the Bottom Encoding Standard using bottom-rs and Serenity. Ever had this pro

An implementation of Code Generation and Factoring for Fast Evaluation of Low-order Spherical Harmonic Products and Squares

sh_product An implementation of Code Generation and Factoring for Fast Evaluation of Low-order Spherical Harmonic Products and Squares (paper by John

lightweight and customizable rust s-expression (s-expr) parser and printer

s-expr Rust library for S-expression like parsing and printing parser keeps track of spans, and representation (e.g. number base) number and decimal d

Crates Registry is a tool for serving and publishing crates and serving rustup installation in offline networks.
Crates Registry is a tool for serving and publishing crates and serving rustup installation in offline networks.

Crates Registry Description Crates Registry is a tool for serving and publishing crates and serving rustup installation in offline networks. (like Ver

Owner
ferrouille
ferrouille
Option and Either types with variants known at compile time.

Const Either Some types to allow deciding at compile time if an option contains a value or which variant from the either type is active. This might be

null 1 May 5, 2022
Faster division by constants that aren't known at compile-time

Baseline implementation of division by constants When dividing integers by compile-time constants, compilers (LLVM) can be trusted to convert those to

Paul Khuong 18 Jul 6, 2022
This crate defines a single macro that is a brainfunct compile-time interpreter.

Compile Protection This crate defines a single macro that is a brainfunct compile-time interpreter. One example is as follows #![recursion_limit = "18

John Marsden 7 Nov 29, 2021
Allocate memory at compile time!

const-alloc Link to the docs! Allocate memory at compile time! Currently, in stable rust there is no way to dynamically allocate or deallocate memory

Sp00ph 1 Feb 5, 2022
Compile-time lifetimes for comments.

todo_by Compile-time lifetimes for comments. To use this macro, add it to your dependencies via Cargo: cargo add todo_by Then, import and invoke the m

Parker McMullin 116 May 23, 2023
A Rust proc-macro crate which derives functions to compile and parse back enums and structs to and from a bytecode representation

Bytecode A simple way to derive bytecode for you Enums and Structs. What is this This is a crate that provides a proc macro which will derive bytecode

null 4 Sep 3, 2022
little brother of gnu-copypasta-maker To compile, use make.

UWU Maker little brother of gnu-copypasta-maker To compile, use make. To install, use sudo make install or if you are root make install To uninstall,

Ahmet Efe AKYAZI 1 Jan 12, 2022
A library to access BGPKIT Broker API and enable searching for BGP data archive files over time from public available data sources.

BGPKIT Broker BGPKIT Broker is a online data API service that allows users to search for publicly available BGP archive files by time, collector, proj

BGPKIT 10 Nov 30, 2022
NSE is a rust cli binary and library for extracting real-time data from National Stock Exchange (India)

NSE Check out the sister projects NsePython and SaveKiteEnctoken which are Python & Javascript libraries to use the NSE and Zerodha APIs respectively

Techfane Technologies 4 Nov 28, 2022
A rust library for interacting with multiple Discord.com-compatible APIs and Gateways at the same time.

Chorus A rust library for interacting with (multiple) Spacebar-compatible APIs and Gateways (at the same time). Explore the docs » Report Bug · Reques

polyphony 4 Apr 30, 2023