serde_magnus 0.11.0

Serde integration for Magnus
Documentation
use super::{array_enumerator::ArrayEnumerator, Deserializer};
use crate::error::Error;
use magnus::{value::ReprValue, RHash, Ruby};
use serde::de::{DeserializeSeed, MapAccess};
use std::iter::Peekable;

pub struct HashDeserializer<'r> {
    ruby: &'r Ruby,
    hash: RHash,
    keys: Peekable<ArrayEnumerator<'r>>,
}

impl<'r> HashDeserializer<'r> {
    pub fn new(ruby: &'r Ruby, hash: RHash) -> Result<HashDeserializer<'r>, Error> {
        Ok(HashDeserializer {
            ruby,
            hash,
            keys: ArrayEnumerator::new(ruby, hash.funcall("keys", ())?).peekable(),
        })
    }
}

impl<'r, 'i> MapAccess<'i> for HashDeserializer<'r> {
    type Error = Error;

    fn next_key_seed<Seed>(&mut self, seed: Seed) -> Result<Option<Seed::Value>, Self::Error>
    where
        Seed: DeserializeSeed<'i>,
    {
        match self.keys.peek() {
            Some(&Ok(key)) => seed
                .deserialize(Deserializer::new(self.ruby, key))
                .map(Some),

            Some(Err(error)) => Err(Error::new(
                self.ruby.exception_runtime_error(),
                format!("encountered unexpected error: {}", error),
            )),

            None => Ok(None),
        }
    }

    fn next_value_seed<Seed>(&mut self, seed: Seed) -> Result<Seed::Value, Self::Error>
    where
        Seed: DeserializeSeed<'i>,
    {
        match self.keys.next() {
            Some(Ok(key)) => seed.deserialize(Deserializer::new(self.ruby, self.hash.aref(key)?)),
            Some(Err(error)) => Err(error.into()),
            None => Err(Error::new(
                self.ruby.exception_index_error(),
                "index out of range",
            )),
        }
    }
}