Crate variadic_from

Source
Expand description

§Module :: variadic_from

experimental rust-status docs.rs Open in Gitpod discord

The variadic_from crate provides a powerful procedural macro and helper traits to simplify the creation of flexible constructors for Rust structs. It automates the implementation of From-like traits, allowing structs to be instantiated from a variable number of arguments or tuples, reducing boilerplate and enhancing code readability.

§Features

  • Variadic Constructors: Easily create instances of structs from 0 to 3 arguments using the from! macro.
  • Derive Macro (VariadicFrom): Automatically implements FromN traits and standard From<T>/From<tuple> for structs with 1, 2, or 3 fields.
  • Tuple Conversion: Seamlessly convert tuples into struct instances using the standard From and Into traits.
  • Compile-time Safety: The from! macro provides compile-time errors for invalid argument counts (e.g., more than 3 arguments).
  • No Code Generation for >3 Fields: The derive macro intelligently generates no code for structs with 0 or more than 3 fields, preventing unexpected behavior.

§Quick Start

To get started with variadic_from, follow these simple steps:

  1. Add to your Cargo.toml:

    [dependencies]
    variadic_from = "0.1" # Or the latest version
    variadic_from_meta = { path = "../variadic_from_meta" } # If using from workspace
  2. Basic Usage Example:

    This example demonstrates the use of the variadic_from macro to implement flexible constructors for a struct, allowing it to be instantiated from different numbers of arguments or tuples. It also showcases how to derive common traits like Debug, PartialEq, Default, and VariadicFrom for the struct.

    #[test]
    fn readme_example_basic()
    {
      use variadic_from::exposed::*;
    
      #[ derive( Debug, PartialEq, Default, VariadicFrom ) ]
      struct MyStruct
      {
        a : i32,
        b : i32,
      }
    
      let got : MyStruct = from!();
      let exp = MyStruct { a : 0, b : 0 };
      assert_eq!( got, exp );
    
      let got : MyStruct = from!( 13 );
      let exp = MyStruct { a : 13, b : 13 };
      assert_eq!( got, exp );
    
      let got : MyStruct = from!( 13, 14 );
      let exp = MyStruct { a : 13, b : 14 };
      assert_eq!( got, exp );
    }
  3. Expanded Code Example (What the macro generates):

    This section shows the code that the VariadicFrom derive macro generates for MyStruct (a two-field struct), including the From2 trait implementation and the standard From<(T1, T2)> implementation.

    #[test]
    fn readme_example_expanded()
    {
      use variadic_from::exposed::*;
    
      #[ derive( Debug, PartialEq, Default ) ]
      struct MyStruct
      {
        a : i32,
        b : i32,
      }
    
      impl From2< i32, i32 > for MyStruct
      {
        fn from2( a : i32, b : i32 ) -> Self { Self{ a : a, b : b } }
      }
    
      impl From< ( i32, i32 ) > for MyStruct
      {
        #[ inline( always ) ]
        fn from( ( a, b ) : ( i32, i32 ) ) -> Self
        {
          Self::from2( a, b )
        }
      }
    
      let got : MyStruct = from!();
      let exp = MyStruct { a : 0, b : 0 };
      assert_eq!( got, exp );
    
      let got : MyStruct = from!( 13 );
      let exp = MyStruct { a : 13, b : 13 };
      assert_eq!( got, exp );
    
      let got : MyStruct = from!( 13, 14 );
      let exp = MyStruct { a : 13, b : 14 };
      assert_eq!( got, exp );
    }

§Macro Behavior Details

  • #[derive(VariadicFrom)]:

    • For a struct with 1 field (e.g., struct MyStruct(i32) or struct MyStruct { field: i32 }), it generates:
      • impl From1<FieldType> for MyStruct
      • impl From<FieldType> for MyStruct (delegating to From1)
    • For a struct with 2 fields (e.g., struct MyStruct(i32, i32) or struct MyStruct { a: i32, b: i32 }), it generates:
      • impl From2<Field1Type, Field2Type> for MyStruct
      • impl From<(Field1Type, Field2Type)> for MyStruct (delegating to From2)
      • Additionally, it generates impl From1<Field1Type> for MyStruct (where Field1Type is used for all fields, for convenience).
    • For a struct with 3 fields, similar From3 and From<(T1, T2, T3)> implementations are generated, along with From1 and From2 convenience implementations.
    • For structs with 0 fields or more than 3 fields, the derive macro generates no code. This means you cannot use from! or FromN traits with such structs unless you implement them manually.
  • from! Macro:

    • from!() -> Default::default()
    • from!(arg1) -> From1::from1(arg1)
    • from!(arg1, arg2) -> From2::from2(arg1, arg2)
    • from!(arg1, arg2, arg3) -> From3::from3(arg1, arg2, arg3)
    • from!(...) with more than 3 arguments will result in a compile-time error.

§API Documentation

For detailed API documentation, visit docs.rs/variadic_from.

§Contributing

We welcome contributions! Please see our CONTRIBUTING.md for guidelines on how to contribute.

§License

This project is licensed under the License file.

§Troubleshooting

  • Too many arguments compile error with from! macro: This means you are trying to use from! with more than 3 arguments. The macro currently only supports up to 3 arguments. Consider using a regular struct constructor or manually implementing FromN for more fields.
  • FromN trait not implemented: Ensure your struct has #[derive(VariadicFrom)] and the number of fields is between 1 and 3 (inclusive). If it’s a 0-field or >3-field struct, the derive macro will not generate FromN implementations.
  • Conflicting From implementations: If you manually implement From<T> or From<(T1, ...)> for a struct that also derives VariadicFrom, you might encounter conflicts. Prefer using the derive macro for automatic implementations, or manually implement FromN traits and use the from! macro.

§Project Structure

The variadic_from project consists of two main crates:

  • variadic_from: The main library crate, containing the FromN traits, the from! declarative macro, and blanket implementations.
  • variadic_from_meta: A procedural macro crate that implements the #[derive(VariadicFrom)] macro.

§Testing

To run all tests for the project, including unit tests, integration tests, and doc tests:

cargo test --workspace

To run tests for a specific crate:

cargo test -p variadic_from --all-targets
cargo test -p variadic_from_meta --all-targets

To run only the doc tests:

cargo test -p variadic_from --doc

§Debugging

For debugging procedural macros, you can use cargo expand to see the code generated by the macro. Add #[debug] attribute to your struct to see the expanded code.

cargo expand --example variadic_from_trivial

You can also use a debugger attached to your test runner.

# Example for VS Code with CodeLLDB
# In .vscode/launch.json:
# {
#     "type": "lldb",
#     "request": "launch",
#     "name": "Debug variadic_from_tests",
#     "cargo": {
#         "args": [
#             "test",
#             "--package=variadic_from",
#             "--test=variadic_from_tests",
#             "--no-run",
#             "--message-format=json-render-diagnostics"
#         ],
#         "filter": {
#             "name": "variadic_from_tests",
#             "kind": "test"
#         }
#     },
#     "args": [],
#     "cwd": "${workspaceFolder}"
# }

§Try out from the repository

git clone https://github.com/Wandalen/wTools
cd wTools/module/core/variadic_from # Navigate to the crate directory
cargo run --example variadic_from_trivial

Re-exports§

pub use ::variadic_from_meta::VariadicFrom;

Modules§

dependency
Namespace with dependencies.
exposed
Exposed namespace of the module.
orphan
Orphan namespace of the module.
own
Own namespace of the module.
prelude
Prelude to use essentials: use my_module::prelude::*.
variadic
Internal implementation of variadic From traits and macro.

Macros§

from
Macro to construct a struct from variadic arguments.

Traits§

From1
Trait for converting from one argument.
From2
Trait for converting from two arguments.
From3
Trait for converting from three arguments.

Derive Macros§

VariadicFrom
Derive macro for VariadicFrom.