# fromsuper `fromsuper` provides a procedural macro that helps with converting (large) super structs to (smaller) sub structs, by discarding unneeded data. It can also automatically unpack [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html)s during this conversion. It implements [`TryFrom`](https://doc.rust-lang.org/std/convert/trait.TryFrom.html) if `Option`s need to be unpacked, and [`From`](https://doc.rust-lang.org/std/convert/trait.From.html) otherwise. It can be useful e.g., when working with large parser outputs of which only a subset is actually needed. Reducing such structs to the data actually needed improves maintainability. If the original struct contains lots of `Option`s, unpacking them validates that the needed data is present and greatly improves ergonomics of further handling. ## Basic Usage Include `fromsuper` in your project by adding the following to your `Cargo.toml`: ```toml fromsuper = "0.2" ``` You may also want to `use` the derive macro: ```rust use fromsuper::FromSuper; ``` Options for the derive macro are specified by using the `fromsuper` attribute. The only option that is necessary is `from_type`, defining the super struct to convert from: ```rust struct Bar { a: u32, b: String, c: HashSet, d: ComplexData, } #[derive(FromSuper)] #[fromsuper(from_type = "Bar")] struct Foo { a: u32, c: HashSet, } let bar = Bar { ... }; let foo: Foo = bar.into(); // using Foo's derived implementation of From ``` If a sub struct's field is not named the same as the original one, the field attribute `rename_from` can be used to specify the mapping: ```rust #[derive(FromSuper)] #[fromsuper(from_type = "Bar")] struct Foo { a: u32, #[fromsuper(rename_from = "c")] new_name: HashSet, } ``` ## Unpacking `Option`s The automatic unpacking of `Option`s from the original struct can be enabled by adding the `unpack` argument. Individual fields can opt-out of the unpacking (`unpack = false`), e.g., when not all original fields are `Option`s, or when you can tolerate `None` values. Also, for field types that implement `Default`, `None` values can be replaced by the default value by specifying `unpack_or_default = true`. When unpacking is enabled, `TryFrom` is implemented instead of `From`, in order to fail when required values are `None`: ```rust struct Bar { a: Option, b: String, c: Option>, d: Option, e: Option } #[derive(FromSuper)] #[fromsuper(from_type = "Bar", unpack = true)] struct Foo { #[fromsuper(unpack = false)] b: String, #[fromsuper(unpack_or_default = true)] c: HashSet, d: ComplexData, #[fromsuper(unpack = false)] e: Option } let bar = Bar { ... }; let foo: Foo = bar.try_into()?; // using Foo's derived implementation of TryFrom ``` ## Generics `derive(FromSuper)` can handle many situations in which generics are involved. Both, the super and the sub struct, can have type parameters. When specifying the super struct, however, it is impossible to decide whether e.g. the `T` in `Bar` is a type parameter or a concrete type, if it is not present in the sub struct. In order to differentiate the two meanings, **generic type parameters have to be prefixed with a `#` sign** if they are not used by the derived type (it is recommended to always use the `#` sign for generic type parameters, even if they are also used in the derived type): ```rust struct Bar { x: Vec, y: Vec, z: U, } #[derive(FromSuper)] #[fromsuper(from_type = "Bar<#T,u32>")] struct Foo { x: Vec, z: u32, } ``` This way, it is possible to reduce the number of type parameters for the sub struct, if its fields do not require them. Lifetime parameters for both, the super and the sub struct, should automatically be handled properly. ## Referencing instead of consuming the super struct If the super struct can or should not be consumed, the derived sub struct can be made to contain only references to the original values instead of consuming them. This behavior can be activated by using the `make_refs` argument. Note that this can only be activated for the whole struct, not on a per-field basis. ```rust struct Bar { a: Option, b: String, } #[derive(FromSuper)] #[fromsuper(from_type = "&'a Bar", unpack = true, make_refs = true)] struct Foo<'a> { a: &'a String, #[fromsuper(unpack = false)] b: &'a String, } ``` ## Contributions Since it is hard to predict all possible usage scenarios of the proc macro, there may be situations that are not properly handled. Please let me know by filing an issue. ## License This project is licensed under the terms of the MIT License, as well as the Apache 2.0 License. You are free to choose whichever suits your needs best.