use std::mem::take;
use std::ops::Deref;
use proc_macro2::{Ident as Ident2, Literal, TokenStream};
use quote::{format_ident, quote};
use crate::{
code::{format_field_ident, format_variant_ident, IdentPath, ModulePath},
schema::{xs::Use, MaxOccurs, MinOccurs, NamespaceId},
types::{
AnyAttributeInfo, AnyInfo, AttributeInfo, BuildInInfo, ComplexInfo, DynamicInfo,
ElementInfo, EnumerationInfo, GroupInfo, Ident, ReferenceInfo, Type, TypeVariant, Types,
UnionInfo, UnionTypeInfo, VariantInfo,
},
};
use super::{
misc::Occurs, BoxFlags, Config, Error, GeneratorFlags, State, TraitInfos, TypeRef, TypedefMode,
};
#[derive(Debug)]
pub enum TypeData<'types> {
BuildIn(BuildInType<'types>),
Union(UnionType<'types>),
Dynamic(DynamicType<'types>),
Reference(ReferenceType<'types>),
Enumeration(EnumerationType<'types>),
Complex(ComplexType<'types>),
}
impl<'types> TypeData<'types> {
pub(super) fn new(
ty: &'types Type,
ident: &Ident,
config: &Config<'types>,
state: &mut State<'types>,
) -> Result<Self, Error> {
let req = Request::new(ident, config, state);
Ok(match &ty.variant {
TypeVariant::BuildIn(x) => Self::BuildIn(BuildInType::new(x)),
TypeVariant::Union(x) => Self::Union(UnionType::new(x, req)?),
TypeVariant::Dynamic(x) => Self::Dynamic(DynamicType::new(x, req)?),
TypeVariant::Reference(x) => Self::Reference(ReferenceType::new(x, req)?),
TypeVariant::Enumeration(x) => Self::Enumeration(EnumerationType::new(x, req)?),
TypeVariant::All(x) => Self::Complex(ComplexType::new_all(x, req)?),
TypeVariant::Choice(x) => Self::Complex(ComplexType::new_choice(x, req)?),
TypeVariant::Sequence(x) => Self::Complex(ComplexType::new_sequence(x, req)?),
TypeVariant::ComplexType(x) => Self::Complex(ComplexType::new_complex(x, req)?),
})
}
}
#[derive(Debug)]
pub struct BuildInType<'types> {
pub info: &'types BuildInInfo,
}
impl<'types> BuildInType<'types> {
fn new(info: &'types BuildInInfo) -> Self {
Self { info }
}
}
#[derive(Debug)]
pub struct UnionType<'types> {
pub info: &'types UnionInfo,
pub type_ident: Ident2,
pub variants: Vec<UnionTypeVariant<'types>>,
pub trait_impls: Vec<TokenStream>,
}
#[derive(Debug)]
pub struct UnionTypeVariant<'types> {
pub info: &'types UnionTypeInfo,
pub target_type: IdentPath,
pub variant_ident: Ident2,
}
impl<'types> UnionType<'types> {
fn new(info: &'types UnionInfo, mut req: Request<'_, 'types>) -> Result<Self, Error> {
let type_ident = req.current_type_ref().type_ident.clone();
let trait_impls = req.make_trait_impls()?;
let variants = info
.types
.iter()
.map(|info| info.make_variant(&mut req))
.collect::<Result<_, _>>()?;
Ok(Self {
info,
type_ident,
variants,
trait_impls,
})
}
}
impl UnionTypeInfo {
fn make_variant<'types>(
&'types self,
req: &mut Request<'_, 'types>,
) -> Result<UnionTypeVariant<'types>, Error> {
let type_ref = req.get_or_create_type_ref(self.type_.clone())?;
let target_type = type_ref.to_ident_path();
let variant_ident = format_variant_ident(&self.type_.name, self.display_name.as_deref());
Ok(UnionTypeVariant {
info: self,
target_type,
variant_ident,
})
}
}
#[derive(Debug)]
pub struct DynamicType<'types> {
pub info: &'types DynamicInfo,
pub type_ident: Ident2,
pub trait_ident: Ident2,
pub deserializer_ident: Ident2,
pub sub_traits: Option<Vec<IdentPath>>,
pub derived_types: Vec<DerivedType>,
}
#[derive(Debug)]
pub struct DerivedType {
pub ident: Ident,
pub b_name: Literal,
pub target_type: IdentPath,
pub variant_ident: Ident2,
}
impl<'types> DynamicType<'types> {
fn new(info: &'types DynamicInfo, mut req: Request<'_, 'types>) -> Result<Self, Error> {
let type_ident = req.current_type_ref().type_ident.clone();
let trait_ident = format_ident!("{type_ident}Trait");
let ident = req.ident.clone();
let sub_traits = req
.get_trait_infos()
.get(&ident)
.map(|info| info.traits_direct.clone())
.map(|traits_direct| {
traits_direct
.iter()
.map(|ident| {
req.get_or_create_type_ref(ident.clone()).map(|x| {
let ident = format_ident!("{}Trait", x.type_ident);
x.to_ident_path().with_ident(ident)
})
})
.collect::<Result<Vec<_>, _>>()
})
.transpose()?;
let derived_types = info
.derived_types
.iter()
.map(|ident| make_derived_type_data(&mut req, ident))
.collect::<Result<Vec<_>, _>>()?;
let deserializer_ident = format_ident!("{type_ident}Deserializer");
Ok(Self {
info,
type_ident,
trait_ident,
deserializer_ident,
sub_traits,
derived_types,
})
}
}
#[derive(Debug)]
pub struct ReferenceType<'types> {
pub info: &'types ReferenceInfo,
pub mode: TypedefMode,
pub occurs: Occurs,
pub type_ident: Ident2,
pub target_type: IdentPath,
pub trait_impls: Vec<TokenStream>,
}
impl<'types> ReferenceType<'types> {
fn new(info: &'types ReferenceInfo, mut req: Request<'_, 'types>) -> Result<Self, Error> {
let occurs = Occurs::from_occurs(info.min_occurs, info.max_occurs);
let type_ident = req.current_type_ref().type_ident.clone();
let target_ref = req.get_or_create_type_ref(info.type_.clone())?;
let target_type = target_ref.to_ident_path();
let trait_impls = req.make_trait_impls()?;
let mode = match (req.typedef_mode, occurs) {
(TypedefMode::Auto, Occurs::None | Occurs::Single) => TypedefMode::Typedef,
(TypedefMode::Auto, _) => TypedefMode::NewType,
(mode, _) => mode,
};
Ok(Self {
info,
mode,
occurs,
type_ident,
target_type,
trait_impls,
})
}
}
#[derive(Debug)]
pub struct EnumerationType<'types> {
pub info: &'types EnumerationInfo,
pub type_ident: Ident2,
pub variants: Vec<EnumerationTypeVariant<'types>>,
pub trait_impls: Vec<TokenStream>,
}
#[derive(Debug)]
pub struct EnumerationTypeVariant<'types> {
pub info: &'types VariantInfo,
pub variant_ident: Ident2,
pub target_type: Option<IdentPath>,
}
impl<'types> EnumerationType<'types> {
fn new(info: &'types EnumerationInfo, mut req: Request<'_, 'types>) -> Result<Self, Error> {
let mut unknown = 0usize;
let type_ident = req.current_type_ref().type_ident.clone();
let trait_impls = req.make_trait_impls()?;
let variants = info
.variants
.iter()
.filter_map(|var| var.make_variant(&mut unknown, &mut req))
.collect::<Result<Vec<_>, _>>()?;
Ok(EnumerationType {
info,
type_ident,
variants,
trait_impls,
})
}
}
impl VariantInfo {
fn make_variant<'types>(
&'types self,
unknown: &mut usize,
req: &mut Request<'_, 'types>,
) -> Option<Result<EnumerationTypeVariant<'types>, Error>> {
match self.use_ {
Use::Prohibited => None,
Use::Required | Use::Optional => {
let type_ref = if let Some(t) = &self.type_ {
match req.get_or_create_type_ref(t.clone()) {
Ok(target_ref) => Some(target_ref),
Err(error) => return Some(Err(error)),
}
} else {
None
};
let variant_ident = if let Some(display_name) = self.display_name.as_deref() {
format_ident!("{display_name}")
} else if let (Some(type_ref), true) = (type_ref, self.ident.name.is_generated()) {
type_ref.type_ident.clone()
} else if self.ident.name.as_str().is_empty() {
*unknown += 1;
format_ident!("Unknown{unknown}")
} else {
format_variant_ident(&self.ident.name, self.display_name.as_deref())
};
let target_type = type_ref.map(TypeRef::to_ident_path);
Some(Ok(EnumerationTypeVariant {
info: self,
variant_ident,
target_type,
}))
}
}
}
}
#[derive(Debug)]
pub enum ComplexType<'types> {
Enum {
type_: ComplexTypeEnum<'types>,
content_type: Option<Box<ComplexType<'types>>>,
},
Struct {
type_: ComplexTypeStruct<'types>,
content_type: Option<Box<ComplexType<'types>>>,
},
}
#[derive(Debug)]
pub struct ComplexTypeBase {
pub type_ident: Ident2,
pub trait_impls: Vec<TokenStream>,
pub tag_name: Option<String>,
pub is_complex: bool,
pub is_dynamic: bool,
pub serializer_ident: Ident2,
pub serializer_state_ident: Ident2,
pub deserializer_ident: Ident2,
pub deserializer_state_ident: Ident2,
}
#[derive(Debug)]
pub struct ComplexTypeEnum<'types> {
pub base: ComplexTypeBase,
pub elements: Vec<ComplexTypeElement<'types>>,
pub any_element: Option<&'types AnyInfo>,
pub any_attribute: Option<&'types AnyAttributeInfo>,
}
#[derive(Debug)]
pub struct ComplexTypeStruct<'types> {
pub base: ComplexTypeBase,
pub mode: StructMode<'types>,
pub attributes: Vec<ComplexTypeAttribute<'types>>,
pub any_attribute: Option<&'types AnyAttributeInfo>,
}
#[derive(Debug)]
pub enum StructMode<'types> {
Empty {
any_element: Option<&'types AnyInfo>,
},
Content {
content: ComplexTypeContent,
},
All {
elements: Vec<ComplexTypeElement<'types>>,
any_element: Option<&'types AnyInfo>,
},
Sequence {
elements: Vec<ComplexTypeElement<'types>>,
any_element: Option<&'types AnyInfo>,
},
}
#[derive(Debug)]
pub struct ComplexTypeContent {
pub occurs: Occurs,
pub is_simple: bool,
pub min_occurs: MinOccurs,
pub max_occurs: MaxOccurs,
pub target_type: IdentPath,
}
#[derive(Debug)]
pub struct ComplexTypeElement<'types> {
pub info: &'types ElementInfo,
pub occurs: Occurs,
pub s_name: String,
pub b_name: Literal,
pub tag_name: String,
pub field_ident: Ident2,
pub variant_ident: Ident2,
pub target_type: IdentPath,
pub need_indirection: bool,
pub target_is_dynamic: bool,
}
#[derive(Debug)]
pub struct ComplexTypeAttribute<'types> {
pub info: &'types AttributeInfo,
pub ident: Ident2,
pub s_name: String,
pub b_name: Literal,
pub tag_name: String,
pub is_option: bool,
pub target_type: IdentPath,
pub default_value: Option<TokenStream>,
}
#[derive(Debug, Clone)]
enum TypeMode {
All,
Choice,
Sequence,
Simple { target_type: IdentPath },
}
impl<'types> ComplexType<'types> {
fn new_all(info: &'types GroupInfo, req: Request<'_, 'types>) -> Result<Self, Error> {
Self::new(
req,
TypeMode::All,
1,
MaxOccurs::Bounded(1),
&[],
None,
&info.elements,
info.any.as_ref(),
)
}
fn new_choice(info: &'types GroupInfo, req: Request<'_, 'types>) -> Result<Self, Error> {
Self::new(
req,
TypeMode::Choice,
1,
MaxOccurs::Bounded(1),
&[],
None,
&info.elements,
info.any.as_ref(),
)
}
fn new_sequence(info: &'types GroupInfo, req: Request<'_, 'types>) -> Result<Self, Error> {
Self::new(
req,
TypeMode::Sequence,
1,
MaxOccurs::Bounded(1),
&[],
None,
&info.elements,
info.any.as_ref(),
)
}
fn new_complex(info: &'types ComplexInfo, mut req: Request<'_, 'types>) -> Result<Self, Error> {
let (type_mode, elements, any_element) = match info.content.as_ref().and_then(|ident| {
req.types
.get_resolved_type(ident)
.map(|ty| (&ty.variant, ident))
}) {
None => (TypeMode::Sequence, &[][..], None),
Some((TypeVariant::All(si), _)) => (TypeMode::All, &si.elements[..], si.any.as_ref()),
Some((TypeVariant::Choice(si), _)) => {
(TypeMode::Choice, &si.elements[..], si.any.as_ref())
}
Some((TypeVariant::Sequence(si), _)) => {
(TypeMode::Sequence, &si.elements[..], si.any.as_ref())
}
Some((
TypeVariant::BuildIn(_)
| TypeVariant::Union(_)
| TypeVariant::Enumeration(_)
| TypeVariant::Reference(_),
ident,
)) => {
let content_ref = req.get_or_create_type_ref(ident.clone())?;
let target_type = content_ref.to_ident_path();
(TypeMode::Simple { target_type }, &[][..], None)
}
Some((x, _)) => {
let ident = &req.current_type_ref().type_ident;
tracing::warn!("Complex type has unexpected content: ident={ident}, info={info:#?}, content={x:#?}!");
(TypeMode::Sequence, &[][..], None)
}
};
Self::new(
req,
type_mode,
info.min_occurs,
info.max_occurs,
&info.attributes,
info.any_attribute.as_ref(),
elements,
any_element,
)
}
#[allow(clippy::too_many_arguments)]
fn new(
req: Request<'_, 'types>,
type_mode: TypeMode,
min_occurs: MinOccurs,
max_occurs: MaxOccurs,
attributes: &'types [AttributeInfo],
any_attribute: Option<&'types AnyAttributeInfo>,
elements: &'types [ElementInfo],
any_element: Option<&'types AnyInfo>,
) -> Result<Self, Error> {
match type_mode {
TypeMode::Simple { target_type } => Self::new_simple(
req,
target_type,
min_occurs,
max_occurs,
attributes,
any_attribute,
),
TypeMode::Choice => Self::new_enum(
req,
min_occurs,
max_occurs,
attributes,
any_attribute,
elements,
any_element,
),
TypeMode::All | TypeMode::Sequence => Self::new_struct(
req,
&type_mode,
min_occurs,
max_occurs,
attributes,
any_attribute,
elements,
any_element,
),
}
}
fn new_simple(
mut req: Request<'_, 'types>,
target_type: IdentPath,
min_occurs: MinOccurs,
max_occurs: MaxOccurs,
attributes: &'types [AttributeInfo],
any_attribute: Option<&'types AnyAttributeInfo>,
) -> Result<Self, Error> {
let base = ComplexTypeBase::new(&mut req)?;
let occurs = Occurs::from_occurs(min_occurs, max_occurs);
let attributes = attributes
.iter()
.filter_map(|info| ComplexTypeAttribute::new_field(info, &mut req).transpose())
.collect::<Result<Vec<_>, _>>()?;
let content = ComplexTypeContent {
occurs,
is_simple: true,
min_occurs,
max_occurs,
target_type,
};
let type_ = ComplexTypeStruct {
base,
mode: StructMode::Content { content },
attributes,
any_attribute,
};
Ok(Self::Struct {
type_,
content_type: None,
})
}
fn new_enum(
mut req: Request<'_, 'types>,
min_occurs: MinOccurs,
max_occurs: MaxOccurs,
attributes: &'types [AttributeInfo],
any_attribute: Option<&'types AnyAttributeInfo>,
elements: &'types [ElementInfo],
any_element: Option<&'types AnyInfo>,
) -> Result<Self, Error> {
let base = ComplexTypeBase::new(&mut req)?;
let occurs = Occurs::from_occurs(min_occurs, max_occurs);
let flatten = occurs == Occurs::Single
&& attributes.is_empty()
&& req.check_flags(GeneratorFlags::FLATTEN_ENUM_CONTENT);
let attributes = attributes
.iter()
.filter_map(|info| ComplexTypeAttribute::new_field(info, &mut req).transpose())
.collect::<Result<Vec<_>, _>>()?;
let mut any_element = any_element;
let mut elements = elements
.iter()
.filter_map(|info| {
ComplexTypeElement::new_variant(info, &mut req, occurs.is_direct()).transpose()
})
.collect::<Result<Vec<_>, _>>()?;
if flatten {
let type_ = ComplexTypeEnum {
base,
elements,
any_element,
any_attribute,
};
return Ok(ComplexType::Enum {
type_,
content_type: None,
});
}
let type_ident = &base.type_ident;
let content_ident = format_ident!("{type_ident}Content");
let has_content = occurs.is_some() && !elements.is_empty();
let content_type = has_content.then(|| {
let type_ = ComplexTypeEnum {
base: ComplexTypeBase::new_empty(content_ident.clone()),
elements: take(&mut elements),
any_element: any_element.take(),
any_attribute: None,
};
Box::new(ComplexType::Enum {
type_,
content_type: None,
})
});
let mode = if has_content {
let type_ref = req.current_type_ref();
let target_type = type_ref.to_ident_path().with_ident(content_ident.clone());
let content = ComplexTypeContent {
occurs,
is_simple: false,
min_occurs,
max_occurs,
target_type,
};
StructMode::Content { content }
} else {
StructMode::Empty { any_element }
};
let type_ = ComplexTypeStruct {
base,
mode,
attributes,
any_attribute,
};
Ok(ComplexType::Struct {
type_,
content_type,
})
}
#[allow(clippy::too_many_arguments)]
fn new_struct(
mut req: Request<'_, 'types>,
type_mode: &TypeMode,
min_occurs: MinOccurs,
max_occurs: MaxOccurs,
attributes: &'types [AttributeInfo],
any_attribute: Option<&'types AnyAttributeInfo>,
elements: &'types [ElementInfo],
any_element: Option<&'types AnyInfo>,
) -> Result<Self, Error> {
let base = ComplexTypeBase::new(&mut req)?;
let occurs = Occurs::from_occurs(min_occurs, max_occurs);
let flatten =
occurs == Occurs::Single && req.check_flags(GeneratorFlags::FLATTEN_STRUCT_CONTENT);
let attributes = attributes
.iter()
.filter_map(|info| ComplexTypeAttribute::new_field(info, &mut req).transpose())
.collect::<Result<Vec<_>, _>>()?;
let elements = elements
.iter()
.filter_map(|info| {
ComplexTypeElement::new_field(info, &mut req, occurs.is_direct()).transpose()
})
.collect::<Result<Vec<_>, _>>()?;
if flatten {
let mode = match type_mode {
_ if elements.is_empty() => StructMode::Empty { any_element },
TypeMode::All => StructMode::All {
elements,
any_element,
},
TypeMode::Sequence => StructMode::Sequence {
elements,
any_element,
},
_ => crate::unreachable!(),
};
let type_ = ComplexTypeStruct {
base,
mode,
attributes,
any_attribute,
};
return Ok(ComplexType::Struct {
type_,
content_type: None,
});
}
let type_ident = &base.type_ident;
let content_ident = format_ident!("{type_ident}Content");
let has_content = occurs.is_some() && !elements.is_empty();
let content_type = has_content.then(|| {
let mode = match type_mode {
TypeMode::All => StructMode::All {
elements,
any_element,
},
TypeMode::Sequence => StructMode::Sequence {
elements,
any_element,
},
_ => crate::unreachable!(),
};
let type_ = ComplexTypeStruct {
base: ComplexTypeBase::new_empty(content_ident.clone()),
mode,
attributes: Vec::new(),
any_attribute: None,
};
Box::new(ComplexType::Struct {
type_,
content_type: None,
})
});
let mode = if has_content {
let type_ref = req.current_type_ref();
let target_type = type_ref.to_ident_path().with_ident(content_ident.clone());
let content = ComplexTypeContent {
occurs,
is_simple: false,
min_occurs,
max_occurs,
target_type,
};
StructMode::Content { content }
} else {
StructMode::Empty { any_element }
};
let type_ = ComplexTypeStruct {
base,
mode,
attributes,
any_attribute,
};
Ok(ComplexType::Struct {
type_,
content_type,
})
}
}
impl ComplexTypeBase {
pub(super) fn element_tag(&self) -> Option<&String> {
self.is_complex.then_some(self.tag_name.as_ref()).flatten()
}
pub(crate) fn represents_element(&self) -> bool {
self.is_complex && self.tag_name.is_some() && !self.is_dynamic
}
fn new(req: &mut Request<'_, '_>) -> Result<Self, Error> {
let type_ref = req.current_type_ref();
let type_ident = type_ref.type_ident.clone();
let mut ret = Self::new_empty(type_ident);
ret.tag_name = Some(make_tag_name(req.types, req.ident));
ret.trait_impls = req.make_trait_impls()?;
if let Some(TypeVariant::ComplexType(ci)) = req.types.get_variant(req.ident) {
ret.is_complex = true;
ret.is_dynamic = ci.is_dynamic;
}
Ok(ret)
}
fn new_empty(type_ident: Ident2) -> Self {
let serializer_ident = format_ident!("{type_ident}Serializer");
let serializer_state_ident = format_ident!("{type_ident}SerializerState");
let deserializer_ident = format_ident!("{type_ident}Deserializer");
let deserializer_state_ident = format_ident!("{type_ident}DeserializerState");
Self {
type_ident,
trait_impls: Vec::new(),
tag_name: None,
is_complex: false,
is_dynamic: false,
serializer_ident,
serializer_state_ident,
deserializer_ident,
deserializer_state_ident,
}
}
}
impl Deref for ComplexTypeEnum<'_> {
type Target = ComplexTypeBase;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl ComplexTypeStruct<'_> {
pub(super) fn is_unit_struct(&self) -> bool {
matches!(&self.mode, StructMode::Empty { .. }) && !self.has_attributes()
}
pub(super) fn has_attributes(&self) -> bool {
!self.attributes.is_empty()
}
pub(super) fn has_content(&self) -> bool {
match &self.mode {
StructMode::All { elements, .. } | StructMode::Sequence { elements, .. } => {
!elements.is_empty()
}
StructMode::Content { .. } => true,
StructMode::Empty { .. } => false,
}
}
pub(super) fn elements(&self) -> &[ComplexTypeElement<'_>] {
if let StructMode::All { elements, .. } | StructMode::Sequence { elements, .. } = &self.mode
{
elements
} else {
&[]
}
}
pub(super) fn any_element(&self) -> Option<&AnyInfo> {
if let StructMode::All { any_element, .. } | StructMode::Sequence { any_element, .. } =
&self.mode
{
*any_element
} else {
None
}
}
pub(super) fn content(&self) -> Option<&ComplexTypeContent> {
if let StructMode::Content { content, .. } = &self.mode {
Some(content)
} else {
None
}
}
}
impl Deref for ComplexTypeStruct<'_> {
type Target = ComplexTypeBase;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl<'types> ComplexTypeElement<'types> {
fn new_variant(
info: &'types ElementInfo,
req: &mut Request<'_, 'types>,
direct_usage: bool,
) -> Result<Option<Self>, Error> {
let force_box = req.box_flags.intersects(BoxFlags::ENUM_ELEMENTS);
Self::new(info, req, direct_usage, force_box)
}
fn new_field(
info: &'types ElementInfo,
req: &mut Request<'_, 'types>,
direct_usage: bool,
) -> Result<Option<Self>, Error> {
let force_box = req.box_flags.intersects(BoxFlags::STRUCT_ELEMENTS);
Self::new(info, req, direct_usage, force_box)
}
fn new(
info: &'types ElementInfo,
req: &mut Request<'_, 'types>,
direct_usage: bool,
force_box: bool,
) -> Result<Option<Self>, Error> {
let occurs = Occurs::from_occurs(info.min_occurs, info.max_occurs);
if occurs == Occurs::None {
return Ok(None);
}
let tag_name = make_tag_name(req.types, &info.ident);
let s_name = info.ident.name.to_string();
let b_name = Literal::byte_string(s_name.as_bytes());
let field_ident = format_field_ident(&info.ident.name, info.display_name.as_deref());
let variant_ident = format_variant_ident(&info.ident.name, info.display_name.as_deref());
let target_ref = req.get_or_create_type_ref(info.type_.clone())?;
let target_type = target_ref.to_ident_path();
let need_box = req.current_type_ref().boxed_elements.contains(&info.ident);
let need_indirection = (direct_usage && need_box) || force_box;
let target_is_dynamic = is_dynamic(&info.type_, req.types);
Ok(Some(Self {
info,
occurs,
s_name,
b_name,
tag_name,
field_ident,
variant_ident,
target_type,
need_indirection,
target_is_dynamic,
}))
}
}
impl<'types> ComplexTypeAttribute<'types> {
fn new_field(
info: &'types AttributeInfo,
req: &mut Request<'_, 'types>,
) -> Result<Option<Self>, Error> {
if info.use_ == Use::Prohibited {
return Ok(None);
}
let current_module = req.current_module();
let target_ref = req.get_or_create_type_ref(info.type_.clone())?;
let ident = format_field_ident(&info.ident.name, info.display_name.as_deref());
let target_type = target_ref.to_ident_path();
let s_name = info.ident.name.to_string();
let b_name = Literal::byte_string(s_name.as_bytes());
let tag_name = make_tag_name(req.types, &info.ident);
let default_value = info
.default
.as_ref()
.map(|default| req.get_default(current_module, default, &info.type_))
.transpose()?;
let is_option = matches!((&info.use_, &default_value), (Use::Optional, None));
Ok(Some(Self {
info,
ident,
s_name,
b_name,
tag_name,
is_option,
target_type,
default_value,
}))
}
}
struct Request<'a, 'types> {
pub ident: &'a Ident,
pub config: &'a Config<'types>,
state: &'a mut State<'types>,
}
impl<'a, 'types> Request<'a, 'types> {
fn new(ident: &'a Ident, config: &'a Config<'types>, state: &'a mut State<'types>) -> Self {
Self {
ident,
config,
state,
}
}
fn current_module(&self) -> Option<NamespaceId> {
self.check_flags(GeneratorFlags::USE_MODULES)
.then_some(self.ident.ns)
.flatten()
}
fn current_type_ref(&self) -> &TypeRef {
self.state.cache.get(self.ident).unwrap()
}
fn get_trait_infos(&mut self) -> &TraitInfos {
self.state
.trait_infos
.get_or_insert_with(|| TraitInfos::new(self.config.types))
}
fn get_or_create_type_ref(&mut self, ident: Ident) -> Result<&TypeRef, Error> {
self.state.get_or_create_type_ref(self.config, ident)
}
fn make_trait_impls(&mut self) -> Result<Vec<TokenStream>, Error> {
let ident = self.ident.clone();
let current_ns = self.current_module();
let module_path = ModulePath::from_namespace(current_ns, self.types);
self.get_trait_infos()
.get(&ident)
.into_iter()
.flat_map(|info| &info.traits_all)
.cloned()
.collect::<Vec<_>>()
.into_iter()
.map(|ident| {
let type_ref = self.get_or_create_type_ref(ident.clone())?;
let ident = format_ident!("{}Trait", type_ref.type_ident);
let trait_type = type_ref.to_ident_path().with_ident(ident);
let trait_ident = trait_type.relative_to(&module_path);
Ok(trait_ident)
})
.collect::<Result<Vec<_>, _>>()
}
fn get_default(
&mut self,
current_ns: Option<NamespaceId>,
default: &str,
ident: &Ident,
) -> Result<TokenStream, Error> {
let types = self.types;
let ty = types
.get(ident)
.ok_or_else(|| Error::UnknownType(ident.clone()))?;
let type_ref = self.get_or_create_type_ref(ident.clone())?;
macro_rules! build_in {
($ty:ty) => {
if let Ok(val) = default.parse::<$ty>() {
return Ok(quote!(#val));
}
};
}
match &ty.variant {
TypeVariant::BuildIn(BuildInInfo::U8) => build_in!(u8),
TypeVariant::BuildIn(BuildInInfo::U16) => build_in!(u16),
TypeVariant::BuildIn(BuildInInfo::U32) => build_in!(u32),
TypeVariant::BuildIn(BuildInInfo::U64) => build_in!(u64),
TypeVariant::BuildIn(BuildInInfo::U128) => build_in!(u128),
TypeVariant::BuildIn(BuildInInfo::Usize) => build_in!(usize),
TypeVariant::BuildIn(BuildInInfo::I8) => build_in!(i8),
TypeVariant::BuildIn(BuildInInfo::I16) => build_in!(i16),
TypeVariant::BuildIn(BuildInInfo::I32) => build_in!(i32),
TypeVariant::BuildIn(BuildInInfo::I64) => build_in!(i64),
TypeVariant::BuildIn(BuildInInfo::I128) => build_in!(i128),
TypeVariant::BuildIn(BuildInInfo::Isize) => build_in!(isize),
TypeVariant::BuildIn(BuildInInfo::F32) => build_in!(f32),
TypeVariant::BuildIn(BuildInInfo::F64) => build_in!(f64),
TypeVariant::BuildIn(BuildInInfo::Bool) => {
match default.to_ascii_lowercase().as_str() {
"true" | "yes" | "1" => return Ok(quote!(true)),
"false" | "no" | "0" => return Ok(quote!(false)),
_ => (),
}
}
TypeVariant::BuildIn(BuildInInfo::String) => {
return Ok(quote!(String::from(#default)));
}
TypeVariant::BuildIn(BuildInInfo::Custom(x)) => {
if let Some(x) = x.default(default) {
return Ok(x);
}
}
TypeVariant::Enumeration(ei) => {
let module_path = ModulePath::from_namespace(current_ns, types);
let target_type = type_ref.to_ident_path().relative_to(&module_path);
for var in &*ei.variants {
if var.type_.is_none() && var.ident.name.as_str() == default {
let variant_ident =
format_variant_ident(&var.ident.name, var.display_name.as_deref());
return Ok(quote!(#target_type :: #variant_ident));
}
if let Some(target_ident) = &var.type_ {
if let Ok(default) = self.get_default(current_ns, default, target_ident) {
let variant_ident = match self.state.cache.get(target_ident) {
Some(type_ref) if var.ident.name.is_generated() => {
type_ref.type_ident.clone()
}
_ => format_variant_ident(
&var.ident.name,
var.display_name.as_deref(),
),
};
return Ok(quote!(#target_type :: #variant_ident(#default)));
}
}
}
}
TypeVariant::Union(ui) => {
let module_path = ModulePath::from_namespace(current_ns, types);
let target_type = type_ref.to_ident_path().relative_to(&module_path);
for ty in &*ui.types {
if let Ok(code) = self.get_default(current_ns, default, &ty.type_) {
let variant_ident = match self.state.cache.get(&ty.type_) {
Some(type_ref) if ty.type_.name.is_generated() => {
type_ref.type_ident.clone()
}
_ => format_variant_ident(&ty.type_.name, ty.display_name.as_deref()),
};
return Ok(quote! {
#target_type :: #variant_ident ( #code )
});
}
}
}
TypeVariant::Reference(ti) => match Occurs::from_occurs(ti.min_occurs, ti.max_occurs) {
Occurs::Single => return self.get_default(current_ns, default, &ti.type_),
Occurs::DynamicList if default.is_empty() => {
let module_path = ModulePath::from_namespace(current_ns, types);
let target_type = type_ref.to_ident_path().relative_to(&module_path);
return Ok(quote! { #target_type(Vec::new()) });
}
_ => (),
},
_ => (),
}
Err(Error::InvalidDefaultValue(
ident.clone(),
default.to_owned(),
))
}
}
impl<'types> Deref for Request<'_, 'types> {
type Target = Config<'types>;
fn deref(&self) -> &Self::Target {
self.config
}
}
fn is_dynamic(ident: &Ident, types: &Types) -> bool {
let Some(ty) = types.get(ident) else {
return false;
};
match &ty.variant {
TypeVariant::Dynamic(_) => true,
TypeVariant::ComplexType(ci) => ci.is_dynamic,
TypeVariant::Reference(x) if x.is_single() => is_dynamic(&x.type_, types),
_ => false,
}
}
fn make_tag_name(types: &Types, ident: &Ident) -> String {
let name = ident.name.to_string();
if let Some(module) = ident
.ns
.as_ref()
.and_then(|ns| types.modules.get(ns))
.and_then(|module| module.name.as_ref())
{
format!("{module}:{name}")
} else {
name
}
}
fn make_derived_type_data<'types>(
req: &mut Request<'_, 'types>,
ident: &'types Ident,
) -> Result<DerivedType, Error> {
let s_name = ident.name.to_string();
let b_name = Literal::byte_string(s_name.as_bytes());
let ty = req
.types
.get(ident)
.ok_or_else(|| Error::UnknownType(ident.clone()))?;
let base_ident = if let TypeVariant::Dynamic(di) = &ty.variant {
di.type_.clone()
} else {
None
};
let ident = base_ident.unwrap_or(ident.clone());
let target_ref = req.get_or_create_type_ref(ident.clone())?;
let target_type = target_ref.to_ident_path();
let variant_ident = format_variant_ident(&ident.name, None);
Ok(DerivedType {
ident,
b_name,
target_type,
variant_ident,
})
}