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    /// URI query.
43    pub query: Option<QueryMap>,
44
45    /// Last modified.
46    pub last_modified: Option<HttpDate>,
47
48    /// Is JSON? And if so, is it pretty JSON?
49    pub is_json: (bool, bool),
50
51    /// Renderer
52    pub renderer: Renderer,
53
54    /// Templates.
55    pub templates: &'own Templates,
56
57    /// Configuration.
58    pub configuration: &'own CredenceConfiguration,
59}
60
61impl<'own> RenderContext<'own> {
62    /// Constructor.
63    pub fn new(
64        rendered_page: &'own RenderedPage,
65        variables: FastHashMap<ByteString, Value>,
66        socket: Option<Socket>,
67        uri_path: ByteString,
68        original_uri_path: Option<ByteString>,
69        query: Option<QueryMap>,
70        last_modified: Option<HttpDate>,
71        is_json: (bool, bool),
72        renderer: Renderer,
73        templates: &'own Templates,
74        configuration: &'own CredenceConfiguration,
75    ) -> Self {
76        Self {
77            rendered_page,
78            variables,
79            socket,
80            uri_path,
81            original_uri_path,
82            query,
83            last_modified,
84            is_json,
85            renderer,
86            templates,
87            configuration,
88        }
89    }
90
91    /// Prepare using [DefaultRenderedPageHandler].
92    pub async fn prepare<PreparerT>(&mut self, preparer: PreparerT) -> Result<(), StatusCode>
93    where
94        PreparerT: RenderPreparer,
95    {
96        preparer.prepare(self).await
97    }
98
99    /// Prepare using [DefaultRenderedPageHandler].
100    pub async fn prepare_default(&mut self) -> Result<(), StatusCode> {
101        self.prepare(DefaultRenderedPageHandler).await
102    }
103
104    /// Into response.
105    pub async fn into_response(self) -> Result<Response, StatusCode> {
106        let template = self.rendered_page.annotations.template(&self.configuration.render);
107        let html = self.templates.render(template, &self.variables).await?;
108        let mut headers = self.rendered_page.merged_headers()?;
109
110        if let Some(last_modified) = &self.last_modified {
111            headers
112                .set_string_value(LAST_MODIFIED, &last_modified.to_string())
113                .map_err_internal_server("set Last-Modified")?;
114        }
115
116        if self.is_json.0 {
117            let json = self.into_json()?;
118            response_from_bytes(json.into_bytes(), JSON_MEDIA_TYPE_STRING, headers)
119        } else {
120            response_from_bytes(html.into_bytes(), HTML_MEDIA_TYPE_STRING, headers)
121        }
122    }
123
124    fn into_json(self) -> Result<ByteString, StatusCode> {
125        Serializer::new(Format::JSON)
126            .with_pretty(self.is_json.1)
127            .stringify_modal(&self.variables_into_value(), &SerializationMode::for_json())
128            .map_err_internal_server("serialize JSON")
129    }
130
131    fn variables_into_value(self) -> Value {
132        self.variables.into_iter().map(|(key, value)| (key.into(), value.clone())).collect()
133    }
134}