Skip to content

Commit 7cb2dba

Browse files
Merge pull request #16 from Erik1000/fix/handle_transparent_types
fix: in WriteScalar::format_scalar use `Peek::innermost_peek()` to
2 parents f0fa06a + b79105d commit 7cb2dba

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

facet-dom/src/serializer/write_scalar.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ pub trait WriteScalar: DomSerializer {
1515
///
1616
/// Returns `Some(string)` if the value is a scalar, `None` otherwise.
1717
fn format_scalar(&self, value: Peek<'_, '_>) -> Option<String> {
18+
// handle transparent types and unwrap all types
19+
let value = value.innermost_peek();
20+
1821
// Handle Option<T> by unwrapping if Some
1922
if let Def::Option(_) = &value.shape().def
2023
&& let Ok(opt) = value.into_option()

facet-xml-node/src/lib.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,10 @@ impl From<&str> for Content {
261261

262262
#[cfg(test)]
263263
mod tests {
264+
use std::{fmt::Display, str::FromStr};
265+
264266
use super::*;
267+
use facet::Facet;
265268
use facet_testhelpers::test;
266269

267270
#[test]
@@ -556,4 +559,82 @@ mod tests {
556559

557560
assert!(result.elements.is_empty());
558561
}
562+
563+
#[derive(Debug, Facet)]
564+
#[facet(proxy = StringRepr)]
565+
struct ConstantName;
566+
567+
/// A proxy type for Facet that uses the Display/FromStr implementation
568+
#[derive(Debug, Facet)]
569+
#[repr(transparent)]
570+
pub(crate) struct StringRepr(pub String);
571+
572+
impl Display for ConstantName {
573+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
574+
write!(f, "CONSTANT")
575+
}
576+
}
577+
578+
impl FromStr for ConstantName {
579+
type Err = &'static str;
580+
fn from_str(s: &str) -> Result<Self, Self::Err> {
581+
if s == "CONSTANT" {
582+
Ok(Self)
583+
} else {
584+
Err("expected `CONSTANT`")
585+
}
586+
}
587+
}
588+
589+
impl From<ConstantName> for StringRepr {
590+
fn from(value: ConstantName) -> Self {
591+
Self(value.to_string())
592+
}
593+
}
594+
impl From<&ConstantName> for StringRepr {
595+
fn from(value: &ConstantName) -> Self {
596+
Self(value.to_string())
597+
}
598+
}
599+
impl TryFrom<StringRepr> for ConstantName {
600+
type Error = <ConstantName as core::str::FromStr>::Err;
601+
fn try_from(value: StringRepr) -> Result<Self, Self::Error> {
602+
value.0.parse()
603+
}
604+
}
605+
impl TryFrom<&StringRepr> for ConstantName {
606+
type Error = <ConstantName as core::str::FromStr>::Err;
607+
fn try_from(value: &StringRepr) -> Result<Self, Self::Error> {
608+
value.0.parse()
609+
}
610+
}
611+
612+
#[derive(Debug, Facet)]
613+
#[repr(C)]
614+
enum Foo {
615+
#[facet(rename = "foo")]
616+
Value {
617+
#[facet(xml::attribute)]
618+
#[allow(unused)]
619+
name: ConstantName,
620+
#[facet(xml::attribute)]
621+
#[allow(unused)]
622+
exists: String,
623+
},
624+
}
625+
626+
#[test]
627+
fn transparent_attribute_not_discarded() {
628+
let raw_xml = r#"
629+
<foo name="CONSTANT" exists="i do exist and am not discarded"></foo>"#;
630+
let x: Foo = facet_xml::from_str(raw_xml).unwrap();
631+
let element = crate::to_element(&x).unwrap();
632+
let _ = facet_xml::to_string(&x).unwrap();
633+
let _ = facet_xml::to_string(&element).unwrap();
634+
assert!(
635+
element.attrs.contains_key("exists"),
636+
"this attribute is not discarded"
637+
);
638+
assert_eq!(element.attrs["name"], "CONSTANT", "name is not discarded");
639+
}
559640
}

facet-xml-node/src/parser.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,10 @@ impl DomSerializer for ElementSerializer {
255255
if let Some(value_str) = self.format_scalar(value) {
256256
let elem = self.stack.last_mut().ok_or(ElementSerializeError)?;
257257
elem.attrs.insert(name.to_string(), value_str);
258+
Ok(())
259+
} else {
260+
Err(ElementSerializeError)
258261
}
259-
Ok(())
260262
}
261263

262264
fn children_start(&mut self) -> Result<(), Self::Error> {

0 commit comments

Comments
 (0)