Skip to content

Instantly share code, notes, and snippets.

@bearcage
Created July 3, 2020 01:46
Show Gist options
  • Select an option

  • Save bearcage/b00137eb479ef535f39ca6200c6b78ac to your computer and use it in GitHub Desktop.

Select an option

Save bearcage/b00137eb479ef535f39ca6200c6b78ac to your computer and use it in GitHub Desktop.
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
where
V: de::DeserializeSeed<'de>,
{
let field = &self.fields[self.field_index];
self.field_index += 1;
// Set this as the current key in the deserializer.
let field = match field {
KeyKind::Normal(field) => {
self.de.key.push(field);
field
}
KeyKind::CaseSensitive(field) => {
self.de.key.push_sensitive(field);
field
}
};
// Env vars that are a prefix of another with a dash/underscore cannot
// be supported by our serde implementation, so check for them here.
// Example:
// CARGO_BUILD_TARGET
// CARGO_BUILD_TARGET_DIR
// or
// CARGO_PROFILE_DEV_DEBUG
// CARGO_PROFILE_DEV_DEBUG_ASSERTIONS
// The `deserialize_option` method does not know the type of the field.
// If the type is an Option<struct> (like
// `profile.dev.build-override`), then it needs to check for env vars
// starting with CARGO_FOO_BAR_. This is a problem for keys like
// CARGO_BUILD_TARGET because checking for a prefix would incorrectly
// match CARGO_BUILD_TARGET_DIR. `deserialize_option` would have no
// choice but to call `visit_some()` which would then fail if
// CARGO_BUILD_TARGET isn't set. So we check for these prefixes and
// disallow them here.
let env_prefix = format!("{}_", field).replace('-', "_");
let env_prefix_ok = !self.fields.iter().any(|field| {
let field = match field {
KeyKind::Normal(s) | KeyKind::CaseSensitive(s) => s.as_str(),
};
field.replace('-', "_").starts_with(&env_prefix)
});
let result = seed.deserialize(Deserializer {
config: self.de.config,
key: self.de.key.clone(),
env_prefix_ok,
});
let result = result.map_err(|e| {
if format!("{}", e).contains("missing config key") {
println!("GOT TO A SAD PLACE {}:{}", file!(), line!());
use serde::de::Error;
let bad_idea = field.to_string().into_boxed_str();
ConfigError::missing_field(Box::leak(bad_idea))
} else {
e
}
});
self.de.key.pop();
result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment