serde_magnus 0.1.1

Serde integration for Magnus
Documentation
use super::Deserializer;
use crate::error::Error;
use magnus::{exception, Enumerator, RArray, RHash};
use serde::de::{DeserializeSeed, MapAccess};
use std::iter::Peekable;

pub struct HashDeserializer {
    hash: RHash,
    keys: Peekable<Enumerator>,
}

impl HashDeserializer {
    pub fn new(hash: RHash) -> Result<HashDeserializer, Error> {
        hash.funcall("keys", ())
            .map(|keys: RArray| HashDeserializer {
                hash,
                keys: keys.each().peekable(),
            })
            .map_err(Into::into)
    }
}

impl<'i> MapAccess<'i> for HashDeserializer {
    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(key)).map(Some),

            Some(Err(error)) => Err(Error::new(
                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.hash.aref(key)?)),
            Some(Err(error)) => Err(error.into()),
            None => Err(Error::new(exception::index_error(), "index out of range")),
        }
    }
}