credence_lib/render/
annotations.rs

1use super::{
2    super::{configuration::*, resolve::*},
3    renderer::*,
4};
5
6use {
7    bytestring::*,
8    compris::{normal::*, parse::Parser, resolve::*, *},
9    kutil_std::{collections::*, string::*},
10};
11
12//
13// Annotations
14//
15
16/// Annotations.
17#[derive(Clone, Debug, Default, Resolve)]
18pub struct Annotations {
19    /// Created.
20    #[resolve]
21    pub created: Option<ResolveDateTime>,
22
23    /// Last updated.
24    #[resolve]
25    pub updated: Option<ResolveDateTime>,
26
27    /// Renderer.
28    #[resolve]
29    pub renderer: Option<Renderer>,
30
31    /// Template.
32    #[resolve]
33    pub template: Option<ByteString>,
34
35    /// Variables.
36    #[resolve]
37    pub variables: FastHashMap<ByteString, Value>,
38
39    /// Headers.
40    #[resolve]
41    pub headers: FastHashMap<ByteString, ByteString>,
42
43    /// Other.
44    #[resolve(other_keys)]
45    pub other: FastHashMap<ByteString, Value>,
46}
47
48impl Annotations {
49    /// Renderer.
50    pub fn renderer(&self, configuration: &RenderConfiguration) -> Renderer {
51        self.renderer.clone().unwrap_or(configuration.default_renderer)
52    }
53
54    /// Template.
55    pub fn template<'own>(&'own self, configuration: &'own RenderConfiguration) -> &'own str {
56        self.template.as_ref().unwrap_or(&configuration.default_template)
57    }
58
59    /// Parse.
60    pub fn parse(identifier: &str, representation: &str, format: Format) -> Self {
61        match Parser::new(format).with_try_unsigned_integers(true).parse_from_string(representation) {
62            Ok(annotations) => match Resolve::<_, CommonResolveContext, CommonResolveError>::resolve(&annotations) {
63                Ok(annotations) => {
64                    if let Some(annotations) = annotations {
65                        return annotations;
66                    }
67                }
68
69                Err(error) => tracing::error!("{}: {}", identifier, error),
70            },
71
72            Err(error) => tracing::error!("{}: {}", identifier, error),
73        }
74
75        Self::default()
76    }
77
78    /// Traverse variable.
79    pub fn traverse_variable(&self, keys: &RefValuePath<'_>) -> Option<&Value> {
80        if !keys.is_empty() {
81            if let Value::Text(first_key) = &keys[0] {
82                if let Some(first_value) = self.variables.get(&first_key.value) {
83                    let keys = keys[1..].iter().map(|value| *value);
84                    return first_value.traverse(keys);
85                }
86            }
87        }
88
89        None
90    }
91}
92
93impl AnnotationsConfiguration {
94    /// Split [Annotations] from content.
95    pub fn split<'content>(&self, identifier: &str, content: &'content str) -> (Annotations, &'content str) {
96        let start_delimiter: &str = &self.start_delimiter;
97        if content.starts_with(start_delimiter) {
98            let end_delimiter: &str = &self.end_delimiter;
99            if let Some((properties, content)) =
100                content[start_delimiter.len()..].split_once_ignore_escaped(end_delimiter)
101            {
102                // Unescape end delimiter
103                let annotations = properties.unescape(end_delimiter);
104                let mut annotations = annotations.as_str();
105
106                let format = {
107                    // The format can be right after the start delimiter with a newline
108                    match annotations.split_once('\n') {
109                        Some((format, annotations_after_format)) => {
110                            let format_result = format.parse();
111                            annotations = annotations_after_format;
112                            format_result.unwrap_or(self.default_format.value.into())
113                        }
114
115                        None => self.default_format.value.into(),
116                    }
117                };
118
119                let annotations = Annotations::parse(identifier, annotations, format);
120                return (annotations, content);
121            }
122        }
123
124        (Annotations::default(), content)
125    }
126}