Skip to content

Commit 91a2aec

Browse files
committed
Introduce MaybeLazy(Cow) for 3-way lazy-less
1 parent e23ae72 commit 91a2aec

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//! A custom LazyLock+Cow suitable for holding borrowed, owned or lazy data.
2+
3+
use std::borrow::{Borrow, Cow};
4+
use std::fmt::{Debug, Display};
5+
use std::ops::Deref;
6+
use std::sync::LazyLock;
7+
8+
enum MaybeLazyInner<T: 'static + ToOwned + ?Sized> {
9+
Lazy(LazyLock<T::Owned>),
10+
Cow(Cow<'static, T>),
11+
}
12+
13+
/// A custom LazyLock+Cow suitable for holding borrowed, owned or lazy data.
14+
///
15+
/// Technically this structure has 3 states: borrowed, owned and lazy
16+
/// They can all be constructed from the [`MaybeLazy::borrowed`], [`MaybeLazy::owned`] and
17+
/// [`MaybeLazy::lazy`] methods.
18+
#[repr(transparent)]
19+
pub struct MaybeLazy<T: 'static + ToOwned + ?Sized> {
20+
// Inner state.
21+
//
22+
// Not to be inlined since we may want in the future to
23+
// make this struct usable to statics and we might need to
24+
// workaround const-eval limitation (particulary around drop).
25+
inner: MaybeLazyInner<T>,
26+
}
27+
28+
impl<T: 'static + ?Sized + ToOwned> MaybeLazy<T> {
29+
/// Create a [`MaybeLazy`] from an borrowed `T`.
30+
#[inline]
31+
pub const fn borrowed(a: &'static T) -> Self {
32+
MaybeLazy { inner: MaybeLazyInner::Cow(Cow::Borrowed(a)) }
33+
}
34+
35+
/// Create a [`MaybeLazy`] from an borrowed `T`.
36+
#[inline]
37+
pub const fn owned(a: T::Owned) -> Self {
38+
MaybeLazy { inner: MaybeLazyInner::Cow(Cow::Owned(a)) }
39+
}
40+
41+
/// Create a [`MaybeLazy`] that is lazy by taking a function pointer.
42+
///
43+
/// This function pointer cannot *ever* take a closure. User can potentially
44+
/// workaround that by using closure-to-fnptr or `const` items.
45+
#[inline]
46+
pub const fn lazy(a: fn() -> T::Owned) -> Self {
47+
MaybeLazy { inner: MaybeLazyInner::Lazy(LazyLock::new(a)) }
48+
}
49+
}
50+
51+
impl<T: 'static + ?Sized + ToOwned<Owned: Clone>> Clone for MaybeLazy<T> {
52+
#[inline]
53+
fn clone(&self) -> Self {
54+
MaybeLazy {
55+
inner: MaybeLazyInner::Cow(match &self.inner {
56+
MaybeLazyInner::Lazy(f) => Cow::Owned((*f).to_owned()),
57+
MaybeLazyInner::Cow(c) => c.clone(),
58+
}),
59+
}
60+
}
61+
}
62+
63+
impl<T: 'static + ?Sized + ToOwned<Owned: Default>> Default for MaybeLazy<T> {
64+
#[inline]
65+
fn default() -> MaybeLazy<T> {
66+
MaybeLazy::lazy(T::Owned::default)
67+
}
68+
}
69+
70+
// `Debug`, `Display` and other traits below are implemented in terms of this `Deref`
71+
impl<T: 'static + ?Sized + ToOwned<Owned: Borrow<T>>> Deref for MaybeLazy<T> {
72+
type Target = T;
73+
74+
#[inline]
75+
fn deref(&self) -> &T {
76+
match &self.inner {
77+
MaybeLazyInner::Lazy(f) => (&**f).borrow(),
78+
MaybeLazyInner::Cow(c) => &*c,
79+
}
80+
}
81+
}
82+
83+
impl<T: 'static + ?Sized + ToOwned<Owned: Debug> + Debug> Debug for MaybeLazy<T> {
84+
#[inline]
85+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86+
Debug::fmt(&**self, fmt)
87+
}
88+
}
89+
90+
impl<T: 'static + ?Sized + ToOwned<Owned: Display> + Display> Display for MaybeLazy<T> {
91+
#[inline]
92+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93+
Display::fmt(&**self, fmt)
94+
}
95+
}
96+
97+
impl<T: 'static + ?Sized + ToOwned> AsRef<T> for MaybeLazy<T> {
98+
#[inline]
99+
fn as_ref(&self) -> &T {
100+
&**self
101+
}
102+
}
103+
104+
impl<B: ?Sized + PartialEq<C> + ToOwned, C: ?Sized + ToOwned> PartialEq<MaybeLazy<C>>
105+
for MaybeLazy<B>
106+
{
107+
#[inline]
108+
fn eq(&self, other: &MaybeLazy<C>) -> bool {
109+
PartialEq::eq(&**self, &**other)
110+
}
111+
}
112+
113+
impl PartialEq<&str> for MaybeLazy<str> {
114+
#[inline]
115+
fn eq(&self, other: &&str) -> bool {
116+
&**self == *other
117+
}
118+
}
119+
120+
impl From<&'static str> for MaybeLazy<str> {
121+
#[inline]
122+
fn from(s: &'static str) -> MaybeLazy<str> {
123+
MaybeLazy::borrowed(s)
124+
}
125+
}

compiler/rustc_target/src/spec/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,16 @@ use tracing::debug;
5555

5656
pub mod abi;
5757
pub mod crt_objects;
58+
pub mod maybe_lazy;
5859

5960
mod base;
6061
pub use base::apple::deployment_target as current_apple_deployment_target;
6162
pub use base::apple::platform as current_apple_platform;
6263
pub use base::apple::sdk_version as current_apple_sdk_version;
6364
pub use base::avr_gnu::ef_avr_arch;
6465

66+
use maybe_lazy::MaybeLazy;
67+
6568
/// Linker is called through a C/C++ compiler.
6669
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
6770
pub enum Cc {

0 commit comments

Comments
 (0)