Skip to content

Commit cc2ff6b

Browse files
XML serialization helpers add XML declaration (#2534)
* XML serialization helpers add XML declaration The XML declaration is automatically prepended to the serialized content. * spellilng * refine via feedback * make DECLARATION bytes * Remove extraneous \n in declaration, re-record Storage tests --------- Co-authored-by: Vincent Tran <[email protected]>
1 parent 74c9492 commit cc2ff6b

File tree

2 files changed

+50
-11
lines changed

2 files changed

+50
-11
lines changed

sdk/storage/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "rust",
4-
"Tag": "rust/azure_storage_blob_e3372225c3",
4+
"Tag": "rust/azure_storage_blob_c54b1e37ce",
55
"TagPrefix": "rust/azure_storage_blob"
66
}

sdk/typespec/typespec_client_core/src/xml.rs

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ use typespec::error::{ErrorKind, Result, ResultExt};
1414
/// The UTF8 [byte order marker](https://en.wikipedia.org/wiki/Byte_order_mark).
1515
const UTF8_BOM: [u8; 3] = [0xEF, 0xBB, 0xBF];
1616

17+
/// The XML declaration used when serializing.
18+
const DECLARATION: &[u8; 38] = br#"<?xml version="1.0" encoding="utf-8"?>"#;
19+
1720
/// Reads XML from bytes.
1821
pub fn read_xml_str<T>(body: &str) -> Result<T>
1922
where
@@ -38,6 +41,8 @@ where
3841
}
3942

4043
/// Serializes a type to bytes.
44+
///
45+
/// Automatically includes the XML declaration.
4146
pub fn to_xml<T>(value: &T) -> Result<Bytes>
4247
where
4348
T: serde::Serialize,
@@ -46,10 +51,15 @@ where
4651
let t = core::any::type_name::<T>();
4752
format!("failed to serialize {t} into xml")
4853
})?;
49-
Ok(Bytes::from(value))
54+
let mut buf = bytes::BytesMut::with_capacity(DECLARATION.len() + value.len());
55+
buf.extend_from_slice(DECLARATION);
56+
buf.extend_from_slice(value.as_bytes());
57+
Ok(buf.into())
5058
}
5159

5260
/// Serializes a type to bytes with a specified root tag.
61+
///
62+
/// Automatically includes the XML declaration.
5363
pub fn to_xml_with_root<T>(root_tag: &str, value: &T) -> Result<Bytes>
5464
where
5565
T: serde::Serialize,
@@ -59,7 +69,10 @@ where
5969
let t = core::any::type_name::<T>();
6070
format!("failed to serialize {t} into xml")
6171
})?;
62-
Ok(Bytes::from(value))
72+
let mut buf = bytes::BytesMut::with_capacity(DECLARATION.len() + value.len());
73+
buf.extend_from_slice(DECLARATION);
74+
buf.extend_from_slice(value.as_bytes());
75+
Ok(buf.into())
6376
}
6477

6578
/// Returns bytes without the UTF-8 BOM.
@@ -74,7 +87,7 @@ fn slice_bom(bytes: &[u8]) -> &[u8] {
7487
#[cfg(test)]
7588
mod test {
7689
use super::*;
77-
use serde::Deserialize;
90+
use serde::{Deserialize, Serialize};
7891

7992
#[test]
8093
fn test_slice_bom() {
@@ -85,27 +98,53 @@ mod test {
8598
assert_eq!(&[8], slice_bom(bytes));
8699
}
87100

101+
#[derive(Deserialize, Serialize, PartialEq, Debug)]
102+
#[serde(rename = "Foo")]
103+
struct Test {
104+
x: String,
105+
}
106+
88107
#[test]
89108
fn reading_xml() -> Result<()> {
90-
#[derive(Deserialize, PartialEq, Debug)]
91-
#[serde(rename = "Foo")]
92-
struct Test {
93-
x: String,
94-
}
95109
let test = Test {
96110
x: "Hello, world!".into(),
97111
};
98112
let xml = br#"<?xml version="1.0" encoding="utf-8"?><Foo><x>Hello, world!</x></Foo>"#;
99113
assert_eq!(test, read_xml(xml)?);
100114

101115
let error = read_xml::<Test>(&xml[..xml.len() - 2]).unwrap_err();
102-
assert!(format!("{error}").contains("reading_xml::Test"));
116+
assert!(format!("{error}").contains("typespec_client_core::xml::test::Test"));
103117

104118
let xml = r#"<?xml version="1.0" encoding="utf-8"?><Foo><x>Hello, world!</x></Foo>"#;
105119
assert_eq!(test, read_xml_str(xml)?);
106120

107121
let error = read_xml_str::<Test>(&xml[..xml.len() - 2]).unwrap_err();
108-
assert!(format!("{error}").contains("reading_xml::Test"));
122+
assert!(format!("{error}").contains("typespec_client_core::xml::test::Test"));
123+
Ok(())
124+
}
125+
126+
#[test]
127+
fn writing_xml() -> Result<()> {
128+
assert_eq!(
129+
br#"<?xml version="1.0" encoding="utf-8"?><Foo><x>Hello, world!</x></Foo>"#,
130+
to_xml(&Test {
131+
x: "Hello, world!".to_string()
132+
})?
133+
.to_vec()
134+
.as_slice()
135+
);
136+
137+
assert_eq!(
138+
br#"<?xml version="1.0" encoding="utf-8"?><Bob><x>Hello, world!</x></Bob>"#,
139+
to_xml_with_root(
140+
"Bob",
141+
&Test {
142+
x: "Hello, world!".to_string()
143+
}
144+
)?
145+
.to_vec()
146+
.as_slice()
147+
);
109148
Ok(())
110149
}
111150
}

0 commit comments

Comments
 (0)