xso: use values instead of types for text codecs
This allows stateful or configurable codecs without having to express all configuration in the type name itself. For example, we could have a Base64 type with configurable Base64 engines without having to duplicate the Base64 type itself. (Note that the different engines in the Base64 crate are values, not types.)
This commit is contained in:
parent
b9fc15977b
commit
271c31c9d4
10 changed files with 150 additions and 101 deletions
|
|
@ -148,7 +148,7 @@ enum FieldKind {
|
|||
/// The field maps to the character data of the element.
|
||||
Text {
|
||||
/// Optional codec to use
|
||||
codec: Option<Type>,
|
||||
codec: Option<Expr>,
|
||||
},
|
||||
|
||||
/// The field maps to a child
|
||||
|
|
@ -321,10 +321,10 @@ impl FieldDef {
|
|||
let FromEventsScope { ref text, .. } = scope;
|
||||
let field_access = scope.access_field(&self.member);
|
||||
let finalize = match codec {
|
||||
Some(codec_ty) => {
|
||||
let decode = text_codec_decode_fn(codec_ty.clone(), self.ty.clone());
|
||||
Some(codec) => {
|
||||
let decode = text_codec_decode_fn(self.ty.clone());
|
||||
quote! {
|
||||
#decode(#field_access)?
|
||||
#decode(&#codec, #field_access)?
|
||||
}
|
||||
}
|
||||
None => {
|
||||
|
|
@ -429,9 +429,9 @@ impl FieldDef {
|
|||
|
||||
FieldKind::Text { ref codec } => {
|
||||
let generator = match codec {
|
||||
Some(codec_ty) => {
|
||||
let encode = text_codec_encode_fn(codec_ty.clone(), self.ty.clone());
|
||||
quote! { #encode(#bound_name)? }
|
||||
Some(codec) => {
|
||||
let encode = text_codec_encode_fn(self.ty.clone());
|
||||
quote! { #encode(&#codec, #bound_name)? }
|
||||
}
|
||||
None => {
|
||||
let as_xml_text = as_xml_text_fn(self.ty.clone());
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ pub(crate) enum XmlFieldMeta {
|
|||
/// `#[xml(text)]`
|
||||
Text {
|
||||
/// The path to the optional codec type.
|
||||
codec: Option<Type>,
|
||||
codec: Option<Expr>,
|
||||
},
|
||||
|
||||
/// `#[xml(child)`
|
||||
|
|
@ -497,7 +497,7 @@ impl XmlFieldMeta {
|
|||
|
||||
/// Parse a `#[xml(text)]` meta.
|
||||
fn text_from_meta(meta: ParseNestedMeta<'_>) -> Result<Self> {
|
||||
let mut codec: Option<Type> = None;
|
||||
let mut codec: Option<Expr> = None;
|
||||
if meta.input.peek(Token![=]) {
|
||||
Ok(Self::Text {
|
||||
codec: Some(meta.value()?.parse()?),
|
||||
|
|
|
|||
|
|
@ -298,76 +298,66 @@ pub(crate) fn as_xml_text_fn(ty: Type) -> Expr {
|
|||
})
|
||||
}
|
||||
|
||||
/// Construct a [`syn::TypePath`] referring to
|
||||
/// `<#codec_ty as ::xso::TextCodec::<#for_ty>>` and return the
|
||||
/// [`syn::Span`] of the `codec_ty` alongside it.
|
||||
fn text_codec_of(codec_ty: Type, for_ty: Type) -> (Span, TypePath) {
|
||||
let span = codec_ty.span();
|
||||
/// Construct a [`syn::Path`] referring to `::xso::TextCodec::<#for_ty>`,
|
||||
/// returing the span of `for_ty` alongside it.
|
||||
fn text_codec_of(for_ty: Type) -> (Span, Path) {
|
||||
let span = for_ty.span();
|
||||
(
|
||||
span,
|
||||
TypePath {
|
||||
qself: Some(QSelf {
|
||||
lt_token: syn::token::Lt { spans: [span] },
|
||||
ty: Box::new(codec_ty),
|
||||
position: 2,
|
||||
as_token: Some(syn::token::As { span }),
|
||||
gt_token: syn::token::Gt { spans: [span] },
|
||||
Path {
|
||||
leading_colon: Some(syn::token::PathSep {
|
||||
spans: [span, span],
|
||||
}),
|
||||
path: Path {
|
||||
leading_colon: Some(syn::token::PathSep {
|
||||
spans: [span, span],
|
||||
}),
|
||||
segments: [
|
||||
PathSegment {
|
||||
ident: Ident::new("xso", span),
|
||||
arguments: PathArguments::None,
|
||||
},
|
||||
PathSegment {
|
||||
ident: Ident::new("TextCodec", span),
|
||||
arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
|
||||
colon2_token: Some(syn::token::PathSep {
|
||||
spans: [span, span],
|
||||
}),
|
||||
lt_token: syn::token::Lt { spans: [span] },
|
||||
args: [GenericArgument::Type(for_ty)].into_iter().collect(),
|
||||
gt_token: syn::token::Gt { spans: [span] },
|
||||
segments: [
|
||||
PathSegment {
|
||||
ident: Ident::new("xso", span),
|
||||
arguments: PathArguments::None,
|
||||
},
|
||||
PathSegment {
|
||||
ident: Ident::new("TextCodec", span),
|
||||
arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments {
|
||||
colon2_token: Some(syn::token::PathSep {
|
||||
spans: [span, span],
|
||||
}),
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
lt_token: syn::token::Lt { spans: [span] },
|
||||
args: [GenericArgument::Type(for_ty)].into_iter().collect(),
|
||||
gt_token: syn::token::Gt { spans: [span] },
|
||||
}),
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Construct a [`syn::Expr`] referring to
|
||||
/// `<#codec_ty as ::xso::TextCodec::<#for_ty>>::encode`.
|
||||
pub(crate) fn text_codec_encode_fn(codec_ty: Type, for_ty: Type) -> Expr {
|
||||
let (span, mut ty) = text_codec_of(codec_ty, for_ty);
|
||||
ty.path.segments.push(PathSegment {
|
||||
/// `::xso::TextCodec::<#for_ty>::encode`.
|
||||
pub(crate) fn text_codec_encode_fn(for_ty: Type) -> Expr {
|
||||
let (span, mut path) = text_codec_of(for_ty);
|
||||
path.segments.push(PathSegment {
|
||||
ident: Ident::new("encode", span),
|
||||
arguments: PathArguments::None,
|
||||
});
|
||||
Expr::Path(ExprPath {
|
||||
attrs: Vec::new(),
|
||||
qself: ty.qself,
|
||||
path: ty.path,
|
||||
qself: None,
|
||||
path: path,
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a [`syn::Expr`] referring to
|
||||
/// `<#codec_ty as ::xso::TextCodec::<#for_ty>>::decode`.
|
||||
pub(crate) fn text_codec_decode_fn(codec_ty: Type, for_ty: Type) -> Expr {
|
||||
let (span, mut ty) = text_codec_of(codec_ty, for_ty);
|
||||
ty.path.segments.push(PathSegment {
|
||||
/// `::xso::TextCodec::<#for_ty>::decode`.
|
||||
pub(crate) fn text_codec_decode_fn(for_ty: Type) -> Expr {
|
||||
let (span, mut path) = text_codec_of(for_ty);
|
||||
path.segments.push(PathSegment {
|
||||
ident: Ident::new("decode", span),
|
||||
arguments: PathArguments::None,
|
||||
});
|
||||
Expr::Path(ExprPath {
|
||||
attrs: Vec::new(),
|
||||
qself: ty.qself,
|
||||
path: ty.path,
|
||||
qself: None,
|
||||
path: path,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue