#tags #lifetime #type-id #no-alloc

no-std ty-tag

TypeId for lifetime containing types via type tags

2 releases

new 0.1.1 Dec 30, 2024
0.1.0 Dec 30, 2024

#654 in Rust patterns

Download history 182/week @ 2024-12-24

189 downloads per month

MIT/Apache

59KB
865 lines

Ty Tag

TypeId for lifetime containing types via type tags.

Version docs.rs Version Crates.io License Crates.io

Not all types in Rust are 'static. Meaning they can't be used with [core::any::TypeId]. However, it is often useful to be able to name a lifetime containing type via a 'static type. Most implementations go about this by using the same type with all the lifetimes replaced by 'static. So for example &'a [u8] would be named by &'static [u8]. These implementations suffer from some limitations. One being that they are usually limited to a single lifetime 'a.

This crate takes a different approach to solve this issue. We introduce the idea of tags. A tag is an arbitrary type with an associated lifetime containing type. So for the &'a [u8] example we would have a struct SliceU8; with the &'a [u8] as an associated type. You may notice that by itself this has an issue. We somehow need to get a 'a to actually write the &'a [u8] associated type. The lifetime can't live on the SliceU8 because we need that to be 'static.

We solve this by injecting the lifetime 'a in an operation called reification. This operation combines a tag type and some number of lifetimes into the lifetime containing type. So SliceU8 + 'a reifies to &'a [u8]. Combining this with a way to get a tag type from a lifetime containing type, we gain the ability to go full circle from a lifetime containing type to a 'static type back to the lifetime containing type.

In this crate a tag type is defined to be a type that implements both [Tag] and [WithLt]. These types automatically gain the [Reify] operation for constructing the lifetime containing type they name. Any type can have a tag associated with it via the [Tagged] trait. Note, [Tagged] does not require the associated tag to name the Self type. This is a useful property but may be unintuitive.

use ty_tag::{tag, TagOf, Reify, l};

// Check that the tag of &str is a 'static type.
is_static::<TagOf<&str>>();

// Introduce an arbitrary lifetime 'a.
fn with_lt<'a>() {
    // Combine the tag of &str with lifetime 'a to form the &'a str lifetime containing type.
    reify::<'a, TagOf<&str>, &'a str>();
}
with_lt();

fn reify<'a, T: Reify<l!['a], Reified = U>, U>() {}

fn is_static<T: 'static>() {}

Another concept this crate introduces is that of a tag group. Because of Rust's coherence rules we are limited in our ability to implement [Tagged] for types outside a user's crate. To work around this we use tag groups like [DefaultGroup] to allow a user to bypass the coherence rules by naming a type they control. This functionality is not used within this crate, but is designed to improve the ergonomics of other crates.

Crate features

  • macros (enabled by default) — Includes the tag macro for creating tags from type aliases.

  • core (enabled by default) — Adds tags for commonly used types in core.

  • alloc — Adds tags for commonly used types in alloc.

  • std — Adds tags for commonly used types in std.

  • unsafe — Allows unsafe code.

    Only some convenience methods of Label need this.

no_std Support

This crate is #![no_std] by default, it can be used anywhere Rust can.

Minimum Supported Rust Version

Requires Rust 1.83.0.

This crate follows the "Latest stable Rust" policy. The listed MSRV won't be changed unless needed. However, updating the MSRV anywhere up to the latest stable at time of release is allowed.

Contributing

Contributions in any form (issues, pull requests, etc.) to this project must adhere to Rust's Code of Conduct.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in ty-tag by you shall be licensed as below, without any additional terms or conditions.

License

This project is licensed under either of

at your option.

Dependencies

~140KB