serde: 在Rust中反序列化`str`

huangapple go评论57阅读模式
英文:

serde: Deserialize `str` in Rust

问题

The error message indicates that the Deserialize trait is not implemented for str, but it is implemented for &'a str. To address this issue without modifying TypePath in main.rs, you can provide a custom implementation of Deserialize for Cou<'a, str> in the cou.rs file. Here's a potential solution:

use serde::{Deserialize, Deserializer, Serialize};

#[derive(Serialize)]
pub enum Cou<'a, T>
where
    T: ToOwned + ?Sized,
{
    Borrowed(&'a T),
    Upgraded(std::sync::Arc<T::Owned>),
}

impl<'de> Deserialize<'de> for Cou<'de, str> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // Deserialize `&str` from the provided deserializer and create a `Cou::Borrowed`.
        let s: &'de str = Deserialize::deserialize(deserializer)?;
        Ok(Cou::Borrowed(s))
    }
}

This code provides a custom Deserialize implementation for Cou&lt;&#39;a, str&gt; by deserializing a &str and wrapping it in Cou::Borrowed. This way, you can handle the deserialization of str without modifying the main.rs code.

英文:

I am working on an existing codebase in Rust, wherein I need to serialize/deserialize a struct with a &lt;&#39;a, str&gt; type.

I am mentioning the minimal reproducible snippets here:

File: main.rs

use serde::{Deserialize, Serialize};

use crate::cou::Cou;

#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub struct TypePath&lt;&#39;a&gt;(Vec&lt;Cou&lt;&#39;a, str&gt;&gt;);

File: cou.rs

use std::{
    borrow::Borrow,
    sync::Arc,
};

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub enum Cou&lt;&#39;a, T&gt;
where
    T: ToOwned + ?Sized,
{
    Borrowed(&amp;&#39;a T),
    Upgraded(Arc&lt;T::Owned&gt;),
}

When I build the above, it gives an error:

error[E0277]: the trait bound `str: Deserialize&lt;&#39;_&gt;` is not satisfied
   --&gt; src/ast.rs:136:25
    |
136 | pub struct TypePath&lt;&#39;a&gt;(Vec&lt;Cou&lt;&#39;a, str&gt;&gt;);
    |                         ^^^ the trait `Deserialize&lt;&#39;_&gt;` is not implemented for `str`
    |
    = help: the trait `Deserialize&lt;&#39;de&gt;` is implemented for `&amp;&#39;a str`
note: required for `Cou&lt;&#39;a, str&gt;` to implement `Deserialize&lt;&#39;_&gt;`
   --&gt; src/cou.rs:11:21
    |
11  | #[derive(Serialize, Deserialize)]
    |                     ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
12  | pub enum Cou&lt;&#39;a, T&gt;
    |          ^^^^^^^^^^
    = note: 1 redundant requirement hidden
    = note: required for `Vec&lt;Cou&lt;&#39;a, str&gt;&gt;` to implement `Deserialize&lt;&#39;_&gt;`
    = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)

Now the output says that the trait is implemented for &amp;&#39;a str but I do not want to change TypePath in main.rs as it is used widely in the remainder of the codebase. Is it possible to define Deserialize for str?

答案1

得分: 2

CouCow具有相同的结构,因此您几乎可以从serde的实现中进行复制粘贴。

use std::{sync::Arc};
use std::borrow::Borrow;
use std::ops::Deref;

use serde::{Deserializer, Deserialize, Serializer, Serialize};

pub enum Cou<'a, T>
  where
    T: ToOwned + ?Sized,
{
  Borrowed(&'a T),
  Upgraded(Arc<T::Owned>),
}


impl<B: ?Sized + ToOwned> Deref for Cou<'_, B>
  where
    B::Owned: Borrow<B>,
{
  type Target = B;

  fn deref(&self) -> &B {
    match *self {
      Cou::Borrowed(borrowed) => borrowed.borrow(),
      Cou::Upgraded(ref owned) => owned.deref().borrow(),
    }
  }
}


impl<'a, T: ?Sized> Serialize for Cou<'a, T> where T: Serialize + ToOwned {
  #[inline]
  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
      S: Serializer,
  {
    (**self).serialize(serializer)
  }
}


impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cou<'a, T>
  where
    T: ToOwned,
    T::Owned: Deserialize<'de>,
{
  #[inline]
  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
      D: Deserializer<'de>,
  {
    T::Owned::deserialize(deserializer).map(Arc::new).map(Cou::Upgraded)
  }
}

Playground

英文:

Cou has the same structure as Cow, so you can almost copy-paste ser/de implementations from serde.

use std::{sync::Arc};
use std::borrow::Borrow;
use std::ops::Deref;

use serde::{Deserializer, Deserialize, Serializer, Serialize};

pub enum Cou&lt;&#39;a, T&gt;
  where
    T: ToOwned + ?Sized,
{
  Borrowed(&amp;&#39;a T),
  Upgraded(Arc&lt;T::Owned&gt;),
}


impl&lt;B: ?Sized + ToOwned&gt; Deref for Cou&lt;&#39;_, B&gt;
  where
    B::Owned: Borrow&lt;B&gt;,
{
  type Target = B;

  fn deref(&amp;self) -&gt; &amp;B {
    match *self {
      Cou::Borrowed(borrowed) =&gt; borrowed.borrow(),
      Cou::Upgraded(ref owned) =&gt; owned.deref().borrow(),
    }
  }
}


impl &lt;&#39;a, T: ?Sized&gt; Serialize for Cou&lt;&#39;a, T&gt; where T: Serialize + ToOwned {
  #[inline]
  fn serialize&lt;S&gt;(&amp;self, serializer: S) -&gt; Result&lt;S::Ok, S::Error&gt;
    where
      S: Serializer,
  {
    (**self).serialize(serializer)
  }
}


impl&lt;&#39;de, &#39;a, T: ?Sized&gt; Deserialize&lt;&#39;de&gt; for Cou&lt;&#39;a, T&gt;
  where
    T: ToOwned,
    T::Owned: Deserialize&lt;&#39;de&gt;,
{
  #[inline]
  fn deserialize&lt;D&gt;(deserializer: D) -&gt; Result&lt;Self, D::Error&gt;
    where
      D: Deserializer&lt;&#39;de&gt;,
  {
    T::Owned::deserialize(deserializer).map(Arc::new).map(Cou::Upgraded)
  }
}

Playground

huangapple
  • 本文由 发表于 2023年5月13日 14:58:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76241465.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定