use crate::{Error, Result};
use core::fmt;
#[cfg(feature = "base64")]
use crate::Base64;
#[cfg(all(feature = "alloc", feature = "base64"))]
use alloc::vec::Vec;
pub const DELIMITER: char = '$';
pub struct Fields<'a>(&'a str);
impl<'a> Fields<'a> {
pub(crate) fn new(s: &'a str) -> Self {
let mut ret = Self(s);
let should_be_empty = ret.next().expect("shouldn't be empty");
debug_assert_eq!(should_be_empty.as_str(), "");
ret
}
}
impl<'a> Iterator for Fields<'a> {
type Item = Field<'a>;
fn next(&mut self) -> Option<Field<'a>> {
if self.0.is_empty() {
return None;
}
match self.0.split_once(DELIMITER) {
Some((field, rest)) => {
self.0 = rest;
Some(Field(field))
}
None => {
let ret = self.0;
self.0 = "";
Some(Field(ret))
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Field<'a>(&'a str);
impl<'a> Field<'a> {
pub fn new(s: &'a str) -> Result<Self> {
let field = Field(s);
field.validate()?;
Ok(field)
}
pub fn as_str(self) -> &'a str {
self.0
}
#[cfg(feature = "base64")]
pub fn decode_base64_into(self, base64_variant: Base64, out: &mut [u8]) -> Result<&[u8]> {
Ok(base64_variant.decode(self.0, out)?)
}
#[cfg(all(feature = "alloc", feature = "base64"))]
pub fn decode_base64(self, base64_variant: Base64) -> Result<Vec<u8>> {
Ok(base64_variant.decode_vec(self.0)?)
}
pub(crate) fn validate(self) -> Result<()> {
if self.0.is_empty() {
return Err(Error::FieldInvalid);
}
for c in self.0.chars() {
match c {
'A'..='Z' | 'a'..='z' | '0'..='9' | '.' | '/' | '+' | '=' | ',' | '-' => (),
_ => return Err(Error::EncodingInvalid),
}
}
Ok(())
}
}
impl AsRef<str> for Field<'_> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl fmt::Display for Field<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.0)
}
}