Skip to content

Commit

Permalink
Merge pull request #106 from tyranron/60-fix-defaults
Browse files Browse the repository at this point in the history
Fix defaults serialization and 'invalid type: unit value' deserialization error (#60)
  • Loading branch information
mehcode authored May 9, 2019
2 parents 2502fbc + a1eecd0 commit c03fd36
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 3 deletions.
39 changes: 36 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ser::ConfigSerializer;
use source::Source;

use path;
use value::{Value, ValueKind, ValueWithKey};
use value::{Table, Value, ValueKind, ValueWithKey};

#[derive(Clone, Debug)]
enum ConfigKind {
Expand Down Expand Up @@ -49,7 +49,12 @@ pub struct Config {

impl Config {
pub fn new() -> Self {
Config::default()
Self {
kind: ConfigKind::default(),
// Config root should be instantiated as an empty table
// to avoid deserialization errors.
cache: Value::new(None, Table::new()),
}
}

/// Merge in a configuration property source.
Expand Down Expand Up @@ -129,6 +134,26 @@ impl Config {
self.refresh()
}

/// Set the configuration defaults by serializing them from given value.
pub fn set_defaults<T>(&mut self, value: &T) -> Result<&mut Config>
where
T: Serialize,
{
match self.kind {
ConfigKind::Mutable {
ref mut defaults, ..
} => {
for (key, val) in Self::try_from(&value)?.collect()? {
defaults.insert(key.parse()?, val);
}
}

ConfigKind::Frozen => return Err(ConfigError::Frozen),
}

self.refresh()
}

pub fn set<T>(&mut self, key: &str, value: T) -> Result<&mut Config>
where
T: Into<Value>,
Expand Down Expand Up @@ -192,13 +217,21 @@ impl Config {
T::deserialize(self)
}

/// Attempt to deserialize the entire configuration into the requested type.
/// Attempt to serialize the entire configuration from the given type.
pub fn try_from<T: Serialize>(from: &T) -> Result<Self> {
let mut serializer = ConfigSerializer::default();
from.serialize(&mut serializer)?;
Ok(serializer.output)
}

/// Attempt to serialize the entire configuration from the given type
/// as default values.
pub fn try_defaults_from<T: Serialize>(from: &T) -> Result<Self> {
let mut c = Self::new();
c.set_defaults(from)?;
Ok(c)
}

#[deprecated(since = "0.7.0", note = "please use 'try_into' instead")]
pub fn deserialize<'de, T: Deserialize<'de>>(self) -> Result<T> {
self.try_into()
Expand Down
36 changes: 36 additions & 0 deletions tests/defaults.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
extern crate config;

#[macro_use]
extern crate serde_derive;

use config::*;

#[derive(Debug, Serialize, Deserialize)]
pub struct Settings {
pub db_host: String,
}

impl Default for Settings {
fn default() -> Self {
Settings {
db_host: String::from("default"),
}
}
}

#[test]
fn set_defaults() {
let mut c = Config::new();
c.set_defaults(&Settings::default())
.expect("Setting defaults failed");
let s: Settings = c.try_into().expect("Deserialization failed");

assert_eq!(s.db_host, "default");
}

#[test]
fn try_from_defaults() {
let c = Config::try_from(&Settings::default()).expect("Serialization failed");
let s: Settings = c.try_into().expect("Deserialization failed");
assert_eq!(s.db_host, "default");
}
21 changes: 21 additions & 0 deletions tests/empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
extern crate config;

#[macro_use]
extern crate serde_derive;

use config::*;

#[derive(Debug, Serialize, Deserialize)]
struct Settings {
#[serde(skip)]
foo: isize,
#[serde(skip)]
bar: u8,
}

#[test]
fn empty_deserializes() {
let s: Settings = Config::new().try_into().expect("Deserialization failed");
assert_eq!(s.foo, 0);
assert_eq!(s.bar, 0);
}

0 comments on commit c03fd36

Please sign in to comment.