Skip to main content

turbo_tasks/
display.rs

1use std::future::Future;
2
3use anyhow::Result;
4use turbo_rcstr::RcStr;
5use turbo_tasks::Vc;
6pub use turbo_tasks_macros::ValueToString;
7
8use crate::{self as turbo_tasks};
9
10/// Async counterpart to `Display`, returning `Vc<RcStr>`.
11///
12/// Use `#[derive(ValueToString)]` to generate an implementation.
13#[doc = include_str!("../FORMATTING.md")]
14#[turbo_tasks::value_trait]
15pub trait ValueToString {
16    #[turbo_tasks::function]
17    fn to_string(self: Vc<Self>) -> Vc<RcStr>;
18}
19
20/// Implements an async counterpart to `Display`, returning `RcStr`. This may
21/// act as an optimization.
22pub trait ValueToStringRef {
23    fn to_string_ref(&self) -> impl Future<Output = Result<RcStr>> + Send;
24}
25
26/// Ref-following: `&T` delegates to `T`'s `ValueToStringRef`.
27impl<T: ValueToStringRef + Sync> ValueToStringRef for &T {
28    fn to_string_ref(&self) -> impl Future<Output = Result<RcStr>> + Send {
29        (**self).to_string_ref()
30    }
31}
32
33/// Identity implementation: `RcStr` just returns itself.
34#[turbo_tasks::value_impl]
35impl ValueToString for RcStr {
36    #[turbo_tasks::function]
37    fn to_string(self: Vc<Self>) -> Vc<RcStr> {
38        self
39    }
40}
41
42/// Identity implementation: `RcStr` just returns itself.
43impl ValueToStringRef for RcStr {
44    async fn to_string_ref(&self) -> Result<RcStr> {
45        Ok(self.clone())
46    }
47}
48
49/// Deref-following: `ReadRef<T>` delegates to the deref target's `ValueToStringRef`.
50impl<T> ValueToStringRef for crate::ReadRef<T>
51where
52    T: crate::VcValueType,
53    <T::Read as crate::VcRead<T>>::Target: ValueToStringRef,
54{
55    fn to_string_ref(&self) -> impl Future<Output = Result<RcStr>> + Send {
56        (**self).to_string_ref()
57    }
58}
59
60/// Part of the auto-deref specialization system.
61#[doc(hidden)]
62#[macro_export]
63macro_rules! __turbo_stringify {
64    ($name:ident, $i:expr) => {
65        // Ugh: https://sabrinajewson.org/blog/truly-hygienic-let
66        // This "let mut" makes errors more obvious in this case
67        let mut $name: $crate::display::macro_helpers::StringifyType = {
68            use $crate::display::macro_helpers::ValueToStringify as _;
69            let tmp = $crate::display::macro_helpers::ValueToStringifyWrap($i);
70            (&&&tmp).to_stringify().await?
71        };
72    };
73}
74
75/// Runtime helpers for the `turbofmt!`/`turbobail!` macros. Not part of the
76/// public API.
77#[doc(hidden)]
78pub mod macro_helpers {
79    use std::{
80        fmt::{self, Display},
81        future::Future,
82    };
83
84    use anyhow::Result;
85    use turbo_rcstr::RcStr;
86
87    use super::{ValueToString, ValueToStringRef};
88    use crate::vc::ResolvedVc;
89
90    pub struct ValueToStringifyWrap<T>(pub T);
91
92    pub trait ValueToStringify<const LEVEL: u8> {
93        fn to_stringify(&self) -> impl Future<Output = Result<StringifyType>> + Send;
94    }
95
96    pub enum StringifyType {
97        RcStr(RcStr),
98        String(String),
99    }
100
101    impl AsRef<str> for StringifyType {
102        fn as_ref(&self) -> &str {
103            match self {
104                StringifyType::RcStr(s) => s.as_str(),
105                StringifyType::String(s) => s.as_str(),
106            }
107        }
108    }
109
110    impl fmt::Debug for StringifyType {
111        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112            fmt::Debug::fmt(self.as_ref(), f)
113        }
114    }
115
116    impl Display for StringifyType {
117        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118            f.write_str(self.as_ref())
119        }
120    }
121
122    impl From<StringifyType> for RcStr {
123        fn from(s: StringifyType) -> Self {
124            match s {
125                StringifyType::RcStr(r) => r,
126                StringifyType::String(s) => RcStr::from(s),
127            }
128        }
129    }
130
131    /// Blanket impl: uses synchronous `Display::to_string()` for owned values.
132    impl<T: Display + Send + Sync> ValueToStringify<1> for &ValueToStringifyWrap<&T> {
133        #[inline(always)]
134        fn to_stringify(&self) -> impl Future<Output = Result<StringifyType>> + Send {
135            let s = (self.0).to_string();
136            async move { Ok(StringifyType::String(s)) }
137        }
138    }
139
140    impl<T: Send> ValueToStringify<2> for &&ValueToStringifyWrap<&crate::Vc<T>>
141    where
142        T: ValueToString,
143    {
144        #[inline(always)]
145        fn to_stringify(&self) -> impl Future<Output = Result<StringifyType>> + Send {
146            let vc = self.0;
147            async move {
148                let s = vc.to_string().await?;
149                Ok(StringifyType::RcStr((*s).clone()))
150            }
151        }
152    }
153
154    impl<T: Send> ValueToStringify<2> for &&ValueToStringifyWrap<&ResolvedVc<T>>
155    where
156        T: ValueToString,
157    {
158        #[inline(always)]
159        fn to_stringify(&self) -> impl Future<Output = Result<StringifyType>> + Send {
160            let vc = self.0;
161            async move {
162                let s = vc.to_string().await?;
163                Ok(StringifyType::RcStr((*s).clone()))
164            }
165        }
166    }
167
168    impl<T: Send> ValueToStringify<2> for &&&ValueToStringifyWrap<&T>
169    where
170        T: ValueToStringRef,
171    {
172        #[inline(always)]
173        fn to_stringify(&self) -> impl Future<Output = Result<StringifyType>> {
174            let s = self.0.to_string_ref();
175            async move { Ok(StringifyType::RcStr(s.await?)) }
176        }
177    }
178}