use std::path::PathBuf;
use bitflags::bitflags;
use url::Url;
pub use crate::generator::{BoxFlags, GeneratorFlags, SerdeSupport, TypedefMode};
pub use crate::schema::{Namespace, NamespacePrefix};
pub use crate::types::{IdentType, Type};
use crate::schema::Schemas;
use crate::types::{Ident, Name};
use crate::InterpreterError;
#[must_use]
#[derive(Default, Debug, Clone)]
pub struct Config {
pub parser: ParserConfig,
pub interpreter: InterpreterConfig,
pub optimizer: OptimizerConfig,
pub generator: GeneratorConfig,
}
#[derive(Debug, Clone)]
pub struct ParserConfig {
pub resolver: Vec<Resolver>,
pub namespaces: Vec<(NamespacePrefix, Namespace)>,
pub schemas: Vec<Schema>,
pub flags: ParserFlags,
pub debug_output: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct InterpreterConfig {
pub types: Vec<(IdentTriple, Type)>,
pub flags: InterpreterFlags,
pub debug_output: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct OptimizerConfig {
pub flags: OptimizerFlags,
pub debug_output: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct GeneratorConfig {
pub types: Vec<IdentTriple>,
pub derive: Option<Vec<String>>,
pub dyn_type_traits: Option<Vec<String>>,
pub type_postfix: TypePostfix,
pub box_flags: BoxFlags,
pub typedef_mode: TypedefMode,
pub serde_support: SerdeSupport,
pub generate: Generate,
pub flags: GeneratorFlags,
pub xsd_parser: String,
pub renderers: Vec<Renderer>,
}
#[derive(Debug, Clone)]
pub struct TypePostfix {
pub type_: String,
pub element: String,
pub element_type: String,
}
#[derive(Debug, Clone)]
pub enum Resolver {
#[cfg(feature = "web-resolver")]
Web,
File,
}
#[derive(Debug, Clone)]
pub enum Schema {
Url(Url),
File(PathBuf),
Schema(String),
}
#[derive(Debug, Clone)]
pub enum Generate {
All,
Named,
Types(Vec<IdentTriple>),
}
#[derive(Debug, Clone)]
pub struct IdentTriple {
pub ns: Option<NamespaceIdent>,
pub name: String,
pub type_: IdentType,
}
#[derive(Debug, Clone)]
pub enum NamespaceIdent {
Prefix(NamespacePrefix),
Namespace(Namespace),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Renderer {
Types,
Defaults,
NamespaceConstants,
WithNamespaceTrait,
QuickXmlSerialize,
QuickXmlDeserialize {
boxed_deserializer: bool,
},
}
bitflags! {
#[derive(Debug, Clone)]
pub struct ParserFlags: u32 {
const RESOLVE_INCLUDES = 1 << 0;
const DEFAULT_NAMESPACES = 1 << 1;
}
}
bitflags! {
#[derive(Debug, Clone)]
pub struct InterpreterFlags: u32 {
const BUILDIN_TYPES = 1 << 0;
const DEFAULT_TYPEDEFS = 1 << 1;
const WITH_XS_ANY_TYPE = 1 << 2;
}
}
bitflags! {
#[derive(Debug, Clone)]
pub struct OptimizerFlags: u32 {
const REMOVE_EMPTY_ENUM_VARIANTS = 1 << 0;
const REMOVE_EMPTY_ENUMS = 1 << 1;
const REMOVE_DUPLICATE_UNION_VARIANTS = 1 << 2;
const REMOVE_EMPTY_UNIONS = 1 << 3;
const USE_UNRESTRICTED_BASE_TYPE = 1 << 4;
const CONVERT_DYNAMIC_TO_CHOICE = 1 << 5;
const FLATTEN_COMPLEX_TYPES = 1 << 6;
const FLATTEN_UNIONS = 1 << 7;
const MERGE_ENUM_UNIONS = 1 << 8;
const RESOLVE_TYPEDEFS = 1 << 9;
const REMOVE_DUPLICATES = 1 << 10;
const SERDE = Self::FLATTEN_COMPLEX_TYPES.bits()
| Self::FLATTEN_UNIONS.bits()
| Self::MERGE_ENUM_UNIONS.bits();
const MERGE_CHOICE_CARDINALITIES = 1 << 11;
}
}
impl Config {
pub fn set_parser_flags(mut self, flags: ParserFlags) -> Self {
self.parser.flags = flags;
self
}
pub fn with_parser_flags(mut self, flags: ParserFlags) -> Self {
self.parser.flags.insert(flags);
self
}
pub fn without_parser_flags(mut self, flags: ParserFlags) -> Self {
self.parser.flags.remove(flags);
self
}
pub fn set_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
self.interpreter.flags = flags;
self
}
pub fn with_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
self.interpreter.flags.insert(flags);
self
}
pub fn without_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
self.interpreter.flags.remove(flags);
self
}
pub fn set_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
self.optimizer.flags = flags;
self
}
pub fn with_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
self.optimizer.flags.insert(flags);
self
}
pub fn without_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
self.optimizer.flags.remove(flags);
self
}
pub fn set_generator_flags(mut self, flags: GeneratorFlags) -> Self {
self.generator.flags = flags;
self
}
pub fn with_generator_flags(mut self, flags: GeneratorFlags) -> Self {
self.generator.flags.insert(flags);
self
}
pub fn without_generator_flags(mut self, flags: GeneratorFlags) -> Self {
self.generator.flags.remove(flags);
self
}
pub fn set_box_flags(mut self, flags: BoxFlags) -> Self {
self.generator.box_flags = flags;
self
}
pub fn with_box_flags(mut self, flags: BoxFlags) -> Self {
self.generator.box_flags.insert(flags);
self
}
pub fn without_box_flags(mut self, flags: BoxFlags) -> Self {
self.generator.box_flags.remove(flags);
self
}
pub fn with_renderer(mut self, renderer: Renderer) -> Self {
if let Some(index) = self.generator.renderers.iter().position(|x| x == &renderer) {
self.generator.renderers[index] = renderer;
} else {
self.generator.renderers.push(renderer);
}
self
}
pub fn with_renderers<I>(mut self, renderers: I) -> Self
where
I: IntoIterator<Item = Renderer>,
{
for renderer in renderers {
self = self.with_renderer(renderer);
}
self
}
pub fn with_quick_xml_serialize(self) -> Self {
self.with_renderers([
Renderer::Types,
Renderer::Defaults,
Renderer::NamespaceConstants,
Renderer::QuickXmlSerialize,
])
}
pub fn with_quick_xml_deserialize(self) -> Self {
self.with_quick_xml_deserialize_config(false)
}
pub fn with_quick_xml_deserialize_config(self, boxed_deserializer: bool) -> Self {
self.with_renderers([
Renderer::Types,
Renderer::Defaults,
Renderer::NamespaceConstants,
Renderer::QuickXmlDeserialize { boxed_deserializer },
])
}
pub fn with_quick_xml(self) -> Self {
self.with_quick_xml_serialize().with_quick_xml_deserialize()
}
pub fn with_quick_xml_config(self, boxed_deserializer: bool) -> Self {
self.with_quick_xml_serialize()
.with_quick_xml_deserialize_config(boxed_deserializer)
}
pub fn with_serde_support(mut self, serde_support: SerdeSupport) -> Self {
self.generator.serde_support = serde_support;
if self.generator.serde_support != SerdeSupport::None {
self.optimizer.flags |= OptimizerFlags::SERDE;
}
self
}
pub fn with_generate<I>(mut self, types: I) -> Self
where
I: IntoIterator,
I::Item: Into<IdentTriple>,
{
self.generator.generate = Generate::Types(types.into_iter().map(Into::into).collect());
self
}
pub fn with_typedef_mode(mut self, mode: TypedefMode) -> Self {
self.generator.typedef_mode = mode;
self
}
pub fn with_derive<I>(mut self, derive: I) -> Self
where
I: IntoIterator,
I::Item: Into<String>,
{
self.generator.derive = Some(
derive
.into_iter()
.map(Into::into)
.filter(|s| !s.is_empty())
.collect(),
);
self
}
}
impl Default for ParserConfig {
fn default() -> Self {
Self {
resolver: vec![Resolver::File],
schemas: vec![],
namespaces: vec![],
flags: ParserFlags::RESOLVE_INCLUDES | ParserFlags::DEFAULT_NAMESPACES,
debug_output: None,
}
}
}
impl Default for InterpreterConfig {
fn default() -> Self {
Self {
types: vec![],
debug_output: None,
flags: InterpreterFlags::BUILDIN_TYPES
| InterpreterFlags::DEFAULT_TYPEDEFS
| InterpreterFlags::WITH_XS_ANY_TYPE,
}
}
}
impl Default for OptimizerConfig {
fn default() -> Self {
Self {
debug_output: None,
flags: OptimizerFlags::REMOVE_EMPTY_ENUM_VARIANTS
| OptimizerFlags::REMOVE_EMPTY_ENUMS
| OptimizerFlags::REMOVE_DUPLICATE_UNION_VARIANTS
| OptimizerFlags::REMOVE_EMPTY_UNIONS,
}
}
}
impl Default for GeneratorConfig {
fn default() -> Self {
Self {
types: vec![],
derive: None,
type_postfix: TypePostfix::default(),
dyn_type_traits: None,
box_flags: BoxFlags::AUTO,
typedef_mode: TypedefMode::Auto,
serde_support: SerdeSupport::None,
generate: Generate::Named,
flags: GeneratorFlags::empty(),
xsd_parser: "xsd_parser".into(),
renderers: vec![Renderer::Types],
}
}
}
impl Default for TypePostfix {
fn default() -> Self {
Self {
type_: String::from("Type"),
element: String::new(),
element_type: String::from("ElementType"),
}
}
}
impl IdentTriple {
pub fn resolve(self, schemas: &Schemas) -> Result<Ident, InterpreterError> {
let ns = match self.ns {
None => None,
Some(NamespaceIdent::Prefix(prefix)) => Some(
schemas
.resolve_prefix(&prefix)
.ok_or(InterpreterError::UnknownNamespacePrefix(prefix))?,
),
#[allow(clippy::unnecessary_literal_unwrap)]
Some(NamespaceIdent::Namespace(ns)) => {
let ns = Some(ns);
Some(
schemas
.resolve_namespace(&ns)
.ok_or_else(|| InterpreterError::UnknownNamespace(ns.unwrap()))?,
)
}
};
Ok(Ident {
ns,
name: Name::new_named(self.name),
type_: self.type_,
})
}
}
impl<X> From<(IdentType, X)> for IdentTriple
where
X: AsRef<str>,
{
fn from((type_, ident): (IdentType, X)) -> Self {
let ident = ident.as_ref();
let (prefix, name) = ident
.split_once(':')
.map_or((None, ident), |(a, b)| (Some(a), b));
let ns = prefix.map(|x| NamespaceIdent::prefix(x.as_bytes().to_owned()));
let name = name.to_owned();
Self { ns, name, type_ }
}
}
impl<N, X> From<(IdentType, N, X)> for IdentTriple
where
N: Into<Option<NamespaceIdent>>,
X: Into<String>,
{
fn from((type_, ns, name): (IdentType, N, X)) -> Self {
let ns = ns.into();
let name = name.into();
Self { ns, name, type_ }
}
}
impl NamespaceIdent {
pub fn prefix<X>(value: X) -> Self
where
NamespacePrefix: From<X>,
{
Self::Prefix(NamespacePrefix::from(value))
}
pub fn namespace<X>(value: X) -> Self
where
Namespace: From<X>,
{
Self::Namespace(Namespace::from(value))
}
}
impl From<Namespace> for NamespaceIdent {
fn from(value: Namespace) -> Self {
Self::Namespace(value)
}
}
impl From<NamespacePrefix> for NamespaceIdent {
fn from(value: NamespacePrefix) -> Self {
Self::Prefix(value)
}
}