Skip to content

Commit 7753afd

Browse files
committed
Introduce MaybeLazy(Cow) to rustc_target for lazyless
1 parent 69f53f5 commit 7753afd

File tree

3 files changed

+141
-0
lines changed

3 files changed

+141
-0
lines changed

compiler/rustc_target/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#![feature(assert_matches)]
1515
#![feature(iter_intersperse)]
1616
#![feature(let_chains)]
17+
#![feature(lazy_cell)]
1718
#![feature(rustc_attrs)]
1819
#![feature(step_trait)]
1920
#![allow(internal_features)]
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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 as ToOwned>::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+
Self { 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 as ToOwned>::Owned) -> Self {
38+
Self { 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 as ToOwned>::Owned) -> Self {
47+
Self { inner: MaybeLazyInner::Lazy(LazyLock::new(a)) }
48+
}
49+
}
50+
51+
impl<T: 'static + ?Sized + ToOwned> Clone for MaybeLazy<T>
52+
where
53+
<T as ToOwned>::Owned: Clone,
54+
{
55+
#[inline]
56+
fn clone(&self) -> Self {
57+
Self {
58+
inner: MaybeLazyInner::Cow(match &self.inner {
59+
MaybeLazyInner::Lazy(f) => Cow::Owned((*f).to_owned()),
60+
MaybeLazyInner::Cow(c) => c.clone(),
61+
}),
62+
}
63+
}
64+
}
65+
66+
impl<T: 'static + ?Sized + ToOwned> Deref for MaybeLazy<T>
67+
where
68+
T::Owned: Borrow<T>,
69+
{
70+
type Target = T;
71+
72+
#[inline]
73+
fn deref(&self) -> &T {
74+
match &self.inner {
75+
MaybeLazyInner::Lazy(f) => (&**f).borrow(),
76+
MaybeLazyInner::Cow(c) => &*c,
77+
}
78+
}
79+
}
80+
81+
impl<T: 'static + ?Sized + ToOwned + Debug> Debug for MaybeLazy<T>
82+
where
83+
<T as ToOwned>::Owned: Debug,
84+
{
85+
#[inline]
86+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87+
match &self.inner {
88+
MaybeLazyInner::Lazy(f) => Debug::fmt(&**f, fmt),
89+
MaybeLazyInner::Cow(c) => Debug::fmt(c, fmt),
90+
}
91+
}
92+
}
93+
94+
impl<T: 'static + ?Sized + ToOwned + Display> Display for MaybeLazy<T>
95+
where
96+
<T as ToOwned>::Owned: Display,
97+
{
98+
#[inline]
99+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100+
match &self.inner {
101+
MaybeLazyInner::Lazy(f) => Display::fmt(&**f, fmt),
102+
MaybeLazyInner::Cow(c) => Display::fmt(c, fmt),
103+
}
104+
}
105+
}
106+
107+
impl<T: 'static + ?Sized + ToOwned> AsRef<T> for MaybeLazy<T> {
108+
#[inline]
109+
fn as_ref(&self) -> &T {
110+
&**self
111+
}
112+
}
113+
114+
impl<B: ?Sized, C: ?Sized> PartialEq<MaybeLazy<C>> for MaybeLazy<B>
115+
where
116+
B: PartialEq<C> + ToOwned,
117+
C: ToOwned,
118+
{
119+
#[inline]
120+
fn eq(&self, other: &MaybeLazy<C>) -> bool {
121+
PartialEq::eq(&**self, &**other)
122+
}
123+
}
124+
125+
impl PartialEq<&str> for MaybeLazy<str> {
126+
#[inline]
127+
fn eq(&self, other: &&str) -> bool {
128+
&**self == *other
129+
}
130+
}
131+
132+
impl From<&'static str> for MaybeLazy<str> {
133+
#[inline]
134+
fn from(s: &'static str) -> MaybeLazy<str> {
135+
MaybeLazy::borrowed(s)
136+
}
137+
}

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)