use crate::{Automaton, Output, State};
use serde::{
de::{self, Deserializer, SeqAccess, Visitor},
ser::SerializeTupleStruct,
Deserialize, Serialize, Serializer,
};
use std::collections::BTreeMap;
use std::fmt;
use std::hash::Hash;
use std::marker::PhantomData;
const SERIALIZATION_VERSION: u32 = 1;
impl Serialize for State {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u32(self.0)
}
}
impl<'de> Deserialize<'de> for State {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(State(deserializer.deserialize_u32(U32Visitor)?))
}
}
struct U32Visitor;
impl<'de> Visitor<'de> for U32Visitor {
type Value = u32;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("an integer between `0` and `2^32 - 1`")
}
fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(u32::from(value))
}
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(value)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
use std::u32;
if value <= u64::from(u32::MAX) {
Ok(value as u32)
} else {
Err(E::custom(format!("u32 out of range: {}", value)))
}
}
}
impl<TAlphabet, TState, TOutput> Serialize for Automaton<TAlphabet, TState, TOutput>
where
TAlphabet: Serialize + Clone + Eq + Hash + Ord,
TState: Serialize + Clone + Eq + Hash,
TOutput: Serialize + Output,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let Automaton {
final_states,
start_state,
state_data,
transitions,
} = self;
let mut s = serializer.serialize_tuple_struct("Automaton", 5)?;
s.serialize_field(&SERIALIZATION_VERSION)?;
s.serialize_field(final_states)?;
s.serialize_field(start_state)?;
s.serialize_field(state_data)?;
s.serialize_field(transitions)?;
s.end()
}
}
impl<'de, TAlphabet, TState, TOutput> Deserialize<'de> for Automaton<TAlphabet, TState, TOutput>
where
TAlphabet: 'de + Deserialize<'de> + Clone + Eq + Hash + Ord,
TState: 'de + Deserialize<'de> + Clone + Eq + Hash,
TOutput: 'de + Deserialize<'de> + Output,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_tuple_struct(
"Automaton",
5,
AutomatonVisitor {
phantom: PhantomData,
},
)
}
}
struct AutomatonVisitor<'de, TAlphabet, TState, TOutput>
where
TAlphabet: 'de + Deserialize<'de> + Clone + Eq + Hash + Ord,
TState: 'de + Deserialize<'de> + Clone + Eq + Hash,
TOutput: 'de + Deserialize<'de> + Output,
{
phantom: PhantomData<&'de (TAlphabet, TState, TOutput)>,
}
impl<'de, TAlphabet, TState, TOutput> Visitor<'de>
for AutomatonVisitor<'de, TAlphabet, TState, TOutput>
where
TAlphabet: 'de + Deserialize<'de> + Clone + Eq + Hash + Ord,
TState: 'de + Deserialize<'de> + Clone + Eq + Hash,
TOutput: 'de + Deserialize<'de> + Output,
{
type Value = Automaton<TAlphabet, TState, TOutput>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("Automaton")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
match seq.next_element::<u32>()? {
Some(v) if v == SERIALIZATION_VERSION => {}
Some(v) => {
return Err(de::Error::invalid_value(
de::Unexpected::Unsigned(v as u64),
&self,
));
}
None => {
return Err(de::Error::invalid_length(
0,
&"Automaton expects 5 elements",
))
}
}
let final_states = match seq.next_element::<BTreeMap<State, TOutput>>()? {
Some(x) => x,
None => {
return Err(de::Error::invalid_length(
1,
&"Automaton expects 5 elements",
))
}
};
let start_state = match seq.next_element::<State>()? {
Some(x) => x,
None => {
return Err(de::Error::invalid_length(
2,
&"Automaton expects 5 elements",
))
}
};
let state_data = match seq.next_element::<Vec<Option<TState>>>()? {
Some(x) => x,
None => {
return Err(de::Error::invalid_length(
3,
&"Automaton expects 5 elements",
))
}
};
let transitions = match seq.next_element::<Vec<BTreeMap<TAlphabet, (State, TOutput)>>>()? {
Some(x) => x,
None => {
return Err(de::Error::invalid_length(
4,
&"Automaton expects 5 elements",
))
}
};
let automata = Automaton {
final_states,
start_state,
state_data,
transitions,
};
automata
.check_representation()
.map_err(|msg| de::Error::custom(msg))?;
Ok(automata)
}
}