cream_core/
reference.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
use serde::{Deserialize, Serialize, Serializer};

/// A reference to a resource or external URL.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Reference(ReferenceInner);

impl Reference {
    /// Construct a new relative reference.
    pub fn new_relative(relative: &str) -> Self {
        Self(ReferenceInner::Relative(RelativeReference(
            relative.to_string(),
        )))
    }
    /// Construct a new absolute reference.
    pub fn new_absolute(absolute: &str) -> Self {
        Self(ReferenceInner::Absolute(absolute.to_string()))
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
enum ReferenceInner {
    Absolute(String),
    #[serde(skip_deserializing)]
    Relative(RelativeReference),
}

#[cfg(feature = "tokio")]
tokio::task_local! {
    #[doc(hidden)]
    pub static BASE_URL: String;
}

#[derive(Debug, Clone)]
struct RelativeReference(String);

impl Serialize for RelativeReference {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        #[cfg(feature = "tokio")]
        let absolute_url = BASE_URL
            .try_with(|base_url| format!("{}{}", base_url, self.0))
            .unwrap_or(self.0.clone());
        #[cfg(not(feature = "tokio"))]
        let absolute_url = self.0.clone();
        serializer.serialize_str(&absolute_url)
    }
}