Inter-Struct
A #[derive()]
macro for various trait implementations between two structs.
Please read the known caveats section before using this crate! It's not trivial to implement code for two structs in the same codebase.
Also note that this crate is in an early development phase. The crate is already properly tested, but bugs might still be there.
Features:
- PartialEq
- Merge
- MergeRef
- Into - A standard
From/Into
impl between two structs. - IntoDefault -
From/Into
, but useDefault
on the target for unknown fields. - Field attributes to customize the behavior of our traits.
-
unchecked
Ignore any type checks done by inter-struct and let the compiler handle errors. -
rename
Similar to serde's rename, map a field to another named field. -
ignore
Ignore this field in the type generation.
-
Merge
/// Merge another struct into Self whilst consuming it.
///
/// The other trait is named `StructMergeRef` and merges other structs by reference.
This following code is an example on how to use the InterStruct
derive macro for implementing the StructMerge
trait between two structs.
use *;
/// The target struct we'll merge into.
/// A struct with both an identical and an optional field type.
/// Note that the path to `Target` must always be fully qualifying.
Into
This following code is an example on how to use the InterStruct
derive macro for implementing Into
between two structs.
use *;
/// The target struct we'll convert our `Source` struct into.
// Note that the path to `Target` must always be fully qualifying.
Known caveats
Inter-struct is designed to work in this environment:
- In the scope of a single crate. Cross-crate usage won't work.
- In the main
src
folder of the crate. Integration tests and examples aren't supported.
The main problems in this crate come from the fact that there's no official way to resolve modules or types in the the procedural macro stage.
Due to this limitation, inter-struct isn't capable of ensuring the equality of two types. As a result, it might create false negative compile errors, even though the types might be compatible. This might happen if, for instance, types are obscured via an alias or if a type can be automatically dereferenced into another type.
However, as we're creating safe and valid Rust code, the compiler will thrown an error if any type problems arise.
Not yet solved problems
These are problems that can probably be solved but they're non-trivial.
- Struct located at root of crate. E.g.
lib.rs
. - Struct is located in integration tests.
- Struct in (potentially nested or alternating)
mod {}
block in file. - The source root dir isn't
src
. We would have to check the environment and possibly parse theCargo.toml
. - Different generic aliases that use different tokens but have the same type.
E.g.
Box<dyn T>
andBox<dyn S>
but bothS
andT
have theClone
trait bound. - Non-public structs. I.e. structs that aren't fully internally visible. This will lead to an compiler-error but isn't cought while running this macro. This might be infeasible?
Unsolvable problems
These are problems that are either impossible to solve or very infeasible. For instance, something infeasible would be to parse all files for a full type resolution of a given crate. That would be a job for the compiler in a later stage.
- Structs that are altered or generated by other macros.
- Type comparison and type resolution. E.g.
type test = Option<String>
won't be detected as optional. The current type checks are literal comparisons of the type tokens.