credence_lib/render/
context.rs

1use super::{
2    super::{configuration::*, middleware::*},
3    constants::*,
4    default_preparer::*,
5    preparer::*,
6    rendered_page::*,
7    renderer::*,
8    templates::*,
9};
10
11use {
12    ::axum::{
13        http::{header::*, *},
14        response::Response,
15    },
16    compris::{annotate::*, normal::*, ser::*, *},
17    httpdate::*,
18    kutil::{
19        http::*,
20        std::{collections::*, immutable::*},
21    },
22    std::result::Result,
23};
24
25/// Render context.
26#[derive(Debug)]
27pub struct RenderContext<'own> {
28    /// Rendered page.
29    pub rendered_page: &'own RenderedPage,
30
31    /// Variables.
32    pub variables: FastHashMap<ByteString, Variant<WithAnnotations>>,
33
34    /// Socket.
35    pub socket: Option<Socket>,
36
37    /// URI path.
38    pub uri_path: ByteString,
39
40    /// Original URI path.
41    pub original_uri_path: Option<ByteString>,
42
43    /// URI query.
44    pub query: Option<QueryMap>,
45
46    /// Last modified.
47    pub last_modified: Option<HttpDate>,
48
49    /// Is JSON? And if so, is it pretty JSON?
50    pub is_json: (bool, bool),
51
52    /// Renderer
53    pub renderer: Renderer,
54
55    /// Templates.
56    pub templates: &'own Templates,
57
58    /// Configuration.
59    pub configuration: &'own CredenceConfiguration,
60}
61
62impl<'own> RenderContext<'own> {
63    /// Constructor.
64    pub fn new(
65        rendered_page: &'own RenderedPage,
66        variables: FastHashMap<ByteString, Variant<WithAnnotations>>,
67        socket: Option<Socket>,
68        uri_path: ByteString,
69        original_uri_path: Option<ByteString>,
70        query: Option<QueryMap>,
71        last_modified: Option<HttpDate>,
72        is_json: (bool, bool),
73        renderer: Renderer,
74        templates: &'own Templates,
75        configuration: &'own CredenceConfiguration,
76    ) -> Self {
77        Self {
78            rendered_page,
79            variables,
80            socket,
81            uri_path,
82            original_uri_path,
83            query,
84            last_modified,
85            is_json,
86            renderer,
87            templates,
88            configuration,
89        }
90    }
91
92    /// Prepare using [DefaultRenderedPageHandler].
93    pub async fn prepare<PreparerT>(&mut self, preparer: PreparerT) -> Result<(), StatusCode>
94    where
95        PreparerT: RenderPreparer,
96    {
97        preparer.prepare(self).await
98    }
99
100    /// Prepare using [DefaultRenderedPageHandler].
101    pub async fn prepare_default(&mut self) -> Result<(), StatusCode> {
102        self.prepare(DefaultRenderedPageHandler).await
103    }
104
105    /// Into response.
106    pub async fn into_response(self) -> Result<Response, StatusCode> {
107        let template = self.rendered_page.annotations.template(&self.configuration.render);
108        let html = self.templates.render(template, &self.variables).await?;
109        let mut headers = self.rendered_page.merged_headers()?;
110
111        if let Some(last_modified) = &self.last_modified {
112            headers
113                .set_string_value(LAST_MODIFIED, &last_modified.to_string())
114                .map_err_internal_server("set Last-Modified")?;
115        }
116
117        if self.is_json.0 {
118            let json = self.into_json()?;
119            response_from_bytes(json.into_bytes(), JSON_MEDIA_TYPE_STRING, headers)
120        } else {
121            response_from_bytes(html.into_bytes(), HTML_MEDIA_TYPE_STRING, headers)
122        }
123    }
124
125    fn into_json(self) -> Result<ByteString, StatusCode> {
126        Serializer::new(Format::JSON)
127            .with_pretty(self.is_json.1)
128            .stringify_modal(&self.variables_into_variant(), &SerializationMode::for_json())
129            .map_err_internal_server("serialize JSON")
130    }
131
132    fn variables_into_variant(self) -> Variant<WithAnnotations> {
133        self.variables.into_iter().map(|(key, value)| (key.into(), value.clone())).collect()
134    }
135}