Telety: Transform syn::Paths into their type definitions in your proc macros

https://crates.io/crates/telety

To enable telety for a type, simply add the attribute with the canonical path to the current module.

pub mod my_mod {
    #[telety(crate::my_mod)]
    pub struct MyType { ... }
}

Telety provides 3 key features:
1. It 'embeds' type information in the macro namespace alongside the item in the type namespace, so it is available (almost) anywhere the type is.
2. Telety utilizes a construct to determine whether a syn::Path contains a macro and invoke it, otherwise invoke a fallback macro instead. This allows accessing the embedded type definitions if available, without resulting in a compile error if a type is not telety-enabled.
3. An alias is created for each type referenced in a telety item definition. In combination with the type information macro, this lets you reference those types even in other modules and crates (which don't have the same imports as the item definition).

As an example, if you wanted to write a macro #[mix(...)] to merge multiple enums, that would turn this:

// water.rs
pub enum Flavor {
    Grapefruit,
    Lemon,
    Lime,
}

#[telety(crate::water)]
pub enum Water {
    Tap,
    Seltzer(Option<Flavor>),
    Heavy,
}

// oil.rs
#[telety(crate::oil)]
pub enum Oil {
    Olive,
    Motor,
    Midnight,
}

// unknown.rs
// not #[telety]!
pub enum Unknown {
    // ...
}

// mixed.rs
use crate::water;
use crate::oil;
use crate::unknown;
#[mix(water::Water, oil::Oil, unknown::Unknown)]
pub enum Mixed { }

into this:

// mixed.rs (effective macro output)
use crate::water;
use crate::oil;
use crate::unknown;

pub enum Mixed { 
    Tap,
    Seltzer(Option<crate::water::Flavor>),
    Heavy,
    Olive,
    Motor,
    Midnight,
    Unknown(unknown::Unknown),
}

The #[telety] attribute creates a macro with the same identifier as the item it is attached to. (So water.rs contains a type Water and a macro Water!. This means use crate::water; brings both into scope as water::Water.) We utilize the telety macros through Commands - TY can get us the item definition, so we can extract all the enum variants.

This works for Water and Oil, but Unknown is not telety-enabled. If we try to invoke a path which is not a macro, we would normally get a compile error. Apply::with_fallback allows you to specify what TokenStream to output if the type does not have a telety macro, instead of erroring (or to give a more helpful error message). For our example, we can just make a new variant to store the opaque enum.

We can now collect all our variants, but there is a problem: the variant Seltzer has a field with the local type Flavor. If we just copy-paste the tokens, Flavor is not a valid type in mixes.rs. You can, however, use the aliases telety creates. visitor::ApplyAliases replaces the original type tokens with a full canonical path to a type alias which we can use anywhere.
The type alias also 'embeds' the telety macro, if it exists for that type, so you can 'traverse' multiple telety types in this way.

For an actual usage example, check out amass, which uses it to derive From for nested enums, even across crates.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.