use std::{
any::Any,
borrow::Cow,
ffi::OsStr,
rc::Rc,
sync::Arc,
};
use crate::{
Configuration,
internal::{
ChangeVerb, CongenChange, CongenDefault, CongenInternal, Description, NotSupported,
ParseError, VerbError,
},
};
#[derive(Debug, Clone, Default)]
pub struct BoxChange<C>(pub C);
#[derive(Debug, Clone, Default)]
pub struct ArcChange<C>(pub C);
#[derive(Debug, Clone, Default)]
pub struct RcChange<C>(pub C);
impl<T> Configuration for Box<T>
where
T: Configuration + 'static,
{
}
impl<T> CongenInternal for Box<T>
where
T: Configuration + 'static,
{
type CongenChange = BoxChange<T::CongenChange>;
fn apply_change_with_inner_default(
&mut self,
change: Self::CongenChange,
inner_default: Option<fn() -> Box<dyn Any>>,
) {
self.as_mut()
.apply_change_with_inner_default(change.0, inner_default);
}
fn description(field_name: &'static str) -> Description {
T::description(field_name)
}
fn default() -> Result<Self, NotSupported> {
Ok(Box::new(T::default()?))
}
fn type_name() -> Cow<'static, str> {
T::type_name()
}
}
impl<T> CongenDefault for Box<T>
where
T: CongenDefault + Configuration + 'static,
{
}
impl<C, T> CongenChange for BoxChange<C>
where
C: CongenChange<Configuration = T>,
T: Configuration + 'static,
{
type Configuration = Box<T>;
fn empty() -> Self {
Self(C::empty())
}
fn default() -> Result<Self, NotSupported> {
Ok(Self(C::default()?))
}
fn parse(input: &OsStr) -> Result<Result<Self, ParseError>, NotSupported> {
C::parse(input).map(|parsed| parsed.map(Self))
}
fn apply_change(&mut self, change: Self) {
self.0.apply_change(change.0);
}
fn from_path_and_verb<'a, P>(path: P, verb: ChangeVerb) -> Result<Self, VerbError>
where
P: Iterator<Item = &'a str>,
{
C::from_path_and_verb(path, verb).map(Self)
}
fn unwrap_field(self) -> Result<Self::Configuration, Self> {
match self.0.unwrap_field() {
Ok(unwrapped) => Ok(Box::new(unwrapped)),
Err(change) => Err(Self(change)),
}
}
}
impl<T> Configuration for Arc<T>
where
T: Configuration + 'static,
{
}
impl<T> CongenInternal for Arc<T>
where
T: Configuration + 'static,
{
type CongenChange = ArcChange<T::CongenChange>;
fn apply_change_with_inner_default(
&mut self,
change: Self::CongenChange,
inner_default: Option<fn() -> Box<dyn Any>>,
) {
let this = Arc::get_mut(self).expect(
"called apply_change_with_inner_default on Arc<T> with multiple strong references",
);
this.apply_change_with_inner_default(change.0, inner_default);
}
fn description(field_name: &'static str) -> Description {
T::description(field_name)
}
fn default() -> Result<Self, NotSupported> {
Ok(Arc::new(T::default()?))
}
fn type_name() -> Cow<'static, str> {
T::type_name()
}
}
impl<T> CongenDefault for Arc<T>
where
T: CongenDefault + Configuration + 'static,
{
}
impl<C, T> CongenChange for ArcChange<C>
where
C: CongenChange<Configuration = T>,
T: Configuration + 'static,
{
type Configuration = Arc<T>;
fn empty() -> Self {
Self(C::empty())
}
fn default() -> Result<Self, NotSupported> {
Ok(Self(C::default()?))
}
fn parse(input: &OsStr) -> Result<Result<Self, ParseError>, NotSupported> {
C::parse(input).map(|parsed| parsed.map(Self))
}
fn apply_change(&mut self, change: Self) {
self.0.apply_change(change.0);
}
fn from_path_and_verb<'a, P>(path: P, verb: ChangeVerb) -> Result<Self, VerbError>
where
P: Iterator<Item = &'a str>,
{
C::from_path_and_verb(path, verb).map(Self)
}
fn unwrap_field(self) -> Result<Self::Configuration, Self> {
match self.0.unwrap_field() {
Ok(unwrapped) => Ok(Arc::new(unwrapped)),
Err(change) => Err(Self(change)),
}
}
}
impl<T> Configuration for Rc<T>
where
T: Configuration + 'static,
{
}
impl<T> CongenInternal for Rc<T>
where
T: Configuration + 'static,
{
type CongenChange = RcChange<T::CongenChange>;
fn apply_change_with_inner_default(
&mut self,
change: Self::CongenChange,
inner_default: Option<fn() -> Box<dyn Any>>,
) {
let this = Rc::get_mut(self)
.expect("called apply_change_with_inner_default on Rc<T> with multiple references");
this.apply_change_with_inner_default(change.0, inner_default);
}
fn description(field_name: &'static str) -> Description {
T::description(field_name)
}
fn default() -> Result<Self, NotSupported> {
Ok(Rc::new(T::default()?))
}
fn type_name() -> Cow<'static, str> {
T::type_name()
}
}
impl<T> CongenDefault for Rc<T>
where
T: CongenDefault + Configuration + 'static,
{
}
impl<C, T> CongenChange for RcChange<C>
where
C: CongenChange<Configuration = T>,
T: Configuration + 'static,
{
type Configuration = Rc<T>;
fn empty() -> Self {
Self(C::empty())
}
fn default() -> Result<Self, NotSupported> {
Ok(Self(C::default()?))
}
fn parse(input: &OsStr) -> Result<Result<Self, ParseError>, NotSupported> {
C::parse(input).map(|parsed| parsed.map(Self))
}
fn apply_change(&mut self, change: Self) {
self.0.apply_change(change.0);
}
fn from_path_and_verb<'a, P>(path: P, verb: ChangeVerb) -> Result<Self, VerbError>
where
P: Iterator<Item = &'a str>,
{
C::from_path_and_verb(path, verb).map(Self)
}
fn unwrap_field(self) -> Result<Self::Configuration, Self> {
match self.0.unwrap_field() {
Ok(unwrapped) => Ok(Rc::new(unwrapped)),
Err(change) => Err(Self(change)),
}
}
}
#[cfg(test)]
mod tests {
extern crate self as congen;
use std::{ffi::OsString, rc::Rc, sync::Arc};
use crate::{
Configuration,
internal::{ChangeVerb, CongenChange, CongenInternal},
};
#[derive(Configuration, Debug)]
struct Inner {
value: u32,
#[congen(default)]
maybe: Option<u32>,
}
#[derive(Configuration, Debug)]
struct Wrapped {
plain: Inner,
boxed: Box<Inner>,
arc: Arc<Inner>,
rc: Rc<Inner>,
plain_num: u32,
boxed_num: Box<u32>,
arc_num: Arc<u32>,
rc_num: Rc<u32>,
}
fn base_config() -> Wrapped {
Wrapped {
plain: Inner {
value: 1,
maybe: Some(10),
},
boxed: Box::new(Inner {
value: 2,
maybe: Some(10),
}),
arc: Arc::new(Inner {
value: 3,
maybe: Some(10),
}),
rc: Rc::new(Inner {
value: 4,
maybe: Some(10),
}),
plain_num: 5,
boxed_num: Box::new(6),
arc_num: Arc::new(7),
rc_num: Rc::new(8),
}
}
fn apply_change(config: &mut Wrapped, path: &[&str], verb: ChangeVerb) {
type Change = <Wrapped as CongenInternal>::CongenChange;
let change = <Change as CongenChange>::from_path_and_verb(path.iter().copied(), verb)
.expect("create change");
config.apply_change(change);
}
#[test]
fn wrappers_support_nested_changes_like_inner_type() {
let mut config = base_config();
apply_change(
&mut config,
&["plain", "value"],
ChangeVerb::Set(OsString::from("11")),
);
apply_change(
&mut config,
&["boxed", "value"],
ChangeVerb::Set(OsString::from("12")),
);
apply_change(
&mut config,
&["arc", "value"],
ChangeVerb::Set(OsString::from("13")),
);
apply_change(
&mut config,
&["rc", "value"],
ChangeVerb::Set(OsString::from("14")),
);
assert_eq!(config.plain.value, 11);
assert_eq!(config.boxed.value, 12);
assert_eq!(config.arc.value, 13);
assert_eq!(config.rc.value, 14);
}
#[test]
fn wrappers_support_use_default_like_inner_type() {
let mut config = base_config();
apply_change(&mut config, &["plain", "maybe"], ChangeVerb::UseDefault);
apply_change(&mut config, &["boxed", "maybe"], ChangeVerb::UseDefault);
apply_change(&mut config, &["arc", "maybe"], ChangeVerb::UseDefault);
apply_change(&mut config, &["rc", "maybe"], ChangeVerb::UseDefault);
assert!(config.plain.maybe.is_none());
assert!(config.boxed.maybe.is_none());
assert!(config.arc.maybe.is_none());
assert!(config.rc.maybe.is_none());
}
#[test]
fn wrappers_support_field_set_like_inner_type() {
let mut config = base_config();
apply_change(
&mut config,
&["plain_num"],
ChangeVerb::Set(OsString::from("15")),
);
apply_change(
&mut config,
&["boxed_num"],
ChangeVerb::Set(OsString::from("16")),
);
apply_change(
&mut config,
&["arc_num"],
ChangeVerb::Set(OsString::from("17")),
);
apply_change(
&mut config,
&["rc_num"],
ChangeVerb::Set(OsString::from("18")),
);
assert_eq!(config.plain_num, 15);
assert_eq!(*config.boxed_num, 16);
assert_eq!(*config.arc_num, 17);
assert_eq!(*config.rc_num, 18);
}
}