#[macro_export]
macro_rules! impl_request_has_field {
(
$type:ty,
$wrapper:ident,
$wrapper_field:ident,
$(
$trait:ident, $method:ident, &$ret:ty, $field:ident;
)+
) => {
$(
impl $trait for $type {
fn $method(
&self,
) -> ::std::result::Result<&$ret, $crate::RequestFieldAccessError> {
Ok(&self.$field)
}
}
impl<T> $trait for $wrapper<T> {
fn $method(
&self,
) -> ::std::result::Result<&$ret, $crate::RequestFieldAccessError> {
self.$wrapper_field.$method()
}
}
)+
};
(
$type:ty,
$wrapper:ident,
$wrapper_field:ident,
$(
$trait:ident, $method:ident, $ret:ty, $field:ident;
)+
) => {
$(
impl $trait for $type {
fn $method(
&self,
) -> ::std::result::Result<$ret, $crate::RequestFieldAccessError> {
Ok(self.$field.clone())
}
}
impl<T> $trait for $wrapper<T> {
fn $method(
&self,
) -> ::std::result::Result<$ret, $crate::RequestFieldAccessError> {
self.$wrapper_field.$method()
}
}
)+
};
}
#[macro_export]
macro_rules! impl_request_has_field_passthrough {
(
$wrapper:ident,
$inner_field:ident,
$(
$trait:ident, $method:ident, &$ret:ty;
)+
) => {
$(
impl<T> $trait for $wrapper<T>
where
T: $trait,
{
fn $method(
&self,
) -> ::std::result::Result<&$ret, $crate::RequestFieldAccessError> {
self.$inner_field.$method()
}
}
)+
};
(
$wrapper:ident,
$inner_field:ident,
$(
$trait:ident, $method:ident, $ret:ty;
)+
) => {
$(
impl<T> $trait for $wrapper<T>
where
T: $trait,
{
fn $method(
&self,
) -> ::std::result::Result<$ret, $crate::RequestFieldAccessError> {
self.$inner_field.$method()
}
}
)+
};
}
#[cfg(test)]
mod tests {
use crate::RequestFieldAccessError;
trait HasNameRef {
fn name_ref(&self) -> Result<&str, RequestFieldAccessError>;
}
trait HasCount {
fn count(&self) -> Result<u32, RequestFieldAccessError>;
}
#[derive(Clone)]
struct Base {
name: String,
count: u32,
}
struct WithBase<T> {
#[allow(dead_code)]
inner: T,
base: Base,
}
crate::impl_request_has_field!(
Base,
WithBase,
base,
HasNameRef, name_ref, &str, name;
);
crate::impl_request_has_field!(
Base,
WithBase,
base,
HasCount, count, u32, count;
);
trait HasInnerNameRef {
fn inner_name_ref(&self) -> Result<&str, RequestFieldAccessError>;
}
trait HasInnerCount {
fn inner_count(&self) -> Result<u32, RequestFieldAccessError>;
}
struct InnerCaps {
name: String,
count: u32,
}
impl HasInnerNameRef for InnerCaps {
fn inner_name_ref(&self) -> Result<&str, RequestFieldAccessError> {
Ok(self.name.as_str())
}
}
impl HasInnerCount for InnerCaps {
fn inner_count(&self) -> Result<u32, RequestFieldAccessError> {
Ok(self.count)
}
}
struct Wrapper<T> {
inner: T,
}
crate::impl_request_has_field_passthrough!(
Wrapper,
inner,
HasInnerNameRef, inner_name_ref, &str;
);
crate::impl_request_has_field_passthrough!(
Wrapper,
inner,
HasInnerCount, inner_count, u32;
);
#[test]
fn impl_request_has_field_generates_ref_and_owned_accessors() {
let base = Base {
name: "alpha".to_string(),
count: 7,
};
assert_eq!(base.name_ref(), Ok("alpha"));
assert_eq!(base.count(), Ok(7));
let wrapped = WithBase {
inner: (),
base: base.clone(),
};
assert_eq!(wrapped.name_ref(), Ok("alpha"));
assert_eq!(wrapped.count(), Ok(7));
}
#[test]
fn impl_request_has_field_passthrough_delegates_for_ref_and_owned_forms() {
let wrapped = Wrapper {
inner: InnerCaps {
name: "beta".to_string(),
count: 11,
},
};
assert_eq!(wrapped.inner_name_ref(), Ok("beta"));
assert_eq!(wrapped.inner_count(), Ok(11));
}
}