serde icon indicating copy to clipboard operation
serde copied to clipboard

Can't find a way to repeat value

Open zoryamba opened this issue 2 years ago • 1 comments

Hi everyone. Have to say, that I'm pretty new to Rust, so my question may be quite amateur. I'm trying to implement serde for zipson format. You can find details here: https://www.npmjs.com/package/zipson There is repeat feature, þ char means repeat last item. So that |¨aaa¨þþ÷ should be parsed as ["aaa", "aaa", "aaa"].

The most obvious way is to make it in SeqAccess implementation, so i desided to store last_elem ref in my SeqAccess and return it in case I see þ char.

struct SeqAccess<'a, 'de: 'a> {
    de: &'a mut Deserializer<'de>,
    last_element: Value,
}

impl<'a, 'de: 'a> SeqAccess<'a, 'de> {
    fn new(de: &'a mut Deserializer<'de>) -> Self {
        SeqAccess {
            de,
            last_element: Value::Undefined
        }
    }
}

impl<'de, 'a> de::SeqAccess<'de> for SeqAccess<'a, 'de> {
    type Error = Error;

    fn next_element_seed<T>(&mut self, seed: T) -> std::result::Result<Option<T::Value>, Self::Error>
        where T: DeserializeSeed<'de>
    {
        match self.de.peek_char()? {
            ARRAY_END_TOKEN => {
                self.de.next_char()?;
                Ok(None)
            }
            ARRAY_REPEAT_TOKEN => {
                self.de.next_char()?;
                Ok(Some(self.last_element.clone()))
            }
            _ => Ok(Some(seed.deserialize(&mut *self.de)?))
        }
    }
}

Unfortunately I'm getting compillation error:

error[E0308]: mismatched types
   --> src/de.rs:661:25
    |
661 |                 Ok(Some(self.last_element.clone()))
    |                    ---- ^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `Value`
    |                    |
    |                    arguments to this enum variant are incorrect
    |
    = note: expected associated type `<T as DeserializeSeed<'de>>::Value`
                          found enum `Value`
help: the type constructed contains `Value` due to the type of the argument passed
   --> src/de.rs:661:20
    |
661 |                 Ok(Some(self.last_element.clone()))
    |                    ^^^^^-------------------------^
    |                         |
    |                         this argument influences the type of `Some`
note: tuple variant defined here
   --> /Users/zoryamba/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:571:5
    |
571 |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    |     ^^^^
help: consider constraining the associated type `<T as DeserializeSeed<'de>>::Value` to `Value`
    |
652 |         where T: DeserializeSeed<'de, Value = Value>
    |                                     +++++++++++++++

Tried to constrain Value for DeserializeSeed:

    fn next_element_seed<T>(&mut self, seed: T) -> std::result::Result<Option<T::Value>, Self::Error>
        where T: DeserializeSeed<'de, Value = Value>

It also didn't help:

error[E0271]: type mismatch resolving `<T as DeserializeSeed<'de>>::Value == Value`
    --> src/de.rs:652:39
     |
652  |         where T: DeserializeSeed<'de, Value = Value>
     |                                       ^^^^^^^^^^^^^ expected associated type, found `Value`
     |
     = note: expected associated type `<T as DeserializeSeed<'de>>::Value`
                           found enum `Value`
note: the requirement `<T as DeserializeSeed<'de>>::Value == Value` appears on the `impl`'s method `next_element_seed` but not on the corresponding trait's method
    --> /Users/zoryamba/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.188/src/de/mod.rs:1712:8
     |
1702 | pub trait SeqAccess<'de> {
     |           --------- in this trait
...
1712 |     fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
     |        ^^^^^^^^^^^^^^^^^ this trait's method doesn't have the requirement `<T as DeserializeSeed<'de>>::Value == Value`

I tried to implement own DeseriealizeSeed, but it's deserialize method requires Deserializer trait:

fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
        where D: de::Deserializer<'de>

So that i can't use my deserializer custom methods like next_char of peek_char.

So my question is: Is it possible to achieve what I want? And what is most convenient method to do that? Thank you!

zoryamba avatar Oct 16 '23 11:10 zoryamba

As I understand is SeqAccess trait was generic itself, it would be possible to do such a trick:

pub trait SeqAccess<'de, V> {
    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
    where
        T: DeserializeSeed<'de Value = V>;
}

struct SeqAccess<'a, 'de: 'a, V> {
    de: &'a mut Deserializer<'de>,
    last_element: V,
}

Wouldn't that be useful?

zoryamba avatar Oct 16 '23 11:10 zoryamba