mirror of
https://github.com/Xiphoseer/serde-amf3.git
synced 2025-12-17 20:34:26 -06:00
Initial commit
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/target
|
||||
/Cargo.lock
|
||||
*.bin
|
||||
*.json
|
||||
*.txt
|
||||
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "serde-amf3"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.140" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0.82"
|
||||
serde = { version = "1.0.140", features = ["derive"] }
|
||||
clap = { version = "3.2.13", features = ["derive"] }
|
||||
22
examples/amf3-pp.rs
Normal file
22
examples/amf3-pp.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Name of the file to pretty-print
|
||||
#[clap(value_parser)]
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let bytes = std::fs::read(&args.path).unwrap();
|
||||
let value = serde_amf3::deserialize::<serde_json::Value>(&bytes[..]).unwrap();
|
||||
let mut serializer = serde_json::Serializer::pretty(std::io::stdout().lock());
|
||||
value.serialize(&mut serializer).unwrap();
|
||||
println!();
|
||||
}
|
||||
85
examples/bbb-msg.rs
Normal file
85
examples/bbb-msg.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// Name of the file to pretty-print
|
||||
#[clap(value_parser)]
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct ExecutionStateStrip {
|
||||
#[serde(rename = "actionIndex")]
|
||||
action_index: u32,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct ExecutionState {
|
||||
#[serde(rename = "stateID")]
|
||||
state_id: u32,
|
||||
strips: Vec<ExecutionStateStrip>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(tag = "Type")]
|
||||
enum Action {
|
||||
OnInteract {
|
||||
#[serde(rename = "__callbackID__")]
|
||||
callback_id: String,
|
||||
},
|
||||
FlyUp {
|
||||
#[serde(rename = "Distance")]
|
||||
distance: f64,
|
||||
#[serde(rename = "__callbackID__")]
|
||||
callback_id: String,
|
||||
},
|
||||
FlyDown {
|
||||
#[serde(rename = "Distance")]
|
||||
distance: f64,
|
||||
#[serde(rename = "__callbackID__")]
|
||||
callback_id: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Pos2 {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Strip {
|
||||
id: u32,
|
||||
actions: Vec<Action>,
|
||||
ui: Pos2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct State {
|
||||
id: u32,
|
||||
strips: Vec<Strip>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Root {
|
||||
#[serde(rename = "BehaviorID")]
|
||||
behavior_id: String,
|
||||
#[serde(rename = "executionState")]
|
||||
execution_state: ExecutionState,
|
||||
#[serde(rename = "objectID")]
|
||||
object_id: String,
|
||||
states: Vec<State>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let bytes = std::fs::read(&args.path).unwrap();
|
||||
let value = serde_amf3::deserialize::<Root>(&bytes[..]).unwrap();
|
||||
println!("{:#?}", value);
|
||||
}
|
||||
173
src/format.rs
Normal file
173
src/format.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
use std::str::Utf8Error;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Marker {
|
||||
Undefined = 0x00,
|
||||
Null = 0x01,
|
||||
False = 0x02,
|
||||
True = 0x03,
|
||||
Integer = 0x04,
|
||||
Double = 0x05,
|
||||
String = 0x06,
|
||||
XmlDoc = 0x07,
|
||||
Date = 0x08,
|
||||
Array = 0x09,
|
||||
Object = 0x0A,
|
||||
Xml = 0x0B,
|
||||
ByteArray = 0x0C,
|
||||
VectorInt = 0x0D,
|
||||
VectorUInt = 0x0E,
|
||||
VectorDouble = 0x0F,
|
||||
VectorObject = 0x10,
|
||||
Dictionary = 0x11,
|
||||
}
|
||||
|
||||
impl Marker {
|
||||
fn new(value: u8) -> Result<Self, Error> {
|
||||
if value < 0x12 {
|
||||
Ok(unsafe { std::mem::transmute(value) })
|
||||
} else {
|
||||
Err(Error::InvalidMarker(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub(super) enum Error {
|
||||
InvalidMarker(u8),
|
||||
StringDecode(Utf8Error),
|
||||
EndOfStream,
|
||||
MissingStringReference,
|
||||
}
|
||||
|
||||
impl From<Utf8Error> for Error {
|
||||
fn from(e: Utf8Error) -> Self {
|
||||
Self::StringDecode(e)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Deserializer<'de> {
|
||||
input: std::slice::Iter<'de, u8>,
|
||||
|
||||
string_reference_table: Vec<&'de str>,
|
||||
}
|
||||
|
||||
fn try_split_array_ref<const N: usize>(slice: &[u8]) -> Result<(&[u8; N], &[u8]), Error> {
|
||||
if slice.len() < N {
|
||||
Err(Error::EndOfStream)
|
||||
} else {
|
||||
let rest = unsafe { slice.get_unchecked(N..) };
|
||||
// SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
|
||||
Ok((unsafe { &*(slice.as_ptr() as *const [u8; N]) }, rest))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserializer<'de> {
|
||||
pub(super) fn read_byte(&mut self) -> Result<u8, Error> {
|
||||
self.input.next().copied().ok_or(Error::EndOfStream)
|
||||
}
|
||||
|
||||
pub(super) fn read_marker(&mut self) -> Result<Marker, Error> {
|
||||
let byte = self.read_byte()?;
|
||||
Marker::new(byte)
|
||||
}
|
||||
|
||||
/// 0x00000000 - 0x0000007F : 0xxxxxxx
|
||||
/// 0x00000080 - 0x00003FFF : 1xxxxxxx 0xxxxxxx
|
||||
/// 0x00004000 - 0x001FFFFF : 1xxxxxxx 1xxxxxxx 0xxxxxxx
|
||||
/// 0x00200000 - 0x3FFFFFFF : 1xxxxxxx 1xxxxxxx 1xxxxxxx xxxxxxxx
|
||||
/// 0x40000000 - 0xFFFFFFFF : throw range exception
|
||||
pub(super) fn read_u29(&mut self) -> Result<u32, Error> {
|
||||
let first = self.read_byte()?;
|
||||
let mut value = u32::from(first & 0x7F);
|
||||
if first >= 0x80 {
|
||||
let second = self.read_byte()?;
|
||||
value <<= 7;
|
||||
value |= u32::from(second & 0x7F);
|
||||
if second >= 0x80 {
|
||||
let third = self.read_byte()?;
|
||||
value <<= 7;
|
||||
value |= u32::from(third & 0x7F);
|
||||
if third >= 0x80 {
|
||||
let fourth = self.read_byte()?;
|
||||
value <<= 8;
|
||||
value |= u32::from(fourth);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub(super) fn read_double(&mut self) -> Result<f64, Error> {
|
||||
let slice = self.input.as_slice();
|
||||
let (double_bytes, rest) = try_split_array_ref(slice)?;
|
||||
self.input = rest.iter();
|
||||
Ok(f64::from_le_bytes(*double_bytes))
|
||||
}
|
||||
|
||||
pub(super) fn read_string(&mut self) -> Result<&'de str, Error> {
|
||||
let header = self.read_u29()?;
|
||||
let value = (header >> 1) as usize;
|
||||
if header & 1 == 0 {
|
||||
// by reference
|
||||
let string = *(self
|
||||
.string_reference_table
|
||||
.get(value)
|
||||
.ok_or(Error::MissingStringReference)?);
|
||||
Ok(string)
|
||||
} else if self.input.len() >= value {
|
||||
// by value
|
||||
let slice = self.input.as_slice();
|
||||
let string_bytes = unsafe { slice.get_unchecked(..value) };
|
||||
let rest = unsafe { slice.get_unchecked(value..) };
|
||||
self.input = rest.iter();
|
||||
let string = std::str::from_utf8(string_bytes)?;
|
||||
if !string.is_empty() {
|
||||
self.string_reference_table.push(string);
|
||||
}
|
||||
Ok(string)
|
||||
} else {
|
||||
Err(Error::EndOfStream)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(input: &'de [u8]) -> Self {
|
||||
Self {
|
||||
input: input.iter(),
|
||||
string_reference_table: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn skip(&mut self) -> Result<(), Error> {
|
||||
let marker = self.read_marker()?;
|
||||
match marker {
|
||||
Marker::Integer => {
|
||||
self.read_u29()?;
|
||||
}
|
||||
Marker::Double => {
|
||||
self.input = self
|
||||
.input
|
||||
.as_slice()
|
||||
.get(8..)
|
||||
.ok_or(Error::EndOfStream)?
|
||||
.iter();
|
||||
}
|
||||
Marker::String => todo!(),
|
||||
Marker::XmlDoc => todo!(),
|
||||
Marker::Date => todo!(),
|
||||
Marker::Array => todo!(),
|
||||
Marker::Object => todo!(),
|
||||
Marker::Xml => todo!(),
|
||||
Marker::ByteArray => todo!(),
|
||||
Marker::VectorInt => todo!(),
|
||||
Marker::VectorUInt => todo!(),
|
||||
Marker::VectorDouble => todo!(),
|
||||
Marker::VectorObject => todo!(),
|
||||
Marker::Dictionary => todo!(),
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
426
src/lib.rs
Normal file
426
src/lib.rs
Normal file
@@ -0,0 +1,426 @@
|
||||
use std::fmt;
|
||||
|
||||
use format::Marker;
|
||||
use serde::{de::value::BorrowedStrDeserializer, forward_to_deserialize_any, Deserialize};
|
||||
use traits::{VisitDouble, VisitInt};
|
||||
|
||||
mod format;
|
||||
mod traits;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum ErrorKind {
|
||||
#[allow(dead_code)]
|
||||
Unimplemented,
|
||||
Custom(String),
|
||||
Format(format::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Error {
|
||||
kind: ErrorKind,
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self.kind {
|
||||
ErrorKind::Unimplemented => write!(f, "Unimplemented"),
|
||||
ErrorKind::Custom(msg) => write!(f, "Custom: {}", msg),
|
||||
ErrorKind::Format(fmt) => write!(f, "Format error: {:?}", fmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::Error for Error {
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: fmt::Display,
|
||||
{
|
||||
Self {
|
||||
kind: ErrorKind::Custom(msg.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ByteDeserializerSeq<'a, 'de> {
|
||||
len: usize,
|
||||
inner: &'a mut ByteDeserializer<'de>,
|
||||
}
|
||||
|
||||
impl<'a, 'de> serde::de::SeqAccess<'de> for ByteDeserializerSeq<'a, 'de> {
|
||||
type Error = Error;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
if self.len > 0 {
|
||||
self.len -= 1;
|
||||
seed.deserialize(&mut *self.inner).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ByteDeserializerMap<'a, 'de> {
|
||||
len: usize,
|
||||
next_key: &'de str,
|
||||
inner: &'a mut ByteDeserializer<'de>,
|
||||
}
|
||||
|
||||
impl<'a, 'de> serde::de::MapAccess<'de> for ByteDeserializerMap<'a, 'de> {
|
||||
type Error = Error;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
|
||||
where
|
||||
K: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
if self.next_key.is_empty() {
|
||||
if self.len > 0 {
|
||||
self.len -= 1;
|
||||
let deserializer = serde::de::value::UsizeDeserializer::new(self.len);
|
||||
seed.deserialize(deserializer).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
let deserializer = BorrowedStrDeserializer::new(self.next_key);
|
||||
seed.deserialize(deserializer).map(Some)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
let value = seed.deserialize(&mut *self.inner)?;
|
||||
if !self.next_key.is_empty() {
|
||||
self.next_key = self.inner.inner.read_string()?;
|
||||
}
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ByteDeserializer<'de> {
|
||||
inner: format::Deserializer<'de>,
|
||||
}
|
||||
|
||||
impl<'de> ByteDeserializer<'de> {
|
||||
pub fn from_bytes(input: &'de [u8]) -> Self {
|
||||
Self {
|
||||
inner: format::Deserializer::new(input),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_array<V: serde::de::Visitor<'de>>(
|
||||
&mut self,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error> {
|
||||
let header = self.inner.read_u29()?;
|
||||
let value = (header >> 1) as usize;
|
||||
if header & 1 == 0 {
|
||||
// array by reference
|
||||
unimplemented!()
|
||||
} else {
|
||||
// dense count
|
||||
let first_key = self.inner.read_string()?;
|
||||
if first_key.is_empty() {
|
||||
// only dense keys => array
|
||||
visitor.visit_seq(ByteDeserializerSeq {
|
||||
inner: self,
|
||||
len: value,
|
||||
})
|
||||
} else {
|
||||
visitor.visit_map(ByteDeserializerMap {
|
||||
inner: self,
|
||||
len: value,
|
||||
next_key: first_key,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_into<V, N: VisitInt, F: VisitDouble>(
|
||||
&mut self,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
let marker = self.inner.read_marker()?;
|
||||
match marker {
|
||||
Marker::Undefined => visitor.visit_none(),
|
||||
Marker::Null => visitor.visit_none(),
|
||||
Marker::False => visitor.visit_bool(false),
|
||||
Marker::True => visitor.visit_bool(true),
|
||||
Marker::Integer => N::visit_int(visitor, self.inner.read_u29()?),
|
||||
Marker::Double => F::visit_double(visitor, self.inner.read_double()?),
|
||||
Marker::String => visitor.visit_borrowed_str(self.inner.read_string()?),
|
||||
Marker::XmlDoc => todo!(),
|
||||
Marker::Date => todo!(),
|
||||
Marker::Array => self.deserialize_array(visitor),
|
||||
Marker::Object => todo!(),
|
||||
Marker::Xml => todo!(),
|
||||
Marker::ByteArray => todo!(),
|
||||
Marker::VectorInt => todo!(),
|
||||
Marker::VectorUInt => todo!(),
|
||||
Marker::VectorDouble => todo!(),
|
||||
Marker::VectorObject => todo!(),
|
||||
Marker::Dictionary => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<format::Error> for Error {
|
||||
fn from(e: format::Error) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::Format(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, T: Deserialize<'de>>(input: &'de [u8]) -> Result<T, Error> {
|
||||
let mut deserializer = ByteDeserializer::from_bytes(input);
|
||||
T::deserialize(&mut deserializer)
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserializer<'de> for &mut ByteDeserializer<'de> {
|
||||
type Error = Error;
|
||||
|
||||
forward_to_deserialize_any! { bool str string option unit seq tuple map struct identifier }
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, u32, f64>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, i8, i8>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, i16, i16>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, i32, i32>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, i64, i64>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, u8, u8>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, u16, u16>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, u32, u32>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, u64, u64>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, f32, f32>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_into::<V, f64, f64>(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn deserialize_unit_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
/*fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
todo!()
|
||||
}*/
|
||||
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.inner.skip()?;
|
||||
visitor.visit_none()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::{format, Error, ErrorKind};
|
||||
|
||||
const EOS_ERROR: Error = Error {
|
||||
kind: ErrorKind::Format(format::Error::EndOfStream),
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_bool() {
|
||||
assert_eq!(super::deserialize::<bool>(&[]), Err(EOS_ERROR));
|
||||
assert_eq!(super::deserialize::<bool>(&[0x02]), Ok(false));
|
||||
assert_eq!(super::deserialize::<bool>(&[0x03]), Ok(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_integer() {
|
||||
assert_eq!(super::deserialize(&[0x04, 0x05]), Ok(5u8));
|
||||
assert_eq!(super::deserialize(&[0x04, 0x05]), Ok(5u16));
|
||||
assert_eq!(super::deserialize(&[0x04, 0x05]), Ok(5u32));
|
||||
assert_eq!(super::deserialize(&[0x04, 0x05]), Ok(5u64));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_double() {
|
||||
assert_eq!(super::deserialize(&[0x05, 0, 0, 0, 0, 0, 0, 0, 0]), Ok(0.0));
|
||||
assert_eq!(
|
||||
super::deserialize(&[0x05, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
Ok(0.0f32)
|
||||
);
|
||||
assert_eq!(
|
||||
super::deserialize(&[0x05, 0, 0, 0, 0, 0, 0, 0xD0, 0x3F]),
|
||||
Ok(0.25)
|
||||
);
|
||||
assert_eq!(
|
||||
super::deserialize(&[0x05, 0, 0, 0, 0, 0, 0, 0xD0, 0x3F]),
|
||||
Ok(0.25f32)
|
||||
);
|
||||
assert_eq!(
|
||||
super::deserialize(&[0x05, 0x9A, 0x99, 0x99, 0x99, 0x99, 0x99, 0xB9, 0x3F]),
|
||||
Ok(0.1)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string() {
|
||||
assert_eq!(super::deserialize(b"\x06\x0BHello"), Ok("Hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option() {
|
||||
assert_eq!(super::deserialize::<Option<u32>>(b"\x00"), Ok(None));
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
struct Test {
|
||||
a: u32,
|
||||
b: u32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array() {
|
||||
assert_eq!(
|
||||
super::deserialize::<Vec<u32>>(&[0x09, 0x7, 0x01, 0x04, 1, 0x04, 2, 0x04, 3]),
|
||||
Ok(vec![1, 2, 3])
|
||||
);
|
||||
assert_eq!(
|
||||
super::deserialize(&[0x09, 0x1, 0x03, b'a', 0x04, 5, 0x03, b'b', 0x04, 7, 0x01]),
|
||||
Ok(Test { a: 5, b: 7 })
|
||||
);
|
||||
}
|
||||
}
|
||||
58
src/traits.rs
Normal file
58
src/traits.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use super::Error;
|
||||
|
||||
pub(super) trait VisitInt {
|
||||
fn visit_int<'de, V: serde::de::Visitor<'de>>(visitor: V, v: u32) -> Result<V::Value, Error>;
|
||||
}
|
||||
|
||||
macro_rules! impl_visit_int {
|
||||
($f:ident $t:ty) => {
|
||||
impl VisitInt for $t {
|
||||
fn visit_int<'de, V: serde::de::Visitor<'de>>(
|
||||
visitor: V,
|
||||
v: u32,
|
||||
) -> Result<V::Value, Error> {
|
||||
visitor.$f(v as $t)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_visit_int!(visit_u8 u8);
|
||||
impl_visit_int!(visit_u16 u16);
|
||||
impl_visit_int!(visit_u32 u32);
|
||||
impl_visit_int!(visit_u64 u64);
|
||||
impl_visit_int!(visit_i8 i8);
|
||||
impl_visit_int!(visit_i16 i16);
|
||||
impl_visit_int!(visit_i32 i32);
|
||||
impl_visit_int!(visit_i64 i64);
|
||||
impl_visit_int!(visit_f32 f32);
|
||||
impl_visit_int!(visit_f64 f64);
|
||||
|
||||
pub(super) trait VisitDouble {
|
||||
fn visit_double<'de, V: serde::de::Visitor<'de>>(visitor: V, v: f64)
|
||||
-> Result<V::Value, Error>;
|
||||
}
|
||||
|
||||
macro_rules! impl_visit_double {
|
||||
($f:ident $t:ty) => {
|
||||
impl VisitDouble for $t {
|
||||
fn visit_double<'de, V: serde::de::Visitor<'de>>(
|
||||
visitor: V,
|
||||
v: f64,
|
||||
) -> Result<V::Value, Error> {
|
||||
visitor.$f(v as $t)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_visit_double!(visit_f32 f32);
|
||||
impl_visit_double!(visit_f64 f64);
|
||||
impl_visit_double!(visit_i8 i8);
|
||||
impl_visit_double!(visit_u8 u8);
|
||||
impl_visit_double!(visit_i16 i16);
|
||||
impl_visit_double!(visit_u16 u16);
|
||||
impl_visit_double!(visit_i32 i32);
|
||||
impl_visit_double!(visit_u32 u32);
|
||||
impl_visit_double!(visit_i64 i64);
|
||||
impl_visit_double!(visit_u64 u64);
|
||||
Reference in New Issue
Block a user