Skip to content

Commit f655bde

Browse files
committed
Add MaybeLazy(Cow) for 3-way lazy-ness
1 parent ff4b398 commit f655bde

File tree

3 files changed

+148
-0
lines changed

3 files changed

+148
-0
lines changed

compiler/rustc_target/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
1313
#![doc(rust_logo)]
1414
#![feature(assert_matches)]
15+
#![feature(fn_traits)]
1516
#![feature(iter_intersperse)]
1617
#![feature(let_chains)]
1718
#![feature(min_exhaustive_patterns)]
1819
#![feature(rustc_attrs)]
1920
#![feature(rustdoc_internals)]
21+
#![feature(unboxed_closures)]
2022
// tidy-alphabetical-end
2123

2224
use std::path::{Path, PathBuf};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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, F> {
9+
Lazy(LazyLock<T::Owned, F>),
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, F = fn() -> <T as ToOwned>::Owned> {
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, F>,
26+
}
27+
28+
impl<T: 'static + ?Sized + ToOwned, F: FnOnce() -> T::Owned> MaybeLazy<T, F> {
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`] from a function-able `F`.
42+
#[inline]
43+
pub const fn lazied(f: F) -> Self {
44+
MaybeLazy { inner: MaybeLazyInner::Lazy(LazyLock::new(f)) }
45+
}
46+
}
47+
48+
impl<T: 'static + ?Sized + ToOwned> MaybeLazy<T> {
49+
/// Create a [`MaybeLazy`] from a function pointer.
50+
#[inline]
51+
pub const fn lazy(a: fn() -> T::Owned) -> Self {
52+
Self::lazied(a)
53+
}
54+
}
55+
56+
impl<T: 'static + ?Sized + ToOwned<Owned: Clone>, F: FnOnce() -> T::Owned> Clone
57+
for MaybeLazy<T, F>
58+
{
59+
#[inline]
60+
fn clone(&self) -> Self {
61+
MaybeLazy {
62+
inner: MaybeLazyInner::Cow(match &self.inner {
63+
MaybeLazyInner::Lazy(f) => Cow::Owned((*f).to_owned()),
64+
MaybeLazyInner::Cow(c) => c.clone(),
65+
}),
66+
}
67+
}
68+
}
69+
70+
impl<T: 'static + ?Sized + ToOwned<Owned: Default>, F: FnOnce() -> T::Owned> Default
71+
for MaybeLazy<T, F>
72+
{
73+
#[inline]
74+
fn default() -> MaybeLazy<T, F> {
75+
MaybeLazy::owned(T::Owned::default())
76+
}
77+
}
78+
79+
// `Debug`, `Display` and other traits below are implemented in terms of this `Deref`
80+
impl<T: 'static + ?Sized + ToOwned<Owned: Borrow<T>>, F: FnOnce() -> T::Owned> Deref
81+
for MaybeLazy<T, F>
82+
{
83+
type Target = T;
84+
85+
#[inline]
86+
fn deref(&self) -> &T {
87+
match &self.inner {
88+
MaybeLazyInner::Lazy(f) => (&**f).borrow(),
89+
MaybeLazyInner::Cow(c) => &*c,
90+
}
91+
}
92+
}
93+
94+
impl<T: 'static + ?Sized + ToOwned<Owned: Debug> + Debug, F: FnOnce() -> T::Owned> Debug
95+
for MaybeLazy<T, F>
96+
{
97+
#[inline]
98+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99+
Debug::fmt(&**self, fmt)
100+
}
101+
}
102+
103+
impl<T: 'static + ?Sized + ToOwned<Owned: Display> + Display, F: FnOnce() -> T::Owned> Display
104+
for MaybeLazy<T, F>
105+
{
106+
#[inline]
107+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108+
Display::fmt(&**self, fmt)
109+
}
110+
}
111+
112+
impl<T: 'static + ?Sized + ToOwned, F: FnOnce() -> T::Owned> AsRef<T> for MaybeLazy<T, F> {
113+
#[inline]
114+
fn as_ref(&self) -> &T {
115+
&**self
116+
}
117+
}
118+
119+
impl<
120+
T1: ?Sized + PartialEq<T2> + ToOwned,
121+
T2: ?Sized + ToOwned,
122+
F1: FnOnce() -> T1::Owned,
123+
F2: FnOnce() -> T2::Owned,
124+
> PartialEq<MaybeLazy<T2, F2>> for MaybeLazy<T1, F1>
125+
{
126+
#[inline]
127+
fn eq(&self, other: &MaybeLazy<T2, F2>) -> bool {
128+
PartialEq::eq(&**self, &**other)
129+
}
130+
}
131+
132+
impl<F: FnOnce() -> String> PartialEq<&str> for MaybeLazy<str, F> {
133+
#[inline]
134+
fn eq(&self, other: &&str) -> bool {
135+
&**self == *other
136+
}
137+
}
138+
139+
impl<F: FnOnce() -> String> From<&'static str> for MaybeLazy<str, F> {
140+
#[inline]
141+
fn from(s: &'static str) -> MaybeLazy<str, F> {
142+
MaybeLazy::borrowed(s)
143+
}
144+
}

compiler/rustc_target/src/spec/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors
3939
use crate::json::{Json, ToJson};
4040
use crate::spec::abi::Abi;
4141
use crate::spec::crt_objects::CrtObjects;
42+
use crate::spec::maybe_lazy::MaybeLazy;
4243
use rustc_fs_util::try_canonicalize;
4344
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
4445
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@@ -55,6 +56,7 @@ use tracing::debug;
5556

5657
pub mod abi;
5758
pub mod crt_objects;
59+
pub mod maybe_lazy;
5860

5961
mod base;
6062
pub use base::apple::deployment_target as current_apple_deployment_target;

0 commit comments

Comments
 (0)