// Copyright (C) 2022, 2023 Soni L.
// SPDX-License-Identifier: MIT OR Apache-2.0
//! Unpacker-related parts of the VM.
use std::collections::HashMap;
use std::collections::hash_map::IntoIter as HMIntoIter;
use serde::de::IntoDeserializer;
use serde::de::value::StrDeserializer;
use crate::errors::UnpackError;
use crate::vm::Pack;
/// A `Deserializer` for Datafu output.
///
/// This converts from Datafu's internal representation (a "pack") into the
/// desired output type.
pub struct Unpacker<'pat, 'de> {
packs: Vec<Pack<'pat, 'de>>,
call_limit: usize,
}
/// Wrapper for an `&mut Unpacker<'pat, 'de>` with additional field
/// unpacking logic.
struct UnpackerFields<'a, 'pat, 'de> {
unpacker: &'a mut Unpacker<'pat, 'de>,
fields: HMIntoIter<&'static str, Option<crate::vm::SerdeObject<'de>>>,
value: Option<crate::vm::SerdeObject<'de>>,
}
impl<'pat, 'de> Unpacker<'pat, 'de> {
/// Creates an Unpacker for unpacking a given Pack.
pub fn new(pack: Pack<'pat, 'de>, call_limit: usize) -> Self {
// invariant: no empty packs
let packs = if pack.subpacks.is_empty() {
vec![]
} else {
vec![pack]
};
Self {
packs, call_limit,
}
}
/// Takes the next subpack from the last pack in the pack stack.
fn take_next_pack(&mut self) -> Option<Pack<'pat, 'de>> {
self.packs.last_mut().and_then(|x| {
x.subpacks.front_mut()
}).map(|&mut (_, ref mut pack)| {
std::mem::take(pack)
}).filter(|pack| !pack.subpacks.is_empty())
}
}
impl<'pat, 'de> serde::de::SeqAccess<'de> for Unpacker<'pat, 'de> {
type Error = UnpackError;
fn next_element_seed<T: serde::de::DeserializeSeed<'de>>(
&mut self,
seed: T,
) -> Result<Option<T::Value>, Self::Error> {
if self.packs.is_empty() {
return Ok(None)
}
seed.deserialize(self).map(Some)
}
}
impl Drop for UnpackerFields<'_, '_, '_> {
fn drop(&mut self) {
let unpacker = &mut *self.unpacker;
while let Some(mut pack) = unpacker.packs.pop() {
pack.subpacks.pop_front();
if !pack.subpacks.is_empty() {
unpacker.packs.push(pack);
break;
}
}
}
}
impl<'pat, 'de> serde::de::MapAccess<'de> for UnpackerFields<'_, 'pat, 'de> {
type Error = UnpackError;
fn next_key_seed<T: serde::de::DeserializeSeed<'de>>(
&mut self,
seed: T,
) -> Result<Option<T::Value>, Self::Error> {
while let Some((key, value)) = self.fields.next() {
if value.is_some() {
self.value = value;
return seed.deserialize(StrDeserializer::new(key)).map(Some)
}
}
Ok(None)
}
fn next_value_seed<T: serde::de::DeserializeSeed<'de>>(
&mut self,
seed: T,
) -> Result<T::Value, Self::Error> {
if let Some(value) = self.value.take() {
seed.deserialize(value.into_deserializer())
} else {
panic!("broken visitor")
}
}
}
impl<'pat, 'de> serde::Deserializer<'de> for &mut Unpacker<'pat, 'de> {
type Error = UnpackError;
fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_bool<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_i8<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_i16<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_i32<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_i64<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_u8<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_u16<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_u32<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_u64<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_f32<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_f64<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_char<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_str<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_string<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_bytes<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_option<V: serde::de::Visitor<'de>>(
self,
visitor: V,
) -> Result<V::Value, Self::Error> {
todo!()
}
fn deserialize_unit<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_unit_struct<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_newtype_struct<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!(); }
fn deserialize_tuple<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_tuple_struct<V>(self, _: &'static str, _: usize, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_map<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let _ = name;
let mut field_map = fields.iter().copied().map(|n| {
(n, None::<crate::vm::SerdeObject<'de>>)
}).collect::<HashMap<&'static str, Option<_>>>();
// unroll packs
while let Some(pack) = self.take_next_pack() {
self.packs.push(pack);
}
// roll them back up
'roll: while let Some(pack) = self.packs.pop() {
let (ref entries, _) = pack.subpacks[0];
for key in entries.keys().copied() {
if field_map.contains_key(key) {
self.packs.push(pack);
break 'roll;
}
}
match self.packs.last_mut().map(|x| &mut x.subpacks[0]) {
Some((_, subpack)) => {
*subpack = pack;
},
None => todo!(),
}
}
for pack in self.packs.iter() {
let (ref entries, _) = pack.subpacks[0];
for (key, value) in entries.iter() {
if let Some(entry) = field_map.get_mut(*key) {
*entry = Some(value.clone());
}
}
}
visitor.visit_map(UnpackerFields {
unpacker: self,
fields: field_map.into_iter(),
value: None,
})
}
fn deserialize_enum<V>(self, _: &'static str, _: &'static [&'static str], _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_identifier<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_ignored_any<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
}
impl<'pat, 'de> serde::Deserializer<'de> for Unpacker<'pat, 'de> {
type Error = UnpackError;
fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_bool<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_i8<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_i16<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_i32<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_i64<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_u8<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_u16<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_u32<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_u64<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_f32<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_f64<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_char<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_str<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_string<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_bytes<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_option<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_unit<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_unit_struct<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_newtype_struct<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_seq(self)
}
fn deserialize_tuple<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_tuple_struct<V>(self, _: &'static str, _: usize, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_map<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
todo!()
}
fn deserialize_enum<V>(self, _: &'static str, _: &'static [&'static str], _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_identifier<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
fn deserialize_ignored_any<V>(self, _: V) -> Result<V::Value, Self::Error> where V: serde::de::Visitor<'de> { todo!() }
}
//#[cfg(test)]
//mod tests {
// use serde::Deserialize;
// use crate::vm::MAX_CALLS;
//
// /// Mock struct for repo options.
// #[derive(Deserialize)]
// #[derive(Debug, PartialEq, Eq)]
// struct Options {
// active: bool,
// federate: Option<bool>,
// pinned: Option<bool>,
// }
//
// /// Mock struct for a project branch.
// #[derive(Deserialize)]
// #[derive(Debug, PartialEq, Eq)]
// struct ProjectBranch {
// /// The project commit.
// commit: String,
// /// The URL to the repo.
// url: String,
// /// The relevant branch.
// branch: String,
// /// Branch options.
// options: Options,
// }
//
// fn get_real_data() -> crate::vm::Pack<'static, 'static> {
// use indexmap::indexmap;
// use crate::vm::Pack;
// use crate::vm::SerdeObject;
// use crate::vm::SerdeObject::*;
//
// fn mkstr<'a>(s: &'a str) -> SerdeObject<'a> {
// SerdeObject::Str(s.into())
// }
//
// Pack {
// subpacks: vec![
// indexmap!{
// "commit" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "url" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "branch" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "active" => (
// Pack {
// subpacks: vec![].into(),
// },
// Bool(
// true,
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "HEAD",
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "https://github.com/ganarchy/GAnarchy",
// ),
// ),
// },
// indexmap!{
// "url" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "branch" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "pinned" => (
// Pack {
// subpacks: vec![].into(),
// },
// Bool(
// true,
// ),
// ),
// "active" => (
// Pack {
// subpacks: vec![].into(),
// },
// Bool(
// true,
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "HEAD",
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "https://soniex2.autistic.space/git-repos/ganarchy.git",
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "385e734a52e13949a7a5c71827f6de920dbfea43",
// ),
// ),
// },
// indexmap!{
// "commit" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "url" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "branch" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "pinned" => (
// Pack {
// subpacks: vec![].into(),
// },
// Bool(
// true,
// ),
// ),
// "active" => (
// Pack {
// subpacks: vec![].into(),
// },
// Bool(
// true,
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "HEAD",
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "https://soniex2.autistic.space/git-repos/mmorfc.git",
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "a8fb5087f79eafe312db270082c052c427b208c2",
// ),
// ),
// },
// indexmap!{
// "commit" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "url" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "branch" => (
// Pack {
// subpacks: vec![
// indexmap!{
// "pinned" => (
// Pack {
// subpacks: vec![].into(),
// },
// Bool(
// true,
// ),
// ),
// "active" => (
// Pack {
// subpacks: vec![].into(),
// },
// Bool(
// true,
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "HEAD",
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "https://soniex2.autistic.space/git-repos/chewstuff.git",
// ),
// ),
// },
// ].into(),
// },
// mkstr(
// "2d0b363fe3179087de59d9ef4a2d14af21d89071",
// ),
// ),
// },
// ].into(),
// }
// }
//
// #[test]
// fn to_vec_of_struct() {
// let der = super::Unpacker::new(get_real_data(), MAX_CALLS);
// let res: Vec<ProjectBranch> = Deserialize::deserialize(der).unwrap();
// assert_eq!(res, [
// ProjectBranch {
// commit: "385e734a52e13949a7a5c71827f6de920dbfea43".into(),
// url: "https://github.com/ganarchy/GAnarchy".into(),
// branch: "HEAD".into(),
// options: Options {
// active: true,
// federate: None,
// pinned: None,
// },
// },
// ProjectBranch {
// commit: "385e734a52e13949a7a5c71827f6de920dbfea43".into(),
// url: "https://soniex2.autistic.space/git-repos/ganarchy.git".into(),
// branch: "HEAD".into(),
// options: Options {
// active: true,
// federate: None,
// pinned: Some(true),
// },
// },
// ProjectBranch {
// commit: "a8fb5087f79eafe312db270082c052c427b208c2".into(),
// url: "https://soniex2.autistic.space/git-repos/mmorfc.git".into(),
// branch: "HEAD".into(),
// options: Options {
// active: true,
// federate: None,
// pinned: Some(true),
// },
// },
// ProjectBranch {
// commit: "2d0b363fe3179087de59d9ef4a2d14af21d89071".into(),
// url: "https://soniex2.autistic.space/git-repos/chewstuff.git".into(),
// branch: "HEAD".into(),
// options: Options {
// active: true,
// federate: None,
// pinned: Some(true),
// },
// },
// ]);
// }
//}