Skip to content

A Rust crate that defines the ToBoundedStatic and IntoBoundedStatic traits

License

Notifications You must be signed in to change notification settings

fujiapple852/bounded-static

Repository files navigation

ci Documentation Crate

Bounded Static

This crate defines the ToBoundedStatic and IntoBoundedStatic traits, the ToStatic macro and provides impls for common types. This crate has zero-dependencies, is no_std friendly and forbids unsafe code.

As described in the Common Rust Lifetime Misconceptions:

T: 'static should be read as "T is bounded by a 'static lifetime" not "T has a 'static lifetime".

The traits ToBoundedStatic and IntoBoundedStatic can be used to convert any suitable T and &T to an owned T such that T: 'static. Both traits define an associated type which is bounded by 'static and provide a method to convert to that bounded type.

The macros ToStatic can be used to automatically derive ToBoundedStatic and IntoBoundedStatic for any struct or enum that can be converted to a form that is bounded by 'static.

Refer to the crate documentation for details and examples.

FAQ

When is this useful?

This is useful for data structures which directly or indirectly contain Cow<T> types that must be supplied to a function which requires the 'static bound (i.e. std::thread::spawn):

#[derive(Debug, PartialEq, ToStatic)]
struct Foo<'a> {
    foo: Cow<'a, str>,
    bar: Vec<Bar<'a>>
}
#[derive(Debug, PartialEq, ToStatic)]
enum Bar<'a> {
    First,
    Second(Cow<'a, str>),
}

fn main() {
    let value = String::from("data");
    let foo = Foo {
        foo: Cow::from(&value),
        bar: vec![Bar::First, Bar::Second(Cow::from(&value))]
    };
    let foo_static = foo.into_static();
    std::thread::spawn(move || {
        assert_eq!(foo_static.foo, "data");
        assert_eq!(foo_static.bar, vec![Bar::First, Bar::Second("data".into())])
    }).join().unwrap();
}

How does this differ from the ToOwned trait?

The ToOwned trait defines an associated type Owned which is not bound by 'static and therefore the follow will not compile:

use std::borrow::Cow;

fn main() {
    #[derive(Clone)]
    struct Foo<'a> {
        foo: Cow<'a, str>,
    }

    fn ensure_static<T: 'static>(_: T) {}

    let s = String::from("data");
    let foo = Foo { foo: Cow::from(&s) };
    ensure_static(foo.to_owned())
}

Results in the following error:

error[E0597]: `s` does not live long enough
  --> src/lib.rs:12:36
   |
12 |     let foo = Foo { foo: Cow::from(&s) };
   |                          ----------^^-
   |                          |         |
   |                          |         borrowed value does not live long enough
   |                          argument requires that `s` is borrowed for `'static`
13 |     ensure_static(foo.to_owned())
14 | }
   | - `s` dropped here while still borrowed

Replacing Clone with ToStatic and using into_static() (or to_static() as needed) allows the example to compile:

use std::borrow::Cow;

fn main() {

    #[derive(ToStatic)]
    struct Foo<'a> {
        foo: Cow<'a, str>,
    }

    fn ensure_static<T: 'static>(_: T) {}

    let s = String::from("data");
    let foo = Foo { foo: Cow::from(&s) };
    ensure_static(foo.into_static())
}

License

bounded-static is distributed under the terms of the Apache License (Version 2.0).

See LICENSE for details.

Copyright 2022