use std::any::{Any, TypeId};
use std::borrow::Cow;
use std::collections::hash_map::{Entry, HashMap};
use std::ops::Deref;
use std::str::FromStr;
use parking_lot::Mutex;
use proc_macro2::{Ident as Ident2, TokenStream};
use quote::format_ident;
use crate::config::GeneratorFlags;
use crate::models::code::{IdentPath, ModuleIdent};
use crate::models::{
code::{Module, ModulePath},
data::{DataType, PathData},
TypeIdent,
};
use super::MetaData;
#[derive(Debug)]
pub struct Context<'a, 'types> {
pub meta: &'a MetaData<'types>,
pub data: &'a DataType<'types>,
pub ident: &'a TypeIdent,
pub values: Values,
module: Mutex<&'a mut Module>,
module_path: ModulePath,
serialize_module_path: ModulePath,
deserialize_module_path: ModulePath,
}
#[derive(Default, Debug)]
pub struct Values(HashMap<TypeId, Box<dyn Any>>);
pub trait ValueKey: Any {
type Type: Any;
}
impl<'a, 'types> Context<'a, 'types> {
pub fn resolve_type_for_module(&self, target_type: &PathData) -> TokenStream {
self.add_usings(&target_type.usings);
target_type.resolve_relative_to(&self.module_path)
}
pub fn resolve_build_in(&self, path: &str) -> IdentPath {
let path = self.patch_using(Cow::Borrowed(path));
let path = IdentPath::from_str(&path).unwrap();
if self.check_generator_flags(GeneratorFlags::BUILD_IN_ABSOLUTE_PATHS) {
path
} else {
let (ident, _path, _absolute) = path.into_parts();
IdentPath::from_ident(ident)
}
}
pub fn resolve_ident_path(&self, path: &str) -> IdentPath {
self.resolve_ident_path_impl(path, Self::add_usings)
}
pub fn add_usings<I>(&self, usings: I)
where
I: IntoIterator,
I::Item: ToString,
{
let usings = self.patch_usings(usings);
let mut root = self.module.lock();
Self::get_current_module(&self.module_path.0, &mut root).usings(false, usings);
}
pub fn add_root_usings<I>(&self, usings: I)
where
I: IntoIterator,
I::Item: ToString,
{
let usings = self.patch_usings(usings);
self.module.lock().usings(false, usings);
}
pub fn main_module(&mut self) -> &mut Module {
self.module.get_mut()
}
pub fn current_module(&mut self) -> &mut Module {
let root = self.module.get_mut();
Self::get_current_module(&self.module_path.0, root)
}
pub fn set<K>(&mut self, value: K::Type)
where
K: ValueKey,
{
self.values.set::<K>(value);
}
pub fn get<K>(&self) -> K::Type
where
K: ValueKey,
K::Type: Clone,
{
self.values.get::<K>()
}
pub fn get_ref<K>(&self) -> &K::Type
where
K: ValueKey,
{
self.values.get_ref::<K>()
}
pub fn get_mut<K>(&mut self) -> &mut K::Type
where
K: ValueKey,
{
self.values.get_mut::<K>()
}
pub fn get_or_create<K>(&mut self) -> &mut K::Type
where
K: ValueKey,
K::Type: Default,
{
self.values.get_or_create::<K>()
}
pub fn get_or_create_with<K, F>(&mut self, f: F) -> &mut K::Type
where
K: ValueKey,
F: FnOnce() -> K::Type,
{
self.values.get_or_create_with::<K, _>(f)
}
pub fn extract<K>(&mut self) -> K::Type
where
K: ValueKey,
{
self.values.extract::<K>()
}
pub fn unset<K>(&mut self)
where
K: ValueKey,
{
self.values.unset::<K>();
}
pub fn patch_usings<I>(&self, usings: I) -> impl Iterator<Item = String> + use<'_, I>
where
I: IntoIterator,
I::Item: ToString,
{
let alloc = &self.alloc_crate;
let xsd_parser_types = &self.xsd_parser_types;
usings.into_iter().map(move |s| {
Self::patch_using_impl(alloc, xsd_parser_types, Cow::Owned(s.to_string())).into_owned()
})
}
pub fn patch_using<'x>(&self, using: Cow<'x, str>) -> Cow<'x, str> {
Self::patch_using_impl(&self.alloc_crate, &self.xsd_parser_types, using)
}
pub(crate) fn resolve_root_ident_path(&self, path: &str) -> IdentPath {
self.resolve_ident_path_impl(path, Self::add_root_usings)
}
pub(crate) fn resolve_type_for_serialize_module(&self, target_type: &PathData) -> TokenStream {
self.add_quick_xml_serialize_usings(false, &target_type.usings);
target_type.resolve_relative_to(&self.serialize_module_path)
}
pub(crate) fn resolve_type_for_deserialize_module(
&self,
target_type: &PathData,
) -> TokenStream {
self.add_quick_xml_deserialize_usings(false, &target_type.usings);
target_type.resolve_relative_to(&self.deserialize_module_path)
}
pub(crate) fn quick_xml_serialize(&mut self) -> &mut Module {
self.current_module().module_mut("quick_xml_serialize")
}
pub(crate) fn quick_xml_deserialize(&mut self) -> &mut Module {
self.current_module().module_mut("quick_xml_deserialize")
}
pub(crate) fn resolve_quick_xml_serialize_ident_path(&self, path: &str) -> IdentPath {
self.resolve_ident_path_impl(path, |x, path| {
x.add_quick_xml_serialize_usings(false, path);
})
}
pub(crate) fn resolve_quick_xml_deserialize_ident_path(&self, path: &str) -> IdentPath {
self.resolve_ident_path_impl(path, |x, path| {
x.add_quick_xml_deserialize_usings(false, path);
})
}
pub(crate) fn add_quick_xml_serialize_usings<I>(&self, anonymous: bool, usings: I)
where
I: IntoIterator,
I::Item: ToString,
{
let usings = self.patch_usings(usings);
let mut root = self.module.lock();
Self::get_current_module(&self.module_path.0, &mut root)
.module_mut("quick_xml_serialize")
.usings(anonymous, usings);
}
pub(crate) fn add_quick_xml_deserialize_usings<I>(&self, anonymous: bool, usings: I)
where
I: IntoIterator,
I::Item: ToString,
{
let usings = self.patch_usings(usings);
let mut root = self.module.lock();
Self::get_current_module(&self.module_path.0, &mut root)
.module_mut("quick_xml_deserialize")
.usings(anonymous, usings);
}
pub(super) fn new(
meta: &'a MetaData<'types>,
data: &'a DataType<'types>,
ident: &'a TypeIdent,
module: &'a mut Module,
values: Values,
) -> Self {
let module_ident = ModuleIdent::new(
meta.types,
ident,
meta.check_generator_flags(GeneratorFlags::USE_NAMESPACE_MODULES),
meta.check_generator_flags(GeneratorFlags::USE_SCHEMA_MODULES),
);
let module_path = ModulePath::from_ident(meta.types.meta.types, module_ident);
let serialize_module_path = module_path
.clone()
.join(format_ident!("quick_xml_serialize"));
let deserialize_module_path = module_path
.clone()
.join(format_ident!("quick_xml_deserialize"));
Self {
meta,
data,
ident,
module: Mutex::new(module),
module_path,
serialize_module_path,
deserialize_module_path,
values,
}
}
fn get_current_module<I>(idents: I, root: &mut Module) -> &mut Module
where
I: IntoIterator,
I::Item: ToString,
{
let mut module = root;
for ident in idents {
module = module.module_mut(ident.to_string());
}
module
}
fn resolve_ident_path_impl<'x, F>(&self, path: &'x str, add_usings: F) -> IdentPath
where
F: FnOnce(&Self, [Cow<'x, str>; 1]),
{
let path = self.patch_using(Cow::Borrowed(path));
let ret = IdentPath::from_str(&path).unwrap();
if self.check_generator_flags(GeneratorFlags::ABSOLUTE_PATHS_INSTEAD_USINGS) {
ret
} else {
add_usings(self, [path]);
let (ident, _path, _absolute) = ret.into_parts();
IdentPath::from_ident(ident)
}
}
fn patch_using_impl<'x>(
alloc: &Ident2,
xsd_parser_types: &Ident2,
using: Cow<'x, str>,
) -> Cow<'x, str> {
if let Some(s) = using.strip_prefix("xsd_parser_types::") {
Cow::Owned(format!("{xsd_parser_types}::{s}"))
} else if let Some(s) = using.strip_prefix("::xsd_parser_types::") {
Cow::Owned(format!("::{xsd_parser_types}::{s}"))
} else if let Some(s) = using.strip_prefix("alloc::") {
Cow::Owned(format!("{alloc}::{s}"))
} else if let Some(s) = using.strip_prefix("::alloc::") {
Cow::Owned(format!("::{alloc}::{s}"))
} else {
using
}
}
}
impl<'types> Deref for Context<'_, 'types> {
type Target = MetaData<'types>;
fn deref(&self) -> &Self::Target {
self.meta
}
}
impl Values {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn set<K>(&mut self, value: K::Type)
where
K: ValueKey,
{
self.0.insert(TypeId::of::<K>(), Box::new(value));
}
#[must_use]
pub fn get<K>(&self) -> K::Type
where
K: ValueKey,
K::Type: Clone,
{
self.get_ref::<K>().clone()
}
#[must_use]
pub fn get_ref<K>(&self) -> &K::Type
where
K: ValueKey,
{
self.0
.get(&TypeId::of::<K>())
.unwrap()
.downcast_ref::<K::Type>()
.unwrap()
}
pub fn get_mut<K>(&mut self) -> &mut K::Type
where
K: ValueKey,
{
self.0
.get_mut(&TypeId::of::<K>())
.unwrap()
.downcast_mut::<K::Type>()
.unwrap()
}
pub fn get_or_create<K>(&mut self) -> &mut K::Type
where
K: ValueKey,
K::Type: Default,
{
self.get_or_create_with::<K, _>(Default::default)
}
pub fn get_or_create_with<K, F>(&mut self, f: F) -> &mut K::Type
where
K: ValueKey,
F: FnOnce() -> K::Type,
{
match self.0.entry(TypeId::of::<K>()) {
Entry::Vacant(e) => e.insert(Box::new(f())),
Entry::Occupied(e) => e.into_mut(),
}
.downcast_mut::<K::Type>()
.unwrap()
}
pub fn extract<K>(&mut self) -> K::Type
where
K: ValueKey,
{
*self
.0
.remove(&TypeId::of::<K>())
.unwrap()
.downcast::<K::Type>()
.unwrap()
}
pub fn unset<K>(&mut self)
where
K: ValueKey,
{
self.0.remove(&TypeId::of::<K>());
}
}