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