cream_core/
reference.rs

1use serde::{Deserialize, Serialize, Serializer};
2
3/// A reference to a resource or external URL.
4#[derive(Serialize, Deserialize, Debug, Clone)]
5pub struct Reference(ReferenceInner);
6
7impl Reference {
8    /// Construct a new relative reference.
9    pub fn new_relative(relative: &str) -> Self {
10        Self(ReferenceInner::Relative(RelativeReference(
11            relative.to_string(),
12        )))
13    }
14    /// Construct a new absolute reference.
15    pub fn new_absolute(absolute: &str) -> Self {
16        Self(ReferenceInner::Absolute(absolute.to_string()))
17    }
18}
19
20#[derive(Serialize, Deserialize, Debug, Clone)]
21#[serde(untagged)]
22enum ReferenceInner {
23    Absolute(String),
24    #[serde(skip_deserializing)]
25    Relative(RelativeReference),
26}
27
28#[cfg(feature = "tokio")]
29tokio::task_local! {
30    #[doc(hidden)]
31    pub static BASE_URL: String;
32}
33
34#[derive(Debug, Clone)]
35struct RelativeReference(String);
36
37impl Serialize for RelativeReference {
38    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
39    where
40        S: Serializer,
41    {
42        #[cfg(feature = "tokio")]
43        let absolute_url = BASE_URL
44            .try_with(|base_url| format!("{}{}", base_url, self.0))
45            .unwrap_or(self.0.clone());
46        #[cfg(not(feature = "tokio"))]
47        let absolute_url = self.0.clone();
48        serializer.serialize_str(&absolute_url)
49    }
50}