use std::fmt::{self, Display};
use serde::{de::{self, DeserializeSeed, SeqAccess, Visitor}, forward_to_deserialize_any, Deserialize};
const BACKSLASH: u8 = b'\\';
const CLOSE_BRACE: u8 = b'}';
const DATA_PREFIX: &str = "«data TIFF";
const DATA_SUFFIX: &str = "»";
const DOUBLE_ARROW_PREFIX: u8 = "«".as_bytes()[0];
const MISSING_DATA: &str = "missing value";
const NEWLINE: u8 = b'\n';
const OPEN_BRACE: u8 = b'{';
const QUOTE: u8 = b'"';
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
Eof,
Message(String),
InvalidUtf8,
Syntax(char),
TrailingCharacters,
UnexpectedCharacter(char, char),
}
impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error::Message(msg.to_string())
}
}
impl Display for Error {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Eof => formatter.write_str("unexpected end of input"),
Error::InvalidUtf8 => formatter.write_str("invalid utf8"),
Error::Message(msg) => formatter.write_str(msg),
Error::Syntax(c) => formatter.write_fmt(format_args!("syntax error '{}'", c)),
Error::TrailingCharacters => formatter.write_str("trailing characters"),
Error::UnexpectedCharacter(expected, found) => formatter.write_fmt(format_args!("expected '{expected}', found '{found}'")),
}
}
}
impl std::error::Error for Error {}
pub struct AppleScriptDeserializer<'de> {
input: &'de[u8],
}
impl <'de> AppleScriptDeserializer<'de> {
pub fn from_bytes(input: &'de[u8]) -> Self {
AppleScriptDeserializer { input }
}
}
pub fn from_bytes<'a, T>(input: &'a[u8]) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = AppleScriptDeserializer::from_bytes(input);
let t = T::deserialize(&mut deserializer)?;
if deserializer.input.len() == 1 && deserializer.input[0] == NEWLINE {
Ok(t)
} else {
Err(Error::TrailingCharacters)
}
}
impl <'de> AppleScriptDeserializer<'de> {
fn expect_byte(&mut self, b: u8) -> Result<bool> {
if self.input[0] == b {
self.input = &self.input[1..];
Ok(true)
} else {
Err(Error::UnexpectedCharacter(char::from(b), char::from(self.input[0])))
}
}
fn expect_str(&mut self, s: &str) -> Result<()> {
for c in s.bytes() {
self.expect_byte(c)?;
}
Ok(())
}
fn peek_byte(&self) -> Result<u8> {
self.input.first().copied().ok_or(Error::Eof)
}
fn seek_byte(&mut self, b: u8) -> Result<&[u8]> {
let mut result = Err(Error::Eof);
let mut idx = 0;
while result.is_err() && idx < self.input.len() {
if self.input[idx] == b && idx > 0 && self.input[idx - 1] != BACKSLASH {
result = Ok(&self.input[..idx]);
self.input = &self.input[idx..];
}
idx += 1;
}
result
}
}
impl<'de, 'a> de::Deserializer<'de> for &'a mut AppleScriptDeserializer<'de> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.peek_byte()? {
b'm' => self.deserialize_option(visitor),
QUOTE => self.deserialize_str(visitor),
OPEN_BRACE => self.deserialize_seq(visitor),
DOUBLE_ARROW_PREFIX => self.deserialize_bytes(visitor),
b => Err(Error::Syntax(char::from(b))),
}
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de> {
fn try_from_hex(c: u8) -> Result<u8> {
match c {
48..=58 => Ok(c - 48),
65..=71 => Ok(c - 55),
97..=103 => Ok(c - 87),
_ => Err(Error::UnexpectedCharacter(char::from(c), 'x')),
}
}
self.expect_str(DATA_PREFIX)?;
let hex = self.seek_byte(DOUBLE_ARROW_PREFIX)?;
let mut binary = Vec::with_capacity(hex.len() / 2);
for i in 0..binary.capacity() {
binary.push(16 * try_from_hex(hex[i * 2])? + try_from_hex(hex[i * 2 + 1])?);
}
let result = visitor.visit_byte_buf(binary)?;
self.expect_str(DATA_SUFFIX)?;
Ok(result)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de> {
if self.peek_byte()? == MISSING_DATA.as_bytes()[0] {
self.expect_str(MISSING_DATA)?;
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de> {
self.expect_byte(OPEN_BRACE)?;
let value = visitor.visit_seq(CommaSeparated::new(self))?;
self.expect_byte(CLOSE_BRACE)?;
Ok(value)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de> {
self.expect_byte(QUOTE)?;
let value = match std::str::from_utf8(self.seek_byte(QUOTE)?) {
Ok(s) => visitor.visit_str(s),
Err(_) => Err(Error::InvalidUtf8)
};
self.expect_byte(QUOTE)?;
value
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char string
byte_buf unit unit_struct newtype_struct tuple
tuple_struct map struct enum identifier ignored_any
}
}
struct CommaSeparated<'a, 'de: 'a> {
de: &'a mut AppleScriptDeserializer<'de>,
first: bool,
}
impl<'a, 'de> CommaSeparated<'a, 'de> {
fn new(de: &'a mut AppleScriptDeserializer<'de>) -> Self {
CommaSeparated {
de,
first: true,
}
}
}
impl<'de, 'a> SeqAccess<'de> for CommaSeparated<'a, 'de> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
if self.de.peek_byte()? == CLOSE_BRACE {
return Ok(None);
}
if !self.first {
self.de.expect_byte(b',')?;
self.de.expect_byte(b' ')?;
}
self.first = false;
seed.deserialize(&mut *self.de).map(Some)
}
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use image::DynamicImage;
use crate::{deserializer::{from_bytes, Result, DATA_PREFIX, DATA_SUFFIX, NEWLINE}, dynamic_image_ext::DynamicImageExt};
#[test]
fn deserialize_image() {
let sample = DynamicImage::new(1, 2, image::ColorType::L8);
let mut str = String::new();
str.push_str(DATA_PREFIX);
let mut cursor = Cursor::new(Vec::new());
sample.write_to(&mut cursor, image::ImageFormat::Tiff).unwrap();
for c in cursor.into_inner() {
str.push_str(&format!("{:02x}", c));
}
str.push_str(DATA_SUFFIX);
str.push_str(std::str::from_utf8(&[NEWLINE]).unwrap());
let image: DynamicImageExt = from_bytes(str.as_bytes()).unwrap();
assert_eq!(1, image.width());
assert_eq!(2, image.height());
}
#[test]
fn deserialize_optional() {
let optional: Result<Option<String>> = from_bytes("missing value\n".as_bytes());
assert_eq!(None, optional.unwrap());
}
#[test]
fn deserialize_str() {
let str: Result<String> = from_bytes("\"test\"\n".as_bytes());
assert_eq!("test", str.unwrap());
}
#[test]
fn deserialize_seq_empty() {
let seq: Result<Vec<String>> = from_bytes("{}\n".as_bytes());
assert_eq!(Vec::<String>::new(), seq.unwrap());
}
#[test]
fn deserialize_seq_optional_str() {
let seq_optional_str: Result<Vec<Option<String>>> = from_bytes("{\"test\", missing value}\n".as_bytes());
assert_eq!(vec![Some("test".to_string()), None], seq_optional_str.unwrap());
}
}