xsd_parser/generator/
context.rs

1use std::{
2    any::{Any, TypeId},
3    collections::HashMap,
4    ops::Deref,
5};
6
7use parking_lot::Mutex;
8use proc_macro2::{Ident as Ident2, TokenStream};
9use quote::format_ident;
10
11use crate::{
12    code::{IdentPath, Module, ModulePath},
13    schema::NamespaceId,
14    types::Ident,
15};
16
17use super::{Config, GeneratorFlags};
18
19/// Context for the rendering process.
20///
21/// This contains different additional information and configuration that may be
22/// needed by a [`Renderer`](super::Renderer) to render the actual code. It is
23/// also used to collect the rendered code and add it to the corresponding module.
24#[derive(Debug)]
25pub struct Context<'a, 'types> {
26    ident: &'a Ident,
27    config: &'a Config<'types>,
28    module: Mutex<&'a mut Module>,
29
30    module_path: ModulePath,
31    serialize_module_path: ModulePath,
32    deserialize_module_path: ModulePath,
33
34    values: HashMap<TypeId, Box<dyn Any>>,
35}
36
37pub trait ValueKey: Any {
38    type Type: Any + Clone;
39}
40
41impl<'a, 'types> Context<'a, 'types> {
42    /// Returns the namespace ID of the currently rendered type.
43    pub fn current_ns(&self) -> Option<NamespaceId> {
44        self.check_flags(GeneratorFlags::USE_MODULES)
45            .then_some(self.ident.ns)
46            .flatten()
47    }
48
49    /// Resolves the passed `ident` relative to the module of the current rendered type.
50    pub fn resolve_type_for_module(&self, ident: &IdentPath) -> TokenStream {
51        ident.relative_to(&self.module_path)
52    }
53
54    /// Add using directives to the module the of the current rendered type.
55    pub fn add_usings<I>(&self, usings: I)
56    where
57        I: IntoIterator,
58        I::Item: ToString,
59    {
60        let mut root = self.module.lock();
61        Self::main_module(self.module_path.last(), &mut root).usings(usings);
62    }
63
64    /// Returns a mutable reference to the module of the current rendered type.
65    pub fn module(&mut self) -> &mut Module {
66        let root = self.module.get_mut();
67
68        Self::main_module(self.module_path.last(), root)
69    }
70
71    /// Set a `value` for the specified key `K`.
72    pub fn set<K>(&mut self, value: K::Type)
73    where
74        K: ValueKey,
75    {
76        self.values.insert(TypeId::of::<K>(), Box::new(value));
77    }
78
79    /// Get the value that was stored for the specified key `K`.
80    ///
81    /// Panics if the key was not set before.
82    pub fn get<K>(&self) -> K::Type
83    where
84        K: ValueKey,
85    {
86        self.values
87            .get(&TypeId::of::<K>())
88            .unwrap()
89            .downcast_ref::<K::Type>()
90            .unwrap()
91            .clone()
92    }
93
94    /// Removes any values for the specified key `K`.
95    pub fn unset<K>(&mut self)
96    where
97        K: ValueKey,
98    {
99        self.values.remove(&TypeId::of::<K>());
100    }
101
102    pub(crate) fn resolve_type_for_serialize_module(&self, ident: &IdentPath) -> TokenStream {
103        ident.relative_to(&self.serialize_module_path)
104    }
105
106    pub(crate) fn resolve_type_for_deserialize_module(&self, ident: &IdentPath) -> TokenStream {
107        ident.relative_to(&self.deserialize_module_path)
108    }
109
110    pub(crate) fn quick_xml_serialize(&mut self) -> &mut Module {
111        self.module().module_mut("quick_xml_serialize")
112    }
113
114    pub(crate) fn quick_xml_deserialize(&mut self) -> &mut Module {
115        self.module().module_mut("quick_xml_deserialize")
116    }
117
118    pub(crate) fn add_quick_xml_serialize_usings<I>(&self, usings: I)
119    where
120        I: IntoIterator,
121        I::Item: ToString,
122    {
123        let mut root = self.module.lock();
124        Self::main_module(self.module_path.last(), &mut root)
125            .module_mut("quick_xml_serialize")
126            .usings(usings);
127    }
128
129    pub(crate) fn add_quick_xml_deserialize_usings<I>(&self, usings: I)
130    where
131        I: IntoIterator,
132        I::Item: ToString,
133    {
134        let mut root = self.module.lock();
135        Self::main_module(self.module_path.last(), &mut root)
136            .module_mut("quick_xml_deserialize")
137            .usings(usings);
138    }
139
140    pub(super) fn new(
141        ident: &'a Ident,
142        config: &'a Config<'types>,
143        module: &'a mut Module,
144    ) -> Self {
145        let ns = config
146            .check_flags(GeneratorFlags::USE_MODULES)
147            .then_some(ident.ns)
148            .flatten();
149        let module_path = ModulePath::from_namespace(ns, config.types);
150        let serialize_module_path = module_path
151            .clone()
152            .join(format_ident!("quick_xml_serialize"));
153        let deserialize_module_path = module_path
154            .clone()
155            .join(format_ident!("quick_xml_deserialize"));
156
157        Self {
158            ident,
159            config,
160            module: Mutex::new(module),
161
162            module_path,
163            serialize_module_path,
164            deserialize_module_path,
165
166            values: HashMap::new(),
167        }
168    }
169
170    fn main_module<'x>(ident: Option<&Ident2>, root: &'x mut Module) -> &'x mut Module {
171        if let Some(ident) = ident {
172            root.module_mut(ident.to_string())
173        } else {
174            root
175        }
176    }
177}
178
179impl<'types> Deref for Context<'_, 'types> {
180    type Target = Config<'types>;
181
182    fn deref(&self) -> &Self::Target {
183        self.config
184    }
185}