bounded_static/
lib.rs

1#![doc(html_root_url = "https://docs.rs/bounded-static/0.8.0")]
2//! Provides the [`ToBoundedStatic`] and [`IntoBoundedStatic`] traits and [`ToStatic`] derive macro.
3//!
4//! As described in the [Common Rust Lifetime Misconceptions](https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md#2-if-t-static-then-t-must-be-valid-for-the-entire-program):
5//!
6//! > `T: 'static` should be read as "`T` is bounded by a `'static` lifetime" not "`T` has a `'static` lifetime".
7//!
8//! The traits [`ToBoundedStatic`] and [`IntoBoundedStatic`] can be used to convert any suitable `T` and `&T` to an
9//! owned `T` such that `T: 'static`.  Both traits define an associated type which is bounded by `'static` and provide
10//! a method to convert to that bounded type:
11//!
12//! ```rust
13//! pub trait ToBoundedStatic {
14//!     type Static: 'static;
15//!
16//!     fn to_static(&self) -> Self::Static;
17//! }
18//!
19//! pub trait IntoBoundedStatic {
20//!     type Static: 'static;
21//!
22//!     fn into_static(self) -> Self::Static;
23//! }
24//! ```
25//!
26//! Implementations of [`ToBoundedStatic`] and [`IntoBoundedStatic`] are provided for the following `core` types:
27//!
28//! - [`primitive`](core::primitive) (no-op conversions)
29//! - [`array`](array)
30//! - [`tuple`](tuple)
31//! - [`Option`]
32//! - [`Result`]
33//!
34//! Additional implementations are available by enabling the following features:
35//!
36//! - `alloc` for common types from the `alloc` crate:
37//!   - [Cow](https://doc.rust-lang.org/alloc/borrow/enum.Cow.html)
38//!   - [String](https://doc.rust-lang.org/alloc/string/struct.String.html)
39//!   - [Vec](https://doc.rust-lang.org/alloc/vec/struct.Vec.html)
40//!   - [Box](https://doc.rust-lang.org/alloc/boxed/struct.Box.html)
41//!
42//! - `collections` for all collection types in the `alloc` crate:
43//!   - [BinaryHeap](https://doc.rust-lang.org/alloc/collections/binary_heap/struct.BinaryHeap.html)
44//!   - [BTreeMap](https://doc.rust-lang.org/alloc/collections/btree_map/struct.BTreeMap.html)
45//!   - [BTreeSet](https://doc.rust-lang.org/alloc/collections/btree_set/struct.BTreeSet.html)
46//!   - [LinkedList](https://doc.rust-lang.org/alloc/collections/linked_list/struct.LinkedList.html)
47//!   - [VecDeque](https://doc.rust-lang.org/alloc/collections/vec_deque/struct.VecDeque.html)
48//!
49//! - `std` for additional types from `std`:
50//!   - [HashMap](https://doc.rust-lang.org/std/collections/struct.HashMap.html)
51//!   - [HashSet](https://doc.rust-lang.org/std/collections/struct.HashSet.html)
52//!   - [RandomState](https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html)
53//!
54//! Note that `collections`, `alloc` and `std` are enabled be default.
55//!
56//! Additional implementations for 3rd party types are available by enabling the following features:
57//!
58//! - `smol_str` for [`SmolStr`](https://docs.rs/smol_str/0.2.2/smol_str/struct.SmolStr.html)
59//! - `smallvec` for [`SmallVec`](https://docs.rs/smallvec/1.13.2/smallvec/struct.SmallVec.html)
60//! - `smartstring` for [`SmartString`](https://docs.rs/smartstring/1.0.1/smartstring/index.html)
61//! - `ahash` for:
62//!     - [`RandomState`](https://docs.rs/ahash/0.8.6/ahash/random_state/struct.RandomState.html)
63//!     - [`AHashMap`](https://docs.rs/ahash/0.8.6/ahash/struct.AHashMap.html)
64//!     - [`AHashSet`](https://docs.rs/ahash/0.8.6/ahash/struct.AHashSet.html)
65//! - `chrono` for:
66//!     - [`DateTime`](https://docs.rs/chrono/0.4.38/chrono/struct.DateTime.html)
67//!     - [`FixedOffset`](https://docs.rs/chrono/0.4.38/chrono/struct.FixedOffset.html)
68//!     - [`Months`](https://docs.rs/chrono/0.4.38/chrono/struct.Months.html)
69//!     - [`TimeDelta`](https://docs.rs/chrono/0.4.38/chrono/struct.TimeDelta.html)
70//!     - [`Utc`](https://docs.rs/chrono/0.4.38/chrono/struct.Utc.html)
71//!     - [`Month`](https://docs.rs/chrono/0.4.38/chrono/enum.Month.html)
72//!     - [`Weekday`](https://docs.rs/chrono/0.4.38/chrono/enum.Weekday.html)
73//!     - [`Days`](https://docs.rs/chrono/0.4.38/chrono/naive/struct.Days.html)
74//!     - [`IsoWeek`](https://docs.rs/chrono/0.4.38/chrono/naive/struct.IsoWeek.html)
75//!     - [`NaiveDate`](https://docs.rs/chrono/0.4.38/chrono/naive/struct.NaiveDate.html)
76//!     - [`NaiveDateTime`](https://docs.rs/chrono/0.4.38/chrono/naive/struct.NaiveDateTime.html)
77//!     - [`NaiveTime`](https://docs.rs/chrono/0.4.38/chrono/naive/struct.NaiveTime.html)
78//! - `chrono-clock` for:
79//!    - [`Local`](https://docs.rs/chrono/0.4.38/chrono/struct.Local.html)
80//!
81//! # Examples
82//!
83//! Given a structure which can be borrow or owned and a function which requires its argument is bounded by the
84//! `'static` lifetime:
85//!
86//! ```rust
87//! # use std::borrow::Cow;
88//! struct Foo<'a> {
89//!     bar: Cow<'a, str>,
90//!     baz: Vec<Cow<'a, str>>,
91//! }
92//!
93//! fn ensure_static<T: 'static>(_: T) {}
94//! ```
95//!
96//! We can implement [`ToBoundedStatic`] (and [`IntoBoundedStatic`]) for `Foo<'_>`:
97//!
98//! ```rust
99//! # use std::borrow::Cow;
100//! # use bounded_static::ToBoundedStatic;
101//! struct Foo<'a> {
102//!     bar: Cow<'a, str>,
103//!     baz: Vec<Cow<'a, str>>,
104//! }
105//! impl ToBoundedStatic for Foo<'_> {
106//!     type Static = Foo<'static>;
107//!
108//!     fn to_static(&self) -> Self::Static {
109//!         Foo { bar: self.bar.to_static(), baz: self.baz.to_static() }
110//!     }
111//! }
112//! ```
113//!
114//! This allows it to be converted to an owned representation such that it is now bounded by `'static`:
115//!
116//! ```rust
117//! # use std::borrow::Cow;
118//! # use bounded_static::ToBoundedStatic;
119//! # struct Foo<'a> {
120//! #     bar: Cow<'a, str>,
121//! #     baz: Vec<Cow<'a, str>>,
122//! # }
123//! # impl ToBoundedStatic for Foo<'_> {
124//! #     type Static = Foo<'static>;
125//! #
126//! #     fn to_static(&self) -> Self::Static {
127//! #         Foo { bar: self.bar.to_static(), baz: self.baz.to_static() }
128//! #     }
129//! # }
130//! fn test() {
131//!     # fn ensure_static<T: 'static>(_: T) {}
132//!     let s = String::from("data");
133//!     let foo = Foo { bar: Cow::from(&s), baz: vec![Cow::from(&s)] };
134//!     let to_static = foo.to_static();
135//!     ensure_static(to_static);
136//! }
137//! ```
138//!
139//! # Derive
140//!
141//! These traits may be automatically derived for any `struct` or `enum` that can be converted to a form that is
142//! bounded by `'static` by using the [`ToStatic`] macro. It support all `struct` flavors (unit, named & unnamed),
143//! all `enum` variant flavors (unit, named & unnamed).  It does not currently support `union`.
144//!
145//! To use the [`ToStatic`] macro you must enable the `derive` feature:
146//!
147//! ```yaml
148//! bounded-static = { version = "0.8.0", features = [ "derive" ] }
149//! ```
150//!
151//! # Examples
152//!
153//! ```rust
154//! # use std::borrow::Cow;
155//! # use std::collections::HashMap;
156//! # use bounded_static::ToStatic;
157//! /// Named field struct
158//! #[derive(ToStatic)]
159//! struct Foo<'a> {
160//!     aaa: Cow<'a, str>,
161//!     bbb: &'static str,
162//!     ccc: Baz<'a>,
163//! }
164//!
165//! /// Unnamed field struct
166//! #[derive(ToStatic)]
167//! struct Bar<'a, 'b>(u128, HashMap<Cow<'a, str>, Cow<'b, str>>);
168//!
169//! /// Unit struct
170//! #[derive(ToStatic)]
171//! struct Qux;
172//!
173//! #[derive(ToStatic)]
174//! enum Baz<'a> {
175//!     First(String, usize, Vec<Cow<'a, str>>),
176//!     Second { fst: u32, snd: &'static str },
177//!     Third,
178//! }
179//! ```
180#![warn(clippy::all, clippy::pedantic, clippy::nursery, rust_2018_idioms)]
181#![allow(clippy::missing_const_for_fn)]
182#![forbid(unsafe_code)]
183#![no_std]
184
185#[cfg(feature = "std")]
186extern crate std;
187
188#[cfg(feature = "alloc")]
189extern crate alloc;
190
191use core::num::{
192    NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
193    NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
194};
195
196#[cfg(feature = "alloc")]
197use alloc::{
198    borrow::{Cow, ToOwned},
199    boxed::Box,
200    string::String,
201    vec::Vec,
202};
203
204#[cfg(feature = "collections")]
205use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
206
207#[cfg(feature = "derive")]
208/// Re-export for the custom derive macro `ToStatic`.
209pub use bounded_static_derive::ToStatic;
210
211/// A trait for converting `&T` to an owned `T` such that `T: 'static`.
212///
213/// See the module level documentation for details.
214pub trait ToBoundedStatic {
215    /// The target type is bounded by the `'static` lifetime.
216    type Static: 'static;
217
218    /// Convert an `&T` to an owned `T` such that `T: 'static`.
219    #[must_use = "converting is often expensive and is not expected to have side effects"]
220    fn to_static(&self) -> Self::Static;
221}
222
223/// A trait for converting an owned `T` into an owned `T` such that `T: 'static`.
224///
225/// See the module level documentation for details.
226pub trait IntoBoundedStatic {
227    /// The target type is bounded by the `'static` lifetime.
228    type Static: 'static;
229
230    /// Convert an owned `T` into an owned `T` such that `T: 'static`.
231    #[must_use = "converting is often expensive and is not expected to have side effects"]
232    fn into_static(self) -> Self::Static;
233}
234
235/// No-op [`ToBoundedStatic`] impl for converting `&'static str` to `&'static str`.
236impl ToBoundedStatic for &'static str {
237    type Static = &'static str;
238
239    fn to_static(&self) -> Self::Static {
240        self
241    }
242}
243
244/// No-op [`IntoBoundedStatic`] impl for converting `&'static str` into `&'static str`.
245impl IntoBoundedStatic for &'static str {
246    type Static = &'static str;
247
248    fn into_static(self) -> Self::Static {
249        self
250    }
251}
252
253/// No-op [`ToBoundedStatic`] and [`IntoBoundedStatic`] impls for `Copy` types.
254macro_rules! make_copy_impl {
255    ($id:ty) => {
256        /// No-op [`ToBoundedStatic`] impl for this `Copy` type.
257        impl ToBoundedStatic for $id {
258            type Static = Self;
259
260            fn to_static(&self) -> Self::Static {
261                *self
262            }
263        }
264        /// No-op [`IntoBoundedStatic`] impl for this `Copy` type.
265        impl IntoBoundedStatic for $id {
266            type Static = Self;
267
268            fn into_static(self) -> Self::Static {
269                self
270            }
271        }
272    };
273}
274
275make_copy_impl!(bool);
276make_copy_impl!(char);
277make_copy_impl!(f32);
278make_copy_impl!(f64);
279make_copy_impl!(usize);
280make_copy_impl!(u8);
281make_copy_impl!(u16);
282make_copy_impl!(u32);
283make_copy_impl!(u64);
284make_copy_impl!(u128);
285make_copy_impl!(isize);
286make_copy_impl!(i8);
287make_copy_impl!(i16);
288make_copy_impl!(i32);
289make_copy_impl!(i64);
290make_copy_impl!(i128);
291make_copy_impl!(NonZeroUsize);
292make_copy_impl!(NonZeroU8);
293make_copy_impl!(NonZeroU16);
294make_copy_impl!(NonZeroU32);
295make_copy_impl!(NonZeroU64);
296make_copy_impl!(NonZeroU128);
297make_copy_impl!(NonZeroIsize);
298make_copy_impl!(NonZeroI8);
299make_copy_impl!(NonZeroI16);
300make_copy_impl!(NonZeroI32);
301make_copy_impl!(NonZeroI64);
302make_copy_impl!(NonZeroI128);
303
304/// No-op [`ToBoundedStatic`] impl for unit type `()`.
305impl ToBoundedStatic for () {
306    type Static = ();
307
308    fn to_static(&self) -> Self::Static {}
309}
310
311/// No-op [`IntoBoundedStatic`] impl for unit type `()`.
312impl IntoBoundedStatic for () {
313    type Static = ();
314
315    fn into_static(self) -> Self::Static {}
316}
317
318/// Blanket [`ToBoundedStatic`] impl for converting `Option<T>` to `Option<T>: 'static`.
319impl<T> ToBoundedStatic for Option<T>
320where
321    T: ToBoundedStatic,
322{
323    type Static = Option<T::Static>;
324
325    fn to_static(&self) -> Self::Static {
326        self.as_ref().map(ToBoundedStatic::to_static)
327    }
328}
329
330/// Blanket [`IntoBoundedStatic`] impl for converting `Option<T>` into `Option<T>: 'static`.
331impl<T> IntoBoundedStatic for Option<T>
332where
333    T: IntoBoundedStatic,
334{
335    type Static = Option<T::Static>;
336
337    fn into_static(self) -> Self::Static {
338        self.map(IntoBoundedStatic::into_static)
339    }
340}
341
342/// Blanket [`ToBoundedStatic`] impl for converting `Result<T, E>` to `Result<T, E>: 'static`.
343impl<T, E> ToBoundedStatic for Result<T, E>
344where
345    T: ToBoundedStatic,
346    E: ToBoundedStatic,
347{
348    type Static = Result<T::Static, E::Static>;
349
350    fn to_static(&self) -> Self::Static {
351        match self {
352            Ok(value) => Ok(value.to_static()),
353            Err(err) => Err(err.to_static()),
354        }
355    }
356}
357
358/// Blanket [`IntoBoundedStatic`] impl for converting `Result<T, E>` into `Result<T, E>: 'static`.
359impl<T, E> IntoBoundedStatic for Result<T, E>
360where
361    T: IntoBoundedStatic,
362    E: IntoBoundedStatic,
363{
364    type Static = Result<T::Static, E::Static>;
365
366    fn into_static(self) -> Self::Static {
367        match self {
368            Ok(value) => Ok(value.into_static()),
369            Err(err) => Err(err.into_static()),
370        }
371    }
372}
373
374/// Blanket [`ToBoundedStatic`] impl for converting `[T; const N: usize]` to `[T; const N: usize]: 'static`.
375impl<T, const N: usize> ToBoundedStatic for [T; N]
376where
377    T: ToBoundedStatic + Copy,
378{
379    type Static = [T::Static; N];
380
381    fn to_static(&self) -> Self::Static {
382        // Note that we required that `T` is `Copy` here whereas the `IntoBoundedStatic` impl does does not.
383        self.map(|item| item.to_static())
384    }
385}
386
387/// Blanket [`IntoBoundedStatic`] impl for converting `[T; const N: usize]` into `[T; const N: usize]: 'static`.
388impl<T, const N: usize> IntoBoundedStatic for [T; N]
389where
390    T: IntoBoundedStatic,
391{
392    type Static = [T::Static; N];
393
394    fn into_static(self) -> Self::Static {
395        self.map(IntoBoundedStatic::into_static)
396    }
397}
398
399/// Blanket [`ToBoundedStatic`] impl for converting tuples `(T1, T2, ...)` to `(T1, T2, ..): 'static`.
400macro_rules! tuple_to_static {
401    () => ();
402    ($($name:ident,)+) => {
403        tuple_to_static! (
404            @gen $($name,)+,
405            concat!(
406                "Blanket [`ToBoundedStatic`] impl for converting tuple `",
407                stringify!(($($name,)+)), "` to `", stringify!(($($name,)+)), ": 'static `"
408            )
409        );
410    };
411    (@gen $($name:ident,)+, $doc:expr) => {
412        #[doc = $doc]
413        impl<$($name: ToBoundedStatic),+> ToBoundedStatic for ($($name,)+) {
414            type Static = ($($name::Static,)+);
415            #[allow(non_snake_case)]
416            fn to_static(&self) -> Self::Static {
417                let ($(ref $name,)+) = *self;
418                ($($name.to_static(),)+)
419            }
420        }
421        tuple_to_static! {@peel $($name,)+ }
422    };
423    (@peel $name:ident, $($other:ident,)*) => {tuple_to_static! { $($other,)* }};
424}
425
426/// Blanket [`IntoBoundedStatic`] impl for converting tuples `(T1, T2, ...)` into `(T1, T2, ..): 'static`.
427macro_rules! tuple_into_static {
428    () => ();
429    ($($name:ident,)+) => {
430        tuple_into_static! (
431            @gen $($name,)+,
432            concat!(
433                "Blanket [`IntoBoundedStatic`] impl for converting tuple `",
434                stringify!(($($name,)+)), "` into `", stringify!(($($name,)+)), ": 'static `"
435            )
436        );
437    };
438    (@gen $($name:ident,)+, $doc:expr) => {
439        #[doc = $doc]
440        impl<$($name: IntoBoundedStatic),+> IntoBoundedStatic for ($($name,)+) {
441            type Static = ($($name::Static,)+);
442            #[allow(non_snake_case)]
443            fn into_static(self) -> Self::Static {
444                let ($($name,)+) = self;
445                ($($name.into_static(),)+)
446            }
447        }
448        tuple_into_static! {@peel $($name,)+ }
449    };
450    (@peel $name:ident, $($other:ident,)*) => {tuple_into_static! { $($other,)* }};
451}
452
453tuple_to_static! { T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1, T0, }
454tuple_into_static! { T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1, T0, }
455
456#[cfg(feature = "alloc")]
457/// Blanket [`ToBoundedStatic`] impl for converting `Cow<'a, T: ?Sized>` to `Cow<'static, T: ?Sized>`.
458impl<T> ToBoundedStatic for Cow<'_, T>
459where
460    T: 'static + ToOwned + ?Sized,
461{
462    type Static = Cow<'static, T>;
463
464    fn to_static(&self) -> Self::Static {
465        Cow::Owned(self.clone().into_owned())
466    }
467}
468
469#[cfg(feature = "alloc")]
470/// Blanket [`IntoBoundedStatic`] impl for converting `Cow<'a, T: ?Sized>` into `Cow<'static, T: ?Sized>`.
471impl<T> IntoBoundedStatic for Cow<'_, T>
472where
473    T: 'static + ToOwned + ?Sized,
474{
475    type Static = Cow<'static, T>;
476
477    fn into_static(self) -> Self::Static {
478        Cow::Owned(self.into_owned())
479    }
480}
481
482#[cfg(feature = "alloc")]
483/// [`ToBoundedStatic`] impl for `String`.
484impl ToBoundedStatic for String {
485    type Static = Self;
486
487    fn to_static(&self) -> Self::Static {
488        self.clone()
489    }
490}
491
492#[cfg(feature = "alloc")]
493/// No-op [`IntoBoundedStatic`] impl for `String`.
494impl IntoBoundedStatic for String {
495    type Static = Self;
496
497    fn into_static(self) -> Self::Static {
498        self
499    }
500}
501
502#[cfg(feature = "alloc")]
503/// Blanket [`ToBoundedStatic`] impl for converting `Vec<T>` to `Vec<T>: 'static`.
504impl<T> ToBoundedStatic for Vec<T>
505where
506    T: ToBoundedStatic,
507{
508    type Static = Vec<T::Static>;
509
510    fn to_static(&self) -> Self::Static {
511        self.iter().map(ToBoundedStatic::to_static).collect()
512    }
513}
514
515#[cfg(feature = "alloc")]
516/// Blanket [`IntoBoundedStatic`] impl for converting `Vec<T>` into `Vec<T>: 'static`.
517impl<T> IntoBoundedStatic for Vec<T>
518where
519    T: IntoBoundedStatic,
520{
521    type Static = Vec<T::Static>;
522
523    fn into_static(self) -> Self::Static {
524        self.into_iter()
525            .map(IntoBoundedStatic::into_static)
526            .collect()
527    }
528}
529
530#[cfg(feature = "collections")]
531/// Blanket [`ToBoundedStatic`] impl for converting `BinaryHeap<T>` into `BinaryHeap<T>: 'static`.
532impl<T> ToBoundedStatic for BinaryHeap<T>
533where
534    T: ToBoundedStatic,
535    T::Static: Ord,
536{
537    type Static = BinaryHeap<T::Static>;
538
539    fn to_static(&self) -> Self::Static {
540        self.iter().map(ToBoundedStatic::to_static).collect()
541    }
542}
543
544#[cfg(feature = "collections")]
545/// Blanket [`IntoBoundedStatic`] impl for converting `BinaryHeap<T>` into `BinaryHeap<T>: 'static`.
546impl<T> IntoBoundedStatic for BinaryHeap<T>
547where
548    T: IntoBoundedStatic,
549    T::Static: Ord,
550{
551    type Static = BinaryHeap<T::Static>;
552
553    fn into_static(self) -> Self::Static {
554        self.into_iter()
555            .map(IntoBoundedStatic::into_static)
556            .collect()
557    }
558}
559
560#[cfg(feature = "collections")]
561/// Blanket [`ToBoundedStatic`] impl for converting `BTreeMap<K, V>` into `BTreeMap<K, V>: 'static`.
562impl<K, V> ToBoundedStatic for BTreeMap<K, V>
563where
564    K: ToBoundedStatic,
565    K::Static: Ord,
566    V: ToBoundedStatic,
567{
568    type Static = BTreeMap<K::Static, V::Static>;
569
570    fn to_static(&self) -> Self::Static {
571        self.iter()
572            .map(|(k, v)| (k.to_static(), v.to_static()))
573            .collect()
574    }
575}
576
577#[cfg(feature = "collections")]
578/// Blanket [`IntoBoundedStatic`] impl for converting `BTreeMap<K, V>` into `BTreeMap<K, V>: 'static`.
579impl<K, V> IntoBoundedStatic for BTreeMap<K, V>
580where
581    K: IntoBoundedStatic,
582    K::Static: Ord,
583    V: IntoBoundedStatic,
584{
585    type Static = BTreeMap<K::Static, V::Static>;
586
587    fn into_static(self) -> Self::Static {
588        self.into_iter()
589            .map(|(k, v)| (k.into_static(), v.into_static()))
590            .collect()
591    }
592}
593
594#[cfg(feature = "collections")]
595/// Blanket [`ToBoundedStatic`] impl for converting `BTreeSet<T>` into `BTreeSet<T>: 'static`.
596impl<T> ToBoundedStatic for BTreeSet<T>
597where
598    T: ToBoundedStatic,
599    T::Static: Ord,
600{
601    type Static = BTreeSet<T::Static>;
602
603    fn to_static(&self) -> Self::Static {
604        self.iter().map(ToBoundedStatic::to_static).collect()
605    }
606}
607
608#[cfg(feature = "collections")]
609/// Blanket [`IntoBoundedStatic`] impl for converting `BTreeSet<T>` into `BTreeSet<T>: 'static`.
610impl<T> IntoBoundedStatic for BTreeSet<T>
611where
612    T: IntoBoundedStatic,
613    T::Static: Ord,
614{
615    type Static = BTreeSet<T::Static>;
616
617    fn into_static(self) -> Self::Static {
618        self.into_iter()
619            .map(IntoBoundedStatic::into_static)
620            .collect()
621    }
622}
623
624#[cfg(feature = "collections")]
625/// Blanket [`ToBoundedStatic`] impl for converting `LinkedList<T>` into `LinkedList<T>: 'static`.
626impl<T> ToBoundedStatic for LinkedList<T>
627where
628    T: ToBoundedStatic,
629{
630    type Static = LinkedList<T::Static>;
631
632    fn to_static(&self) -> Self::Static {
633        self.iter().map(ToBoundedStatic::to_static).collect()
634    }
635}
636
637#[cfg(feature = "collections")]
638/// Blanket [`IntoBoundedStatic`] impl for converting `LinkedList<T>` into `LinkedList<T>: 'static`.
639impl<T> IntoBoundedStatic for LinkedList<T>
640where
641    T: IntoBoundedStatic,
642{
643    type Static = LinkedList<T::Static>;
644
645    fn into_static(self) -> Self::Static {
646        self.into_iter()
647            .map(IntoBoundedStatic::into_static)
648            .collect()
649    }
650}
651
652#[cfg(feature = "collections")]
653/// Blanket [`ToBoundedStatic`] impl for converting `VecDeque<T>` into `VecDeque<T>: 'static`.
654impl<T> ToBoundedStatic for VecDeque<T>
655where
656    T: ToBoundedStatic,
657{
658    type Static = VecDeque<T::Static>;
659
660    fn to_static(&self) -> Self::Static {
661        self.iter().map(ToBoundedStatic::to_static).collect()
662    }
663}
664
665#[cfg(feature = "collections")]
666/// Blanket [`IntoBoundedStatic`] impl for converting `VecDeque<T>` into `VecDeque<T>: 'static`.
667impl<T> IntoBoundedStatic for VecDeque<T>
668where
669    T: IntoBoundedStatic,
670{
671    type Static = VecDeque<T::Static>;
672
673    fn into_static(self) -> Self::Static {
674        self.into_iter()
675            .map(IntoBoundedStatic::into_static)
676            .collect()
677    }
678}
679
680#[cfg(feature = "alloc")]
681/// Blanket [`ToBoundedStatic`] impl for converting `Box<T>` to `Box<T>: 'static`.
682impl<T> ToBoundedStatic for Box<T>
683where
684    T: ToBoundedStatic,
685{
686    type Static = Box<T::Static>;
687
688    fn to_static(&self) -> Self::Static {
689        Box::new(self.as_ref().to_static())
690    }
691}
692
693#[cfg(feature = "alloc")]
694/// Blanket [`IntoBoundedStatic`] impl for converting `Box<T>` into `Box<T>: 'static`.
695impl<T> IntoBoundedStatic for Box<T>
696where
697    T: IntoBoundedStatic,
698{
699    type Static = Box<T::Static>;
700
701    fn into_static(self) -> Self::Static {
702        Box::new((*self).into_static())
703    }
704}
705
706#[cfg(feature = "std")]
707/// Blanket [`ToBoundedStatic`] impl for converting `HashMap<K, V>` to `HashMap<K, V>: 'static`.
708impl<K, V, S> ToBoundedStatic for std::collections::HashMap<K, V, S>
709where
710    K: ToBoundedStatic,
711    K::Static: Eq + std::hash::Hash,
712    V: ToBoundedStatic,
713    S: ToBoundedStatic,
714    S::Static: std::hash::BuildHasher,
715{
716    type Static = std::collections::HashMap<K::Static, V::Static, S::Static>;
717
718    fn to_static(&self) -> Self::Static {
719        let mut map = std::collections::HashMap::with_capacity_and_hasher(
720            self.len(),
721            self.hasher().to_static(),
722        );
723        map.extend(self.iter().map(|(k, v)| (k.to_static(), v.to_static())));
724        map
725    }
726}
727
728#[cfg(feature = "std")]
729/// Blanket [`IntoBoundedStatic`] impl for for converting `HashMap<K, V>` into `HashMap<K, V>: 'static`.
730impl<K, V, S> IntoBoundedStatic for std::collections::HashMap<K, V, S>
731where
732    K: IntoBoundedStatic,
733    K::Static: Eq + std::hash::Hash,
734    V: IntoBoundedStatic,
735    S: ToBoundedStatic,
736    S::Static: std::hash::BuildHasher,
737{
738    type Static = std::collections::HashMap<K::Static, V::Static, S::Static>;
739
740    fn into_static(self) -> Self::Static {
741        let mut map = std::collections::HashMap::with_capacity_and_hasher(
742            self.len(),
743            self.hasher().to_static(),
744        );
745        map.extend(
746            self.into_iter()
747                .map(|(k, v)| (k.into_static(), v.into_static())),
748        );
749        map
750    }
751}
752
753#[cfg(feature = "std")]
754/// Blanket [`ToBoundedStatic`] impl for converting `HashSet<T>` into `HashSet<T>: 'static`.
755impl<T, S> ToBoundedStatic for std::collections::HashSet<T, S>
756where
757    T: ToBoundedStatic,
758    T::Static: Eq + std::hash::Hash,
759    S: ToBoundedStatic,
760    S::Static: std::hash::BuildHasher,
761{
762    type Static = std::collections::HashSet<T::Static, S::Static>;
763
764    fn to_static(&self) -> Self::Static {
765        let mut set = std::collections::HashSet::with_capacity_and_hasher(
766            self.len(),
767            self.hasher().to_static(),
768        );
769        set.extend(self.iter().map(ToBoundedStatic::to_static));
770        set
771    }
772}
773
774#[cfg(feature = "std")]
775/// Blanket [`IntoBoundedStatic`] impl for converting `HashSet<T>` into `HashSet<T>: 'static`.
776impl<T, S> IntoBoundedStatic for std::collections::HashSet<T, S>
777where
778    T: IntoBoundedStatic,
779    T::Static: Eq + std::hash::Hash,
780    S: ToBoundedStatic,
781    S::Static: std::hash::BuildHasher,
782{
783    type Static = std::collections::HashSet<T::Static, S::Static>;
784
785    fn into_static(self) -> Self::Static {
786        let mut set = std::collections::HashSet::with_capacity_and_hasher(
787            self.len(),
788            self.hasher().to_static(),
789        );
790        set.extend(self.into_iter().map(IntoBoundedStatic::into_static));
791        set
792    }
793}
794
795#[cfg(feature = "std")]
796/// [`ToBoundedStatic`] impl for `std::collections::hash_map::RandomState`.
797impl ToBoundedStatic for std::collections::hash_map::RandomState {
798    type Static = Self;
799
800    fn to_static(&self) -> Self::Static {
801        self.clone()
802    }
803}
804
805/// [`ToBoundedStatic`] impl for `smol_str::SmolStr`.
806#[cfg(feature = "smol_str")]
807impl ToBoundedStatic for smol_str::SmolStr {
808    type Static = Self;
809
810    fn to_static(&self) -> Self::Static {
811        self.clone()
812    }
813}
814
815/// No-op [`IntoBoundedStatic`] impl for `smol_str::SmolStr`.
816#[cfg(feature = "smol_str")]
817impl IntoBoundedStatic for smol_str::SmolStr {
818    type Static = Self;
819
820    fn into_static(self) -> Self::Static {
821        self
822    }
823}
824
825/// [`ToBoundedStatic`] impl for `smallvec::SmallVec`.
826#[cfg(feature = "smallvec")]
827impl<A> ToBoundedStatic for smallvec::SmallVec<A>
828where
829    A: smallvec::Array + 'static,
830    A::Item: Clone,
831{
832    type Static = Self;
833
834    fn to_static(&self) -> Self::Static {
835        self.clone()
836    }
837}
838
839/// No-op [`IntoBoundedStatic`] impl for `smallvec::SmallVec`.
840#[cfg(feature = "smallvec")]
841impl<A> IntoBoundedStatic for smallvec::SmallVec<A>
842where
843    A: smallvec::Array + 'static,
844    A::Item: Clone,
845{
846    type Static = Self;
847
848    fn into_static(self) -> Self::Static {
849        self
850    }
851}
852
853/// [`ToBoundedStatic`] impl for `smartstring::SmartString`.
854#[cfg(feature = "smartstring")]
855impl<Mode> ToBoundedStatic for smartstring::SmartString<Mode>
856where
857    Mode: smartstring::SmartStringMode + 'static,
858{
859    type Static = Self;
860
861    fn to_static(&self) -> Self::Static {
862        self.clone()
863    }
864}
865
866/// No-op [`IntoBoundedStatic`] impl for `smartstring::SmartString`.
867#[cfg(feature = "smartstring")]
868impl<Mode> IntoBoundedStatic for smartstring::SmartString<Mode>
869where
870    Mode: smartstring::SmartStringMode + 'static,
871{
872    type Static = Self;
873
874    fn into_static(self) -> Self::Static {
875        self
876    }
877}
878
879#[cfg(feature = "ahash")]
880/// [`ToBoundedStatic`] impl for `ahash::RandomState`.
881impl ToBoundedStatic for ahash::RandomState {
882    type Static = Self;
883
884    fn to_static(&self) -> Self::Static {
885        self.clone()
886    }
887}
888
889#[cfg(all(feature = "ahash", feature = "std"))]
890/// Blanket [`ToBoundedStatic`] impl for converting `ahash::AHashMap<K, V, S>` to `ahash::AHashMap<K, V, S>: 'static`.
891impl<K, V, S> ToBoundedStatic for ahash::AHashMap<K, V, S>
892where
893    K: ToBoundedStatic,
894    K::Static: Eq + std::hash::Hash,
895    V: ToBoundedStatic,
896    S: ToBoundedStatic,
897    S::Static: std::hash::BuildHasher,
898{
899    type Static = ahash::AHashMap<K::Static, V::Static, S::Static>;
900
901    fn to_static(&self) -> Self::Static {
902        let mut map =
903            ahash::AHashMap::with_capacity_and_hasher(self.len(), self.hasher().to_static());
904        map.extend(self.iter().map(|(k, v)| (k.to_static(), v.to_static())));
905        map
906    }
907}
908
909#[cfg(all(feature = "ahash", feature = "std"))]
910/// Blanket [`IntoBoundedStatic`] impl for converting `ahash::AHashMap<K, V, S>` into `ahash::AHashMap<K, V, S>: 'static`.
911impl<K, V, S> IntoBoundedStatic for ahash::AHashMap<K, V, S>
912where
913    K: IntoBoundedStatic,
914    K::Static: Eq + std::hash::Hash,
915    V: IntoBoundedStatic,
916    S: ToBoundedStatic,
917    S::Static: std::hash::BuildHasher,
918{
919    type Static = ahash::AHashMap<K::Static, V::Static, S::Static>;
920
921    fn into_static(self) -> Self::Static {
922        let mut map =
923            ahash::AHashMap::with_capacity_and_hasher(self.len(), self.hasher().to_static());
924        map.extend(
925            self.into_iter()
926                .map(|(k, v)| (k.into_static(), v.into_static())),
927        );
928        map
929    }
930}
931
932#[cfg(all(feature = "ahash", feature = "std"))]
933/// Blanket [`ToBoundedStatic`] impl for converting `ahash::AHashSet<T, S>` to `ahash::AHashSet<T, S>: 'static`.
934impl<T, S> ToBoundedStatic for ahash::AHashSet<T, S>
935where
936    T: ToBoundedStatic,
937    T::Static: Eq + std::hash::Hash,
938    S: ToBoundedStatic,
939    S::Static: std::hash::BuildHasher,
940{
941    type Static = ahash::AHashSet<T::Static, S::Static>;
942
943    fn to_static(&self) -> Self::Static {
944        let mut set =
945            ahash::AHashSet::with_capacity_and_hasher(self.len(), self.hasher().to_static());
946        set.extend(self.iter().map(ToBoundedStatic::to_static));
947        set
948    }
949}
950
951#[cfg(all(feature = "ahash", feature = "std"))]
952/// Blanket [`IntoBoundedStatic`] impl for converting `ahash::AHashSet<T, S>` into `ahash::AHashSet<T, S>: 'static`.
953impl<T, S> IntoBoundedStatic for ahash::AHashSet<T, S>
954where
955    T: IntoBoundedStatic,
956    T::Static: Eq + std::hash::Hash,
957    S: ToBoundedStatic,
958    S::Static: std::hash::BuildHasher,
959{
960    type Static = ahash::AHashSet<T::Static, S::Static>;
961
962    fn into_static(self) -> Self::Static {
963        let mut set =
964            ahash::AHashSet::with_capacity_and_hasher(self.len(), self.hasher().to_static());
965        set.extend(self.into_iter().map(IntoBoundedStatic::into_static));
966        set
967    }
968}
969
970#[cfg(feature = "chrono")]
971/// Blanket [`ToBoundedStatic`] impl for converting `chrono::DateTime<Tz>` into `chrono::DateTime<Tz>: 'static`.
972impl<Tz> ToBoundedStatic for chrono::DateTime<Tz>
973where
974    Tz: ToBoundedStatic + chrono::TimeZone,
975    Tz::Static: chrono::TimeZone,
976{
977    type Static = chrono::DateTime<Tz::Static>;
978
979    fn to_static(&self) -> Self::Static {
980        self.with_timezone(&self.timezone().to_static())
981    }
982}
983
984#[cfg(feature = "chrono")]
985/// Blanket [`IntoBoundedStatic`] impl for converting `chrono::DateTime<Tz>` into `chrono::DateTime<Tz>: 'static`.
986impl<Tz> IntoBoundedStatic for chrono::DateTime<Tz>
987where
988    Tz: IntoBoundedStatic + chrono::TimeZone,
989    Tz::Static: chrono::TimeZone,
990{
991    type Static = chrono::DateTime<Tz::Static>;
992
993    fn into_static(self) -> Self::Static {
994        self.with_timezone(&self.timezone().into_static())
995    }
996}
997
998#[cfg(feature = "chrono")]
999make_copy_impl!(chrono::FixedOffset);
1000#[cfg(feature = "chrono")]
1001make_copy_impl!(chrono::Months);
1002#[cfg(feature = "chrono")]
1003make_copy_impl!(chrono::TimeDelta);
1004#[cfg(feature = "chrono")]
1005make_copy_impl!(chrono::Utc);
1006#[cfg(feature = "chrono")]
1007make_copy_impl!(chrono::Month);
1008#[cfg(feature = "chrono")]
1009make_copy_impl!(chrono::Weekday);
1010#[cfg(feature = "chrono")]
1011make_copy_impl!(chrono::naive::Days);
1012#[cfg(feature = "chrono")]
1013make_copy_impl!(chrono::naive::IsoWeek);
1014#[cfg(feature = "chrono")]
1015make_copy_impl!(chrono::naive::NaiveDate);
1016#[cfg(feature = "chrono")]
1017make_copy_impl!(chrono::naive::NaiveDateTime);
1018#[cfg(feature = "chrono")]
1019make_copy_impl!(chrono::naive::NaiveTime);
1020#[cfg(feature = "chrono-clock")]
1021make_copy_impl!(chrono::Local);
1022// No implementation for chrono::NaiveWeek as it's not Copy nor Clone.
1023
1024#[cfg(test)]
1025mod core_tests {
1026    use super::*;
1027
1028    fn ensure_static<T: 'static>(t: T) {
1029        drop(t);
1030    }
1031
1032    #[test]
1033    fn test_bool() {
1034        ensure_static(false.to_static());
1035    }
1036
1037    #[test]
1038    fn test_char() {
1039        ensure_static('a'.to_static());
1040    }
1041
1042    #[test]
1043    fn test_f32() {
1044        ensure_static(0.0f32.to_static());
1045    }
1046
1047    #[test]
1048    fn test_f64() {
1049        ensure_static(0.0f64.to_static());
1050    }
1051
1052    #[test]
1053    fn test_usize() {
1054        ensure_static(0usize.to_static());
1055    }
1056
1057    #[test]
1058    fn test_u8() {
1059        ensure_static(0u8.to_static());
1060    }
1061
1062    #[test]
1063    fn test_u16() {
1064        ensure_static(0u16.to_static());
1065    }
1066
1067    #[test]
1068    fn test_u32() {
1069        ensure_static(0u32.to_static());
1070    }
1071
1072    #[test]
1073    fn test_u64() {
1074        ensure_static(0u64.to_static());
1075    }
1076
1077    #[test]
1078    fn test_u128() {
1079        ensure_static(0u128.to_static());
1080    }
1081
1082    #[test]
1083    fn test_isize() {
1084        ensure_static(0isize.to_static());
1085    }
1086
1087    #[test]
1088    fn test_i8() {
1089        ensure_static(0i8.to_static());
1090    }
1091
1092    #[test]
1093    fn test_i16() {
1094        ensure_static(0i16.to_static());
1095    }
1096
1097    #[test]
1098    fn test_i32() {
1099        ensure_static(0i32.to_static());
1100    }
1101
1102    #[test]
1103    fn test_i64() {
1104        ensure_static(0i64.to_static());
1105    }
1106
1107    #[test]
1108    fn test_i128() {
1109        ensure_static(0i128.to_static());
1110    }
1111
1112    #[test]
1113    fn test_non_zero_usize() {
1114        ensure_static(NonZeroUsize::new(1).unwrap().to_static());
1115    }
1116
1117    #[test]
1118    fn test_non_zero_u8() {
1119        ensure_static(NonZeroU8::new(1).unwrap().to_static());
1120    }
1121
1122    #[test]
1123    fn test_non_zero_u16() {
1124        ensure_static(NonZeroU16::new(1).unwrap().to_static());
1125    }
1126
1127    #[test]
1128    fn test_non_zero_u32() {
1129        ensure_static(NonZeroU32::new(1).unwrap().to_static());
1130    }
1131
1132    #[test]
1133    fn test_non_zero_u64() {
1134        ensure_static(NonZeroU64::new(1).unwrap().to_static());
1135    }
1136
1137    #[test]
1138    fn test_non_zero_u128() {
1139        ensure_static(NonZeroU128::new(1).unwrap().to_static());
1140    }
1141
1142    #[test]
1143    fn test_non_zero_isize() {
1144        ensure_static(NonZeroIsize::new(1).unwrap().to_static());
1145    }
1146
1147    #[test]
1148    fn test_non_zero_i8() {
1149        ensure_static(NonZeroI8::new(1).unwrap().to_static());
1150    }
1151
1152    #[test]
1153    fn test_non_zero_i16() {
1154        ensure_static(NonZeroI16::new(1).unwrap().to_static());
1155    }
1156
1157    #[test]
1158    fn test_non_zero_i32() {
1159        ensure_static(NonZeroI32::new(1).unwrap().to_static());
1160    }
1161
1162    #[test]
1163    fn test_non_zero_i64() {
1164        ensure_static(NonZeroI64::new(1).unwrap().to_static());
1165    }
1166
1167    #[test]
1168    fn test_non_zero_i128() {
1169        ensure_static(NonZeroI128::new(1).unwrap().to_static());
1170    }
1171
1172    #[test]
1173    fn test_unit() {
1174        #[allow(clippy::unit_arg)]
1175        ensure_static(().to_static());
1176    }
1177
1178    #[test]
1179    fn test_str() {
1180        let s = "";
1181        let to_static = s.to_static();
1182        ensure_static(to_static);
1183    }
1184
1185    #[test]
1186    fn test_option_none() {
1187        let value: Option<u32> = None;
1188        let to_static = value.to_static();
1189        ensure_static(to_static);
1190    }
1191
1192    #[test]
1193    fn test_option_some() {
1194        let value: Option<u32> = Some(32);
1195        let to_static = value.to_static();
1196        ensure_static(to_static);
1197    }
1198
1199    #[test]
1200    fn test_result() {
1201        #[derive(Clone)]
1202        struct MyError;
1203        #[allow(clippy::unnecessary_wraps)]
1204        fn foo_ok() -> Result<(), MyError> {
1205            Ok(())
1206        }
1207        #[allow(clippy::unnecessary_wraps)]
1208        fn foo_err() -> Result<(), MyError> {
1209            Err(MyError)
1210        }
1211        impl ToBoundedStatic for MyError {
1212            type Static = Self;
1213
1214            fn to_static(&self) -> Self::Static {
1215                self.clone()
1216            }
1217        }
1218        let ok_result = foo_ok();
1219        ensure_static(ok_result.to_static());
1220        assert!(ok_result.is_ok());
1221        let err_result = foo_err();
1222        ensure_static(err_result.to_static());
1223        assert!(err_result.is_err());
1224    }
1225
1226    #[test]
1227    fn test_array() {
1228        let arr = ["test"];
1229        ensure_static(arr.to_static());
1230    }
1231
1232    #[test]
1233    fn test_tuple2() {
1234        let tuple = ("test", 32);
1235        ensure_static(tuple.to_static());
1236    }
1237
1238    #[test]
1239    fn test_tuple11() {
1240        let tuple = (
1241            (),
1242            '1',
1243            "2",
1244            3_i32,
1245            4_usize,
1246            5_isize,
1247            6.0_f64,
1248            ["7"],
1249            Some(8),
1250            9,
1251            (10,),
1252            false,
1253        );
1254        ensure_static(tuple.to_static());
1255    }
1256}
1257
1258#[cfg(feature = "alloc")]
1259#[cfg(test)]
1260mod alloc_tests {
1261    use super::*;
1262
1263    fn ensure_static<T: 'static>(t: T) {
1264        drop(t);
1265    }
1266
1267    #[test]
1268    fn test_string() {
1269        let s = String::new();
1270        let to_static = s.to_static();
1271        ensure_static(to_static);
1272    }
1273
1274    #[test]
1275    fn test_cow_borrowed_str() {
1276        let s = String::new();
1277        let to_static = Cow::from(&s).to_static();
1278        ensure_static(to_static);
1279    }
1280
1281    #[test]
1282    fn test_cow_owned_string() {
1283        let s = String::new();
1284        let to_static = Cow::from(s).to_static();
1285        ensure_static(to_static);
1286    }
1287
1288    #[test]
1289    fn test_cow_to_static() {
1290        let s = String::new();
1291        let s_cow: Cow<'_, str> = Cow::Borrowed(&s);
1292        let s1_cow_owned: Cow<'_, str> = s_cow.to_static();
1293        let s2_cow_owned: Cow<'_, str> = Cow::Owned(s_cow.into_owned());
1294        assert_eq!(s1_cow_owned, s2_cow_owned);
1295    }
1296
1297    #[test]
1298    fn test_cow_into_static() {
1299        let s = String::new();
1300        let s_cow: Cow<'_, str> = Cow::Borrowed(&s);
1301        let s1_cow_owned: Cow<'_, str> = s_cow.clone().into_static();
1302        let s2_cow_owned: Cow<'_, str> = Cow::Owned(s_cow.into_owned());
1303        assert_eq!(s1_cow_owned, s2_cow_owned);
1304    }
1305
1306    #[test]
1307    fn test_option_none() {
1308        let value: Option<Cow<'_, str>> = None;
1309        let to_static = value.to_static();
1310        ensure_static(to_static);
1311    }
1312
1313    #[test]
1314    fn test_option_some() {
1315        let s = String::new();
1316        let value = Some(Cow::from(&s));
1317        let to_static = value.to_static();
1318        ensure_static(to_static);
1319    }
1320
1321    #[test]
1322    fn test_array() {
1323        let arr = ["test"];
1324        ensure_static(arr.to_static());
1325    }
1326
1327    #[test]
1328    fn test_array_into() {
1329        let s = String::new();
1330        let arr = [Cow::from(&s)];
1331        ensure_static(arr.into_static());
1332    }
1333
1334    #[test]
1335    fn test_vec1() {
1336        let s = String::new();
1337        let value = alloc::vec![Cow::from(&s)];
1338        let to_static = value.to_static();
1339        ensure_static(to_static);
1340    }
1341
1342    #[test]
1343    fn test_vec2() {
1344        let s = String::new();
1345        let value = alloc::vec![Cow::from(&s), Cow::from(s.as_str())];
1346        let to_static = value.to_static();
1347        ensure_static(to_static);
1348    }
1349
1350    #[test]
1351    fn test_box() {
1352        let s = String::new();
1353        let value = Box::new(s);
1354        let to_static = value.to_static();
1355        ensure_static(to_static);
1356    }
1357
1358    #[test]
1359    fn test_box_cow() {
1360        let s = String::new();
1361        let value = Box::new(Cow::from(&s));
1362        let to_static = value.to_static();
1363        ensure_static(to_static);
1364    }
1365
1366    #[test]
1367    fn test_box_vec_cow() {
1368        let s = String::new();
1369        let value = Box::new(alloc::vec![Cow::from(&s)]);
1370        let to_static = value.to_static();
1371        ensure_static(to_static);
1372    }
1373
1374    #[test]
1375    fn test_vec_box_cow() {
1376        let s = String::new();
1377        let value = alloc::vec![Box::new(Cow::from(&s))];
1378        let to_static = value.to_static();
1379        ensure_static(to_static);
1380    }
1381
1382    #[test]
1383    fn test_cow_box() {
1384        let s = String::new();
1385        let boxed = Box::new(s);
1386        let value = Cow::Borrowed(&boxed);
1387        let to_static = value.to_static();
1388        ensure_static(to_static);
1389    }
1390
1391    #[test]
1392    fn test_cow_struct() {
1393        #[derive(Copy, Clone)]
1394        struct Foo {}
1395        impl ToBoundedStatic for Foo {
1396            type Static = Self;
1397
1398            fn to_static(&self) -> Self::Static {
1399                *self
1400            }
1401        }
1402        let foo = Foo {};
1403        let value = Cow::Borrowed(&foo);
1404        let to_static = value.to_static();
1405        ensure_static(to_static);
1406    }
1407
1408    #[test]
1409    fn test_cow_struct_of_cow() {
1410        #[derive(Clone)]
1411        struct Foo<'a> {
1412            foo: Cow<'a, str>,
1413        }
1414        impl ToBoundedStatic for Foo<'_> {
1415            type Static = Foo<'static>;
1416
1417            fn to_static(&self) -> Self::Static {
1418                Foo {
1419                    foo: self.foo.to_static(),
1420                }
1421            }
1422        }
1423        let s = String::new();
1424        let foo = Foo { foo: Cow::from(&s) };
1425        let value = Cow::Borrowed(&foo);
1426        // TODO need to `into_owned()` here
1427        let to_static = value.into_owned().to_static();
1428        ensure_static(to_static);
1429    }
1430
1431    #[test]
1432    fn test_cow_cow() {
1433        let s = String::new();
1434        let value1: Cow<'_, str> = Cow::Borrowed(&s);
1435        let value2: Cow<'_, Cow<'_, str>> = Cow::Borrowed(&value1);
1436        // TODO need to `into_owned()` here
1437        let to_static = value2.into_owned().to_static();
1438        ensure_static(to_static);
1439    }
1440
1441    #[test]
1442    fn test_struct_cow_borrowed_str() {
1443        struct Foo<'a> {
1444            foo: Cow<'a, str>,
1445        }
1446        impl ToBoundedStatic for Foo<'_> {
1447            type Static = Foo<'static>;
1448
1449            fn to_static(&self) -> Self::Static {
1450                Foo {
1451                    foo: self.foo.to_static(),
1452                }
1453            }
1454        }
1455        let s = String::new();
1456        let foo = Foo { foo: Cow::from(&s) };
1457        let to_static = foo.to_static();
1458        ensure_static(to_static);
1459    }
1460
1461    #[test]
1462    fn test_struct_cow_owned_string() {
1463        struct Foo<'a> {
1464            foo: Cow<'a, str>,
1465        }
1466        impl ToBoundedStatic for Foo<'_> {
1467            type Static = Foo<'static>;
1468
1469            fn to_static(&self) -> Self::Static {
1470                Foo {
1471                    foo: self.foo.to_static(),
1472                }
1473            }
1474        }
1475        let s = String::new();
1476        let foo = Foo { foo: Cow::from(s) };
1477        let to_static = foo.to_static();
1478        ensure_static(to_static);
1479    }
1480
1481    #[test]
1482    fn test_struct_multi() {
1483        #[derive(Clone)]
1484        struct Foo<'a> {
1485            bar: Cow<'a, str>,
1486            baz: Vec<Cow<'a, str>>,
1487        }
1488        impl ToBoundedStatic for Foo<'_> {
1489            type Static = Foo<'static>;
1490
1491            fn to_static(&self) -> Self::Static {
1492                Foo {
1493                    bar: self.bar.to_static(),
1494                    baz: self.baz.to_static(),
1495                }
1496            }
1497        }
1498        let s = String::new();
1499        let foo = Foo {
1500            bar: Cow::from(&s),
1501            baz: alloc::vec![Cow::from(&s)],
1502        };
1503        let to_static = foo.to_static();
1504        ensure_static(to_static);
1505    }
1506
1507    #[test]
1508    fn test_struct_mixed() {
1509        struct Foo<'a> {
1510            prim: u64,
1511            borrowed_str: &'static str,
1512            owned_str: String,
1513            cow_str: Cow<'a, str>,
1514        }
1515        impl ToBoundedStatic for Foo<'_> {
1516            type Static = Foo<'static>;
1517
1518            fn to_static(&self) -> Self::Static {
1519                Foo {
1520                    prim: self.prim.to_static(),
1521                    borrowed_str: self.borrowed_str.to_static(),
1522                    owned_str: self.owned_str.to_static(),
1523                    cow_str: self.cow_str.to_static(),
1524                }
1525            }
1526        }
1527        let s = String::new();
1528        let foo = Foo {
1529            prim: 0,
1530            borrowed_str: "",
1531            owned_str: s.clone(),
1532            cow_str: Cow::from(&s),
1533        };
1534        let to_static = foo.to_static();
1535        ensure_static(to_static);
1536    }
1537}
1538
1539#[cfg(feature = "collections")]
1540#[cfg(test)]
1541mod collections_tests {
1542    use super::*;
1543
1544    fn ensure_static<T: 'static>(t: T) {
1545        drop(t);
1546    }
1547
1548    #[test]
1549    fn test_binary_heap() {
1550        let s = String::new();
1551        let value = BinaryHeap::from([Cow::from(&s)]);
1552        let to_static = value.to_static();
1553        ensure_static(to_static);
1554    }
1555
1556    #[test]
1557    fn test_btree_map() {
1558        let k = String::from("key");
1559        let v = String::from("value");
1560        let value = BTreeMap::from([(Cow::from(&k), Cow::from(&v))]);
1561        let to_static = value.to_static();
1562        ensure_static(to_static);
1563    }
1564
1565    #[test]
1566    fn test_btree_set() {
1567        let s = String::new();
1568        let value = BTreeSet::from([Cow::from(&s)]);
1569        let to_static = value.to_static();
1570        ensure_static(to_static);
1571    }
1572
1573    #[test]
1574    fn test_linked_list() {
1575        let s = String::new();
1576        let value = LinkedList::from([Cow::from(&s)]);
1577        let to_static = value.to_static();
1578        ensure_static(to_static);
1579    }
1580
1581    #[test]
1582    fn test_vec_deque() {
1583        let s = String::new();
1584        let value = VecDeque::from([Cow::from(&s)]);
1585        let to_static = value.to_static();
1586        ensure_static(to_static);
1587    }
1588}
1589
1590#[cfg(feature = "std")]
1591#[cfg(test)]
1592mod std_tests {
1593    use core::any::Any;
1594
1595    use super::*;
1596
1597    fn ensure_static<T: 'static>(t: T) {
1598        drop(t);
1599    }
1600
1601    #[test]
1602    fn test_hashmap1() {
1603        let k = String::from("key");
1604        let v = String::from("value");
1605        let value = std::collections::HashMap::from([(Cow::from(&k), Cow::from(&v))]);
1606        let to_static = value.to_static();
1607        ensure_static(to_static);
1608    }
1609
1610    #[test]
1611    fn test_hashmap2() {
1612        let k = "key";
1613        let v = String::from("value");
1614        let value = std::collections::HashMap::from([(k, Cow::from(&v))]);
1615        let to_static = value.to_static();
1616        ensure_static(to_static);
1617    }
1618
1619    #[test]
1620    fn test_hashmap3() {
1621        let k = String::from("key");
1622        let v = 0i16;
1623        let value = std::collections::HashMap::from([(Cow::from(&k), v)]);
1624        let to_static = value.to_static();
1625        ensure_static(to_static);
1626    }
1627
1628    #[test]
1629    fn test_hashset() {
1630        let value = String::from("data");
1631        let value = std::collections::HashSet::from([(Cow::from(&value))]);
1632        let to_static = value.to_static();
1633        ensure_static(to_static);
1634    }
1635
1636    #[test]
1637    fn test_custom_random_state() {
1638        #[derive(Clone, Default)]
1639        struct RandomState;
1640
1641        impl std::hash::BuildHasher for RandomState {
1642            type Hasher = std::collections::hash_map::DefaultHasher;
1643
1644            fn build_hasher(&self) -> Self::Hasher {
1645                std::collections::hash_map::DefaultHasher::default()
1646            }
1647        }
1648
1649        impl ToBoundedStatic for RandomState {
1650            type Static = Self;
1651
1652            fn to_static(&self) -> Self::Static {
1653                self.clone()
1654            }
1655        }
1656
1657        let k = "key";
1658        let v = 0i16;
1659        let value = std::collections::HashMap::<_, _, RandomState>::from_iter([(k, v)]);
1660        let to_static = value.to_static();
1661        assert_eq!(value.type_id(), to_static.type_id());
1662        ensure_static(to_static);
1663        let value = std::collections::HashSet::<_, RandomState>::from_iter([k]);
1664        let to_static = value.to_static();
1665        assert_eq!(value.type_id(), to_static.type_id());
1666        ensure_static(to_static);
1667    }
1668}
1669
1670#[cfg(feature = "smol_str")]
1671#[cfg(test)]
1672mod smol_str_tests {
1673    use super::*;
1674
1675    fn ensure_static<T: 'static>(t: T) {
1676        drop(t);
1677    }
1678
1679    #[test]
1680    fn test_smol_str() {
1681        ensure_static(smol_str::SmolStr::new("smol").to_static());
1682        ensure_static(smol_str::SmolStr::new("smol").into_static());
1683    }
1684}
1685
1686#[cfg(feature = "smallvec")]
1687#[cfg(test)]
1688mod smallvec_tests {
1689    use super::*;
1690
1691    fn ensure_static<T: 'static>(t: T) {
1692        drop(t);
1693    }
1694
1695    #[test]
1696    fn test_smallvec1() {
1697        let vec: smallvec::SmallVec<[usize; 0]> = smallvec::SmallVec::new();
1698        ensure_static(vec.to_static());
1699        ensure_static(vec.into_static());
1700    }
1701
1702    #[test]
1703    fn test_smallvec2() {
1704        let buf = [1, 2, 3, 4, 5];
1705        let small_vec: smallvec::SmallVec<_> = smallvec::SmallVec::from_buf(buf);
1706        ensure_static(small_vec.to_static());
1707        ensure_static(small_vec.into_static());
1708    }
1709}
1710
1711#[cfg(feature = "smartstring")]
1712#[cfg(test)]
1713mod smartstring_tests {
1714    use super::*;
1715    use smartstring::alias::String;
1716
1717    fn ensure_static<T: 'static>(t: T) {
1718        drop(t);
1719    }
1720
1721    #[test]
1722    fn test_smartstring() {
1723        let string = String::from("test");
1724        ensure_static(string.to_static());
1725        ensure_static(string.into_static());
1726    }
1727}
1728
1729#[cfg(feature = "ahash")]
1730#[cfg(test)]
1731mod ahash_tests {
1732    use super::*;
1733
1734    fn ensure_static<T: 'static>(t: T) {
1735        drop(t);
1736    }
1737
1738    #[test]
1739    fn test_ahash_random_state() {
1740        ensure_static(ahash::RandomState::new().to_static());
1741    }
1742
1743    #[cfg(feature = "std")]
1744    #[test]
1745    fn test_ahash_ahashmap() {
1746        let k = String::from("key");
1747        let v = String::from("value");
1748        let value = ahash::AHashMap::from([(Cow::from(&k), Cow::from(&v))]);
1749        let to_static = value.to_static();
1750        ensure_static(to_static);
1751    }
1752
1753    #[cfg(feature = "std")]
1754    #[test]
1755    fn test_ahash_ahashset() {
1756        let value = String::from("data");
1757        let value = ahash::AHashSet::from([(Cow::from(&value))]);
1758        let to_static = value.to_static();
1759        ensure_static(to_static);
1760    }
1761}
1762
1763#[cfg(feature = "chrono")]
1764#[cfg(test)]
1765mod chrono_tests {
1766    use super::*;
1767
1768    fn ensure_static<T: 'static>(t: T) {
1769        drop(t);
1770    }
1771
1772    #[test]
1773    fn test_chrono_datetime() {
1774        let value = chrono::Utc::now();
1775        let to_static = value.to_static();
1776        assert_eq!(value, to_static);
1777        ensure_static(to_static);
1778    }
1779
1780    #[test]
1781    fn test_chrono_datetime_with_custom_tz() {
1782        use chrono::{
1783            DateTime, FixedOffset, MappedLocalTime, NaiveDate, NaiveDateTime, Offset, TimeZone,
1784        };
1785        #[derive(Debug, Clone)]
1786        struct MyOffset;
1787        impl Offset for MyOffset {
1788            fn fix(&self) -> FixedOffset {
1789                FixedOffset::east_opt(1).unwrap()
1790            }
1791        }
1792        #[derive(Clone)]
1793        struct MyTz;
1794        impl TimeZone for MyTz {
1795            type Offset = MyOffset;
1796
1797            fn from_offset(_offset: &Self::Offset) -> Self {
1798                Self
1799            }
1800
1801            fn offset_from_local_date(&self, _local: &NaiveDate) -> MappedLocalTime<Self::Offset> {
1802                MappedLocalTime::None
1803            }
1804
1805            fn offset_from_local_datetime(
1806                &self,
1807                _local: &NaiveDateTime,
1808            ) -> MappedLocalTime<Self::Offset> {
1809                MappedLocalTime::None
1810            }
1811
1812            fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Self::Offset {
1813                MyOffset
1814            }
1815
1816            fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Self::Offset {
1817                MyOffset
1818            }
1819        }
1820
1821        impl ToBoundedStatic for MyTz {
1822            type Static = Self;
1823
1824            fn to_static(&self) -> Self::Static {
1825                self.clone()
1826            }
1827        }
1828
1829        let value = DateTime::from_timestamp(0, 0).unwrap().with_timezone(&MyTz);
1830        let to_static = value.to_static();
1831        ensure_static(to_static);
1832    }
1833
1834    #[test]
1835    fn test_chrono_fixed_offset() {
1836        let value = chrono::FixedOffset::east_opt(1).unwrap();
1837        let to_static = value.to_static();
1838        ensure_static(to_static);
1839    }
1840
1841    #[test]
1842    fn test_chrono_months() {
1843        let value = chrono::Months::new(1);
1844        let to_static = value.to_static();
1845        ensure_static(to_static);
1846    }
1847
1848    #[test]
1849    fn test_chrono_time_delta() {
1850        let value = chrono::TimeDelta::days(10);
1851        let to_static = value.to_static();
1852        ensure_static(to_static);
1853    }
1854
1855    #[test]
1856    fn test_chrono_utc() {
1857        let value = chrono::Utc;
1858        let to_static = value.to_static();
1859        ensure_static(to_static);
1860    }
1861
1862    #[test]
1863    fn test_chrono_month() {
1864        let value = chrono::Month::January;
1865        let to_static = value.to_static();
1866        ensure_static(to_static);
1867    }
1868
1869    #[test]
1870    fn test_chrono_weekday() {
1871        let value = chrono::Weekday::Mon;
1872        let to_static = value.to_static();
1873        ensure_static(to_static);
1874    }
1875
1876    #[test]
1877    fn test_chrono_naive_days() {
1878        let value = chrono::naive::Days::new(1);
1879        let to_static = value.to_static();
1880        ensure_static(to_static);
1881    }
1882
1883    #[test]
1884    fn test_chrono_naive_iso_week() {
1885        use chrono::Datelike;
1886        let value = chrono::naive::NaiveDate::from_ymd_opt(2024, 6, 1)
1887            .unwrap()
1888            .iso_week();
1889        let to_static = value.to_static();
1890        ensure_static(to_static);
1891    }
1892
1893    #[test]
1894    fn test_chrono_naive_date() {
1895        let value = chrono::naive::NaiveDate::from_ymd_opt(2024, 6, 1).unwrap();
1896        let to_static = value.to_static();
1897        ensure_static(to_static);
1898    }
1899
1900    #[test]
1901    fn test_chrono_naive_date_time() {
1902        let value = chrono::naive::NaiveDateTime::new(
1903            chrono::NaiveDate::from_ymd_opt(2024, 6, 1).unwrap(),
1904            chrono::NaiveTime::from_hms_opt(22, 33, 44).unwrap(),
1905        );
1906        let to_static = value.to_static();
1907        ensure_static(to_static);
1908    }
1909
1910    #[test]
1911    fn test_chrono_naive_time() {
1912        let value = chrono::naive::NaiveTime::from_hms_opt(22, 33, 44).unwrap();
1913        let to_static = value.to_static();
1914        ensure_static(to_static);
1915    }
1916}
1917
1918#[cfg(feature = "chrono-clock")]
1919#[cfg(test)]
1920mod chrono_clock_tests {
1921    use super::*;
1922
1923    fn ensure_static<T: 'static>(t: T) {
1924        drop(t);
1925    }
1926
1927    #[test]
1928    fn test_chrono_local() {
1929        let value = chrono::Local::now();
1930        let to_static = value.to_static();
1931        ensure_static(to_static);
1932    }
1933}