使用config-rs将TOML字符串反序列化为枚举

时间:2017-12-13 04:55:17

标签: rust serde toml

我正在使用config-rs从TOML文件加载配置,我想将字符串反序列化为枚举。我尝试使用serde_derive的var stripecard = "cus_BwS21a7fAH22uk"; StripeCustomer customer; StripeConfiguration.SetApiKey(ConfigurationManager.AppSettings["StripeApiKey"].ToString()); var customerService = new StripeCustomerService(); customer = customerService.Get(stripecard); ViewBag.last4card = customer.Sources.Data[0].Card.Last4.ToString(); ViewBag.ExpMonth = customer.Sources.Data[0].Card.ExpirationMonth.ToString(); ViewBag.ExpYear = customer.Sources.Data[0].Card.ExpirationYear.ToString(); ViewBag.Name = customer.Sources.Data[0].Card.Name.ToString(); 功能解决它,但我不知道如何返回合适的Error来满足函数签名。我怎样才能实现它?

我的依赖项:

deserialize_with

用于反序列化枚举config = "0.7" serde_derive = "1.0" serde = "1.0" toml = "0.4" 的示例代码:

RotationPolicyType

deserialize_with 编译错误:

extern crate config;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::env;
use config::{Config, Environment, File};
use std::path::PathBuf;
use serde;
use serde::de::Deserializer;
use serde::Deserialize;

#[derive(Debug, Deserialize, Clone)]
pub enum RotationPolicyType {
    ByDuration,
    ByDay,
}

#[derive(Debug, Deserialize, Clone)]
pub struct FileConfig {
    pub rotations: i32,
    #[serde(deserialize_with="deserialize_with")]
    pub rotation_policy_type: RotationPolicyType,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Settings {
    pub threads: usize,
    pub file_writer: FileConfig,
}

impl Settings {
    pub fn new() -> Self {
        let mut s = Config::new();
        s.merge(File::with_name("config/default")).unwrap();
        s.merge(File::with_name("config/local").required(false))
            .unwrap();
        s.merge(Environment::with_prefix("app")).unwrap();
        s.deserialize().unwrap()
    }
}


fn deserialize_with<D>(deserializer: D) -> Result<RotationPolicyType, D::Error> where D: Deserializer {
    let s = String::deserialize(deserializer)?;

    match s.as_ref() {
        "ByDuration" => Ok(RotationPolicyType::ByDuration),
        "ByDay" => Ok(RotationPolicyType::ByDay),
        _ => Err(serde::de::Error::custom("error trying to deserialize rotation policy config"))
    }
}



fn deserialize_with2<'de, D>(deserializer: &'de mut D) -> Result<RotationPolicyType, D::Error> where &'de mut D: Deserializer<'de> {
    let s = String::deserialize(deserializer)?;

    match s.as_ref() {
        "ByDuration" => Ok(RotationPolicyType::ByDuration),
        "ByDay" => Ok(RotationPolicyType::ByDay),
        _ => Err(serde::de::Error::custom("error trying to deserialize rotation policy config"))
    }
}

deserialize_with2 的编译错误:

error[E0106]: missing lifetime specifier
  --> src/settings.rs:30:94
   |
30 |     fn deserialize_with<D>(deserializer: D) -> Result<RotationPolicyType, D::Error> where D: Deserializer {
   |                                                                                              ^^^^^^^^^^^^ expected lifetime parameter

error: aborting due to previous error

2 个答案:

答案 0 :(得分:3)

首先,您的示例编译得不够远,无法解决您所描述的错误。请注意下次生成MCVE。要让它在https://play.rust-lang.org上运行的加分点(可能,extern crate config在您的示例中完全没有必要)。

修复所有编译问题后,只需修改功能API以匹配建议的in the serde docs

即可解决您的第一个错误
-fn deserialize_with<     D>(deserializer: D) -> Result<RotationPolicyType, D::Error> where D: Deserializer
+fn deserialize_with<'de, D>(deserializer: D) -> Result<RotationPolicyType, D::Error> where D: Deserializer<'de>

错误试图帮助你。它告诉你Deserializer缺少一个生命周期参数。

第二个功能是告诉您D没有关联的类型Error。只有在D实施Deserializer<'de>时才能使用。但是您指定&'de mut D实现Deserializer<'de>。寻找这个问题的解决方案留给读者练习。

答案 1 :(得分:1)

根据@ oli-obk-ker的建议,解决方案非常简单:

use std::env;
use config::{Config, File, Environment};
use std::path::PathBuf;
use serde;
use serde::de::Deserializer;
use serde::Deserialize;

pub trait DeserializeWith: Sized {
    fn deserialize_with<'de, D>(de: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>;
}

#[derive(Debug, Deserialize, Eq, PartialEq, Clone)]
pub enum RotationPolicyType {
    ByDuration,
    ByDay
}

impl DeserializeWith for RotationPolicyType {
    fn deserialize_with<'de, D>(de: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
        let s = String::deserialize(de)?;

        match s.as_ref() {
            "ByDuration" => Ok(RotationPolicyType::ByDuration),
            "ByDay" => Ok(RotationPolicyType::ByDay),
            _ => Err(serde::de::Error::custom("error trying to deserialize rotation policy config"))
        }
    }
}

#[derive(Debug, Deserialize, Clone)]
pub struct FileConfig {
    pub rotations: i32,
    #[serde(deserialize_with="RotationPolicyType::deserialize_with")]
    pub rotation_policy_type: RotationPolicyType,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Settings {
    pub threads: i32,
    pub file_writer: FileConfig,
}

impl Settings {
    pub fn new() -> Self {
        let mut s = Config::new();
        s.merge(File::with_name("config/default")).unwrap();
        s.merge(File::with_name("config/local").required(false)).unwrap();
        s.merge(Environment::with_prefix("app")).unwrap();
        s.deserialize().unwrap()
    }
}