#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub mod owned;
mod parse;
mod write;
pub use write::Writer;
use parse::{Cursor, Events, Nothing};
use crate::{
error::{ErrorKind, ParseError, Result, err},
limits::Limits,
};
const RELAXED: Limits = Limits::DEFAULT
.max_list_members(u16::MAX)
.max_inner_list_members(u16::MAX)
.max_params(u16::MAX)
.max_dictionary_members(u16::MAX)
.max_key_len(u16::MAX)
.max_string_len(u16::MAX)
.max_token_len(u16::MAX)
.max_byte_seq_len(u32::MAX);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BareItem<'a> {
Integer(i64),
Decimal(Decimal),
String(SfString<'a>),
Token(&'a str),
ByteSeq(ByteSeq<'a>),
Boolean(bool),
Date(i64),
DisplayString(DisplayString<'a>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Decimal(pub(crate) i64);
impl Decimal {
pub const fn from_thousandths(t: i64) -> Result<Self> {
if t > parse::INTEGER_MAX || t < -parse::INTEGER_MAX {
return err(ErrorKind::OutOfRange, 0);
}
Ok(Self(t))
}
#[must_use]
pub const fn thousandths(self) -> i64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SfString<'a> {
raw: &'a str,
escapes: bool,
}
impl<'a> SfString<'a> {
#[must_use]
pub const fn raw(&self) -> &'a str {
self.raw
}
#[must_use]
pub const fn as_plain(&self) -> Option<&'a str> {
if self.escapes { None } else { Some(self.raw) }
}
fn bytes(&self) -> crate::text::Unescape<'a> {
crate::text::Quoted::from_raw(self.raw.as_bytes(), self.escapes).bytes()
}
#[must_use]
pub fn unescaped_len(&self) -> usize {
if self.escapes {
self.bytes().count()
} else {
self.raw.len()
}
}
pub fn unescape_into<'b>(&self, out: &'b mut [u8]) -> Result<&'b str> {
let len = self.unescaped_len();
let Some(dst) = out.get_mut(..len) else {
return err(ErrorKind::BufferTooSmall, 0);
};
for (d, b) in dst.iter_mut().zip(self.bytes()) {
*d = b;
}
core::str::from_utf8(dst).map_err(|_| ParseError::new(ErrorKind::InvalidUtf8, 0))
}
#[must_use]
pub fn eq_str(&self, other: &str) -> bool {
self.bytes().eq(other.bytes())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ByteSeq<'a> {
raw: &'a [u8],
}
impl<'a> ByteSeq<'a> {
#[must_use]
pub const fn raw(&self) -> &'a [u8] {
self.raw
}
#[must_use]
pub fn decoded_len(&self) -> usize {
let body = self.raw.iter().take_while(|&&b| b != b'=').count();
body / 4 * 3 + (body % 4).saturating_sub(1)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DisplayString<'a> {
raw: &'a [u8],
}
impl<'a> DisplayString<'a> {
#[must_use]
pub const fn raw(&self) -> &'a [u8] {
self.raw
}
#[must_use]
pub fn decoded_len(&self) -> usize {
crate::pct::decoded_len(self.raw).unwrap_or(0)
}
pub fn decode_into<'b>(&self, out: &'b mut [u8]) -> Result<&'b str> {
crate::pct::decode_utf8_into(self.raw, out)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SfParams<'a> {
text: &'a [u8],
count: usize,
}
impl<'a> SfParams<'a> {
const EMPTY: Self = Self {
text: &[],
count: 0,
};
#[must_use]
pub fn iter(&self) -> ParamIter<'a> {
ParamIter {
c: Cursor::new(self.text),
}
}
#[must_use]
pub fn get(&self, key: &str) -> Option<BareItem<'a>> {
self.iter()
.filter(|(k, _)| *k == key)
.last()
.map(|(_, v)| v)
}
#[must_use]
pub const fn len(&self) -> usize {
self.count
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.count == 0
}
}
#[derive(Clone, Debug)]
pub struct ParamIter<'a> {
c: Cursor<'a>,
}
impl<'a> Iterator for ParamIter<'a> {
type Item = (&'a str, BareItem<'a>);
fn next(&mut self) -> Option<Self::Item> {
if self.c.peek() != Some(b';') {
return None;
}
self.c.bump();
self.c.skip_sp();
let k = parse::key(&mut self.c, &RELAXED).ok()?;
let v = if self.c.peek() == Some(b'=') {
self.c.bump();
parse::bare_item(&mut self.c, &RELAXED).ok()?
} else {
BareItem::Boolean(true)
};
Some((k, v))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Item<'a> {
pub bare: BareItem<'a>,
pub params: SfParams<'a>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InnerList<'a> {
text: &'a [u8],
count: usize,
params: SfParams<'a>,
}
impl<'a> InnerList<'a> {
#[must_use]
pub fn iter(&self) -> InnerIter<'a> {
let mut c = Cursor::new(self.text);
c.bump(); InnerIter { c }
}
#[must_use]
pub const fn len(&self) -> usize {
self.count
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.count == 0
}
#[must_use]
pub const fn params(&self) -> SfParams<'a> {
self.params
}
}
#[derive(Clone, Debug)]
pub struct InnerIter<'a> {
c: Cursor<'a>,
}
impl<'a> Iterator for InnerIter<'a> {
type Item = Item<'a>;
fn next(&mut self) -> Option<Item<'a>> {
self.c.skip_sp();
if matches!(self.c.peek(), Some(b')') | None) {
return None;
}
item_view(&mut self.c)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Member<'a> {
Item(Item<'a>),
InnerList(InnerList<'a>),
}
fn item_view<'a>(c: &mut Cursor<'a>) -> Option<Item<'a>> {
let bare = parse::bare_item(c, &RELAXED).ok()?;
let params = params_view(c)?;
Some(Item { bare, params })
}
fn params_view<'a>(c: &mut Cursor<'a>) -> Option<SfParams<'a>> {
let start = c.i;
let count = parse::params(c, &RELAXED, |_, _| Ok(())).ok()?;
Some(SfParams {
text: c.s.get(start..c.i).unwrap_or(&[]),
count,
})
}
fn member_view<'a>(c: &mut Cursor<'a>) -> Option<Member<'a>> {
if c.peek() != Some(b'(') {
return item_view(c).map(Member::Item);
}
let start = c.i;
let mut inner = *c;
inner.bump(); let mut count = 0usize;
loop {
inner.skip_sp();
match inner.peek() {
Some(b')') => {
inner.bump();
break;
}
None => return None,
Some(_) => {}
}
let _ = item_view(&mut inner)?;
count += 1;
}
let text = c.s.get(start..inner.i).unwrap_or(&[]);
let params = params_view(&mut inner)?;
*c = inner;
Some(Member::InnerList(InnerList {
text,
count,
params,
}))
}
fn field_text(v: &[u8]) -> Cursor<'_> {
let start = v.iter().take_while(|&&b| b == b' ').count();
let end = v.len() - v.iter().rev().take_while(|&&b| b == b' ').count();
Cursor::new(v.get(start..end.max(start)).unwrap_or(&[]))
}
fn next_member(c: &mut Cursor<'_>) -> bool {
c.skip_ows();
if c.peek() != Some(b',') {
return false;
}
c.bump();
c.skip_ows();
true
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct List<'a> {
text: &'a [u8],
count: usize,
}
impl<'a> List<'a> {
#[must_use]
pub fn iter(&self) -> ListIter<'a> {
ListIter {
c: Cursor::new(self.text),
started: false,
}
}
#[must_use]
pub const fn len(&self) -> usize {
self.count
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.count == 0
}
}
#[derive(Clone, Debug)]
pub struct ListIter<'a> {
c: Cursor<'a>,
started: bool,
}
impl<'a> Iterator for ListIter<'a> {
type Item = Member<'a>;
fn next(&mut self) -> Option<Member<'a>> {
if self.started && !next_member(&mut self.c) {
return None;
}
self.started = true;
if self.c.is_empty() {
return None;
}
member_view(&mut self.c)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Dictionary<'a> {
text: &'a [u8],
count: usize,
}
impl<'a> Dictionary<'a> {
#[must_use]
pub fn iter(&self) -> DictIter<'a> {
DictIter {
c: Cursor::new(self.text),
started: false,
}
}
#[must_use]
pub fn get(&self, key: &str) -> Option<Member<'a>> {
self.iter()
.filter(|(k, _)| *k == key)
.last()
.map(|(_, m)| m)
}
pub fn index_into<'i>(
&self,
slots: &'i mut [(&'a str, Member<'a>)],
) -> Result<&'i [(&'a str, Member<'a>)]> {
let mut n = 0usize;
for (k, m) in self.iter() {
let existing = slots
.get_mut(..n)
.and_then(|filled| filled.iter_mut().find(|(sk, _)| *sk == k));
match existing {
Some(slot) => slot.1 = m,
None => {
let Some(slot) = slots.get_mut(n) else {
return err(ErrorKind::BufferTooSmall, 0);
};
*slot = (k, m);
n += 1;
}
}
}
Ok(slots.get(..n).unwrap_or(&[]))
}
#[must_use]
pub const fn len(&self) -> usize {
self.count
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.count == 0
}
}
#[derive(Clone, Debug)]
pub struct DictIter<'a> {
c: Cursor<'a>,
started: bool,
}
impl<'a> Iterator for DictIter<'a> {
type Item = (&'a str, Member<'a>);
fn next(&mut self) -> Option<Self::Item> {
if self.started && !next_member(&mut self.c) {
return None;
}
self.started = true;
if self.c.is_empty() {
return None;
}
let k = parse::key(&mut self.c, &RELAXED).ok()?;
let m = if self.c.peek() == Some(b'=') {
self.c.bump();
member_view(&mut self.c)?
} else {
Member::Item(Item {
bare: BareItem::Boolean(true),
params: params_view(&mut self.c)?,
})
};
Some((k, m))
}
}
#[derive(Clone, Copy, Debug)]
pub struct ListLines<'a> {
lines: &'a [&'a [u8]],
count: usize,
}
impl<'a> ListLines<'a> {
pub fn iter(&self) -> impl Iterator<Item = Member<'a>> + use<'a> {
self.lines.iter().flat_map(|l| ListIter {
c: field_text(l),
started: false,
})
}
#[must_use]
pub const fn len(&self) -> usize {
self.count
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.count == 0
}
}
#[derive(Clone, Copy, Debug)]
pub struct DictionaryLines<'a> {
lines: &'a [&'a [u8]],
count: usize,
}
impl<'a> DictionaryLines<'a> {
pub fn iter(&self) -> impl Iterator<Item = (&'a str, Member<'a>)> + use<'a> {
self.lines.iter().flat_map(|l| DictIter {
c: field_text(l),
started: false,
})
}
#[must_use]
pub fn get(&self, key: &str) -> Option<Member<'a>> {
self.iter()
.filter(|(k, _)| *k == key)
.last()
.map(|(_, m)| m)
}
#[must_use]
pub const fn len(&self) -> usize {
self.count
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.count == 0
}
}
pub trait Visitor<'a> {
fn item(&mut self, bare: BareItem<'a>) -> Result<()>;
fn param(&mut self, key: &'a str, value: BareItem<'a>) -> Result<()>;
fn inner_list_start(&mut self) -> Result<()> {
Ok(())
}
fn inner_list_end(&mut self) -> Result<()> {
Ok(())
}
fn key(&mut self, key: &'a str) -> Result<()> {
let _ = key;
Ok(())
}
}
struct VisitorEvents<'v, V>(&'v mut V);
impl<'a, V: Visitor<'a>> Events<'a> for VisitorEvents<'_, V> {
fn item(&mut self, bare: BareItem<'a>) -> Result<()> {
self.0.item(bare)
}
fn param(&mut self, key: &'a str, value: BareItem<'a>) -> Result<()> {
self.0.param(key, value)
}
fn inner_start(&mut self) -> Result<()> {
self.0.inner_list_start()
}
fn inner_end(&mut self) -> Result<()> {
self.0.inner_list_end()
}
fn key(&mut self, key: &'a str) -> Result<()> {
self.0.key(key)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Parser {
limits: Limits,
}
impl Default for Parser {
fn default() -> Self {
Self::new(Limits::DEFAULT)
}
}
impl Parser {
#[must_use]
pub const fn new(limits: Limits) -> Self {
Self { limits }
}
pub fn item<'a>(&self, v: &'a [u8]) -> Result<Item<'a>> {
let l = self.limits;
let ((bare, params), _, _) = parse::field(v, |c| {
let bare = parse::bare_item(c, &l)?;
let start = c.i;
let count = parse::params(c, &l, |_, _| Ok(()))?;
Ok((
bare,
SfParams {
text: c.s.get(start..c.i).unwrap_or(&[]),
count,
},
))
})?;
Ok(Item { bare, params })
}
pub fn list<'a>(&self, v: &'a [u8]) -> Result<List<'a>> {
let l = self.limits;
let (count, start, end) = parse::field(v, |c| parse::list(c, &l, &mut Nothing))?;
Ok(List {
text: v.get(start..end).unwrap_or(&[]),
count,
})
}
pub fn dictionary<'a>(&self, v: &'a [u8]) -> Result<Dictionary<'a>> {
let l = self.limits;
let (count, start, end) = parse::field(v, |c| parse::dictionary(c, &l, &mut Nothing))?;
Ok(Dictionary {
text: v.get(start..end).unwrap_or(&[]),
count,
})
}
pub fn list_lines<'a>(&self, lines: &'a [&'a [u8]]) -> Result<ListLines<'a>> {
let mut count = 0usize;
for (n, line) in lines.iter().enumerate() {
if line.iter().all(|&b| b == b' ') {
return Err(ParseError::new(ErrorKind::Empty, 0).on_line(n));
}
count += self.list(line).map_err(|e| e.on_line(n))?.len();
if count > usize::from(self.limits.list_members) {
return Err(ParseError::new(ErrorKind::TooManyMembers, 0).on_line(n));
}
}
Ok(ListLines { lines, count })
}
pub fn dictionary_lines<'a>(&self, lines: &'a [&'a [u8]]) -> Result<DictionaryLines<'a>> {
let mut count = 0usize;
for (n, line) in lines.iter().enumerate() {
if line.iter().all(|&b| b == b' ') {
return Err(ParseError::new(ErrorKind::Empty, 0).on_line(n));
}
count += self.dictionary(line).map_err(|e| e.on_line(n))?.len();
if count > usize::from(self.limits.dictionary_members) {
return Err(ParseError::new(ErrorKind::TooManyMembers, 0).on_line(n));
}
}
Ok(DictionaryLines { lines, count })
}
pub fn visit_item<'a, V: Visitor<'a>>(&self, v: &'a [u8], visitor: &mut V) -> Result<()> {
let l = self.limits;
parse::field(v, |c| {
let mut ev = VisitorEvents(visitor);
let bare = parse::bare_item(c, &l)?;
ev.item(bare)?;
parse::params(c, &l, |k, x| ev.param(k, x)).map(|_| ())
})
.map(|_| ())
}
pub fn visit_list<'a, V: Visitor<'a>>(&self, v: &'a [u8], visitor: &mut V) -> Result<()> {
let l = self.limits;
parse::field(v, |c| parse::list(c, &l, &mut VisitorEvents(visitor))).map(|_| ())
}
pub fn visit_dictionary<'a, V: Visitor<'a>>(&self, v: &'a [u8], visitor: &mut V) -> Result<()> {
let l = self.limits;
parse::field(v, |c| parse::dictionary(c, &l, &mut VisitorEvents(visitor))).map(|_| ())
}
}
pub fn parse_item(value: &[u8]) -> Result<Item<'_>> {
Parser::default().item(value)
}
pub fn parse_list(value: &[u8]) -> Result<List<'_>> {
Parser::default().list(value)
}
pub fn parse_dictionary(value: &[u8]) -> Result<Dictionary<'_>> {
Parser::default().dictionary(value)
}
pub fn parse_list_lines<'a>(lines: &'a [&'a [u8]]) -> Result<ListLines<'a>> {
Parser::default().list_lines(lines)
}
pub fn parse_dictionary_lines<'a>(lines: &'a [&'a [u8]]) -> Result<DictionaryLines<'a>> {
Parser::default().dictionary_lines(lines)
}
impl<'a> Item<'a> {
#[must_use]
pub const fn new(bare: BareItem<'a>) -> Self {
Self {
bare,
params: SfParams::EMPTY,
}
}
}
#[cfg(test)]
mod tests;