use alloc::vec::Vec;
use super::{
BareItem, ByteSeq, Decimal, Dictionary, DisplayString, Item, List, SfParams, SfString,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
enum Kind {
Integer(i64),
Decimal(Decimal),
String { escapes: bool },
Token,
ByteSeq,
Boolean(bool),
Date(i64),
DisplayString,
}
fn split<'a>(b: &BareItem<'a>) -> (Kind, &'a [u8]) {
match *b {
BareItem::Integer(i) => (Kind::Integer(i), &[]),
BareItem::Decimal(d) => (Kind::Decimal(d), &[]),
BareItem::String(s) => (Kind::String { escapes: s.escapes }, s.raw.as_bytes()),
BareItem::Token(t) => (Kind::Token, t.as_bytes()),
BareItem::ByteSeq(s) => (Kind::ByteSeq, s.raw),
BareItem::Boolean(v) => (Kind::Boolean(v), &[]),
BareItem::Date(d) => (Kind::Date(d), &[]),
BareItem::DisplayString(s) => (Kind::DisplayString, s.raw),
}
}
fn view(kind: Kind, bytes: &[u8]) -> BareItem<'_> {
let text = core::str::from_utf8(bytes).unwrap_or("");
match kind {
Kind::Integer(i) => BareItem::Integer(i),
Kind::Decimal(d) => BareItem::Decimal(d),
Kind::String { escapes } => BareItem::String(SfString { raw: text, escapes }),
Kind::Token => BareItem::Token(text),
Kind::ByteSeq => BareItem::ByteSeq(ByteSeq { raw: bytes }),
Kind::Boolean(v) => BareItem::Boolean(v),
Kind::Date(d) => BareItem::Date(d),
Kind::DisplayString => BareItem::DisplayString(DisplayString { raw: bytes }),
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OwnedBareItem {
kind: Kind,
buf: Vec<u8>,
}
impl BareItem<'_> {
#[must_use]
pub fn to_owned(&self) -> OwnedBareItem {
let (kind, bytes) = split(self);
OwnedBareItem {
kind,
buf: bytes.to_vec(),
}
}
}
impl OwnedBareItem {
#[must_use]
pub fn as_view(&self) -> BareItem<'_> {
view(self.kind, &self.buf)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OwnedItem {
kind: Kind,
buf: Vec<u8>,
split: usize,
count: usize,
}
impl Item<'_> {
#[must_use]
pub fn to_owned(&self) -> OwnedItem {
let (kind, bytes) = split(&self.bare);
let mut buf = Vec::with_capacity(bytes.len() + self.params.text.len());
buf.extend_from_slice(bytes);
buf.extend_from_slice(self.params.text);
OwnedItem {
kind,
buf,
split: bytes.len(),
count: self.params.count,
}
}
}
impl OwnedItem {
#[must_use]
pub fn as_view(&self) -> Item<'_> {
let (bare, text) = self.buf.split_at(self.split.min(self.buf.len()));
Item {
bare: view(self.kind, bare),
params: SfParams {
text,
count: self.count,
},
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OwnedList {
text: Vec<u8>,
count: usize,
}
impl List<'_> {
#[must_use]
pub fn to_owned(&self) -> OwnedList {
OwnedList {
text: self.text.to_vec(),
count: self.count,
}
}
}
impl OwnedList {
#[must_use]
pub fn as_view(&self) -> List<'_> {
List {
text: &self.text,
count: self.count,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OwnedDictionary {
text: Vec<u8>,
count: usize,
}
impl Dictionary<'_> {
#[must_use]
pub fn to_owned(&self) -> OwnedDictionary {
OwnedDictionary {
text: self.text.to_vec(),
count: self.count,
}
}
}
impl OwnedDictionary {
#[must_use]
pub fn as_view(&self) -> Dictionary<'_> {
Dictionary {
text: &self.text,
count: self.count,
}
}
}
#[cfg(test)]
mod tests {
use super::super::{parse_dictionary, parse_item, parse_list};
#[test]
fn test_owned_sfv_gives_the_same_view() {
for v in [
&b"1;a=2"[..],
b"\"a\\\"b\";x",
b":YQ==:",
b"%\"%c3%a9\"",
b"?0",
b"@1",
b"tok;p=1.5",
b"-0.5",
] {
let i = parse_item(v).unwrap();
assert_eq!(i.to_owned().as_view(), i);
assert_eq!(i.bare.to_owned().as_view(), i.bare);
}
let l = parse_list(b"a, (b c);d, \"e\"").unwrap();
assert_eq!(l.to_owned().as_view(), l);
let d = parse_dictionary(b"a=1, b, c=(x y);q").unwrap();
assert_eq!(d.to_owned().as_view(), d);
}
}