use super::codec::{put_plp_utf16, Encode};
use bytes::BytesMut;
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct XmlSchema {
db_name: String,
owner: String,
collection: String,
}
impl XmlSchema {
pub(crate) fn new(
db_name: impl ToString,
owner: impl ToString,
collection: impl ToString,
) -> Self {
Self {
db_name: db_name.to_string(),
owner: owner.to_string(),
collection: collection.to_string(),
}
}
pub fn db_name(&self) -> &str {
&self.db_name
}
pub fn owner(&self) -> &str {
&self.owner
}
pub fn collection(&self) -> &str {
&self.collection
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct XmlData {
data: String,
schema: Option<Arc<XmlSchema>>,
}
impl XmlData {
pub fn new(data: impl ToString) -> Self {
Self {
data: data.to_string(),
schema: None,
}
}
pub(crate) fn set_schema(&mut self, schema: Arc<XmlSchema>) {
self.schema = Some(schema);
}
#[allow(clippy::option_as_ref_deref)]
pub fn schema(&self) -> Option<&XmlSchema> {
self.schema.as_ref().map(|s| &**s)
}
pub fn into_string(self) -> String {
self.data
}
}
impl std::fmt::Display for XmlData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.data)
}
}
impl AsRef<str> for XmlData {
fn as_ref(&self) -> &str {
self.data.as_ref()
}
}
impl Encode<BytesMut> for XmlData {
fn encode(self, dst: &mut BytesMut) -> crate::Result<()> {
put_plp_utf16(dst, &self.data)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn xml_schema_accessors() {
let schema = XmlSchema::new("db", "owner", "collection");
assert_eq!(schema.db_name(), "db");
assert_eq!(schema.owner(), "owner");
assert_eq!(schema.collection(), "collection");
}
#[test]
fn xml_schema_eq_and_clone() {
let a = XmlSchema::new("db", "owner", "collection");
let b = a.clone();
assert_eq!(a, b);
}
#[test]
fn xml_data_without_schema() {
let data = XmlData::new("<root/>");
assert!(data.schema().is_none());
assert_eq!(data.as_ref(), "<root/>");
assert_eq!(format!("{}", data), "<root/>");
assert_eq!(data.into_string(), "<root/>");
}
#[test]
fn xml_data_with_schema() {
let schema = Arc::new(XmlSchema::new("db", "owner", "collection"));
let mut data = XmlData::new("<a>1</a>");
data.set_schema(schema.clone());
let stored = data.schema().expect("schema present");
assert_eq!(stored.db_name(), "db");
assert_eq!(stored.owner(), "owner");
assert_eq!(stored.collection(), "collection");
}
#[test]
fn encode_writes_plp_header_and_backpatches_length() {
let mut buf = BytesMut::new();
XmlData::new("ab")
.encode(&mut buf)
.expect("encode succeeds");
assert_eq!(buf.len(), 8 + 4 + 4 + 4);
assert_eq!(&buf[0..8], &0xfffffffffffffffe_u64.to_le_bytes());
assert_eq!(&buf[8..12], &(4u32).to_le_bytes());
assert_eq!(&buf[12..16], &[b'a', 0, b'b', 0]);
assert_eq!(&buf[16..20], &(0u32).to_le_bytes());
}
#[test]
fn encode_empty_is_the_terminator_alone() {
let mut buf = BytesMut::new();
XmlData::new("").encode(&mut buf).unwrap();
let mut expected = 0xfffffffffffffffe_u64.to_le_bytes().to_vec();
expected.extend_from_slice(&0u32.to_le_bytes());
assert_eq!(&buf[..], &expected[..]);
}
}