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