1use super::codec::{put_plp_utf16, Encode};
3use bytes::BytesMut;
4use std::sync::Arc;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct XmlSchema {
10 db_name: String,
11 owner: String,
12 collection: String,
13}
14
15impl XmlSchema {
16 pub(crate) fn new(
17 db_name: impl ToString,
18 owner: impl ToString,
19 collection: impl ToString,
20 ) -> Self {
21 Self {
22 db_name: db_name.to_string(),
23 owner: owner.to_string(),
24 collection: collection.to_string(),
25 }
26 }
27
28 pub fn db_name(&self) -> &str {
30 &self.db_name
31 }
32
33 pub fn owner(&self) -> &str {
35 &self.owner
36 }
37
38 pub fn collection(&self) -> &str {
41 &self.collection
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
48#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49pub struct XmlData {
50 data: String,
51 schema: Option<Arc<XmlSchema>>,
52}
53
54impl XmlData {
55 pub fn new(data: impl ToString) -> Self {
58 Self {
59 data: data.to_string(),
60 schema: None,
61 }
62 }
63
64 pub(crate) fn set_schema(&mut self, schema: Arc<XmlSchema>) {
65 self.schema = Some(schema);
66 }
67
68 #[allow(clippy::option_as_ref_deref)]
70 pub fn schema(&self) -> Option<&XmlSchema> {
71 self.schema.as_ref().map(|s| &**s)
72 }
73
74 pub fn into_string(self) -> String {
76 self.data
77 }
78}
79
80impl std::fmt::Display for XmlData {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 write!(f, "{}", self.data)
83 }
84}
85
86impl AsRef<str> for XmlData {
87 fn as_ref(&self) -> &str {
88 self.data.as_ref()
89 }
90}
91
92impl Encode<BytesMut> for XmlData {
93 fn encode(self, dst: &mut BytesMut) -> crate::Result<()> {
94 put_plp_utf16(dst, &self.data)
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn xml_schema_accessors() {
104 let schema = XmlSchema::new("db", "owner", "collection");
105 assert_eq!(schema.db_name(), "db");
106 assert_eq!(schema.owner(), "owner");
107 assert_eq!(schema.collection(), "collection");
108 }
109
110 #[test]
111 fn xml_schema_eq_and_clone() {
112 let a = XmlSchema::new("db", "owner", "collection");
113 let b = a.clone();
114 assert_eq!(a, b);
115 }
116
117 #[test]
118 fn xml_data_without_schema() {
119 let data = XmlData::new("<root/>");
120 assert!(data.schema().is_none());
121 assert_eq!(data.as_ref(), "<root/>");
122 assert_eq!(format!("{}", data), "<root/>");
123 assert_eq!(data.into_string(), "<root/>");
124 }
125
126 #[test]
127 fn xml_data_with_schema() {
128 let schema = Arc::new(XmlSchema::new("db", "owner", "collection"));
129 let mut data = XmlData::new("<a>1</a>");
130 data.set_schema(schema.clone());
131
132 let stored = data.schema().expect("schema present");
133 assert_eq!(stored.db_name(), "db");
134 assert_eq!(stored.owner(), "owner");
135 assert_eq!(stored.collection(), "collection");
136 }
137
138 #[test]
139 fn encode_writes_plp_header_and_backpatches_length() {
140 let mut buf = BytesMut::new();
141 XmlData::new("ab")
142 .encode(&mut buf)
143 .expect("encode succeeds");
144
145 assert_eq!(buf.len(), 8 + 4 + 4 + 4);
147
148 assert_eq!(&buf[0..8], &0xfffffffffffffffe_u64.to_le_bytes());
150 assert_eq!(&buf[8..12], &(4u32).to_le_bytes());
152 assert_eq!(&buf[12..16], &[b'a', 0, b'b', 0]);
154 assert_eq!(&buf[16..20], &(0u32).to_le_bytes());
156 }
157
158 #[test]
159 fn encode_empty_is_the_terminator_alone() {
160 let mut buf = BytesMut::new();
161 XmlData::new("").encode(&mut buf).unwrap();
162
163 let mut expected = 0xfffffffffffffffe_u64.to_le_bytes().to_vec();
164 expected.extend_from_slice(&0u32.to_le_bytes());
165 assert_eq!(&buf[..], &expected[..]);
166 }
167}