use std::fmt;
use std::sync::Arc;
pub mod lock;
pub mod prelude;
pub use lock::{
ArcMutexAccess, ArcRwLockAccess, LockAccess, LockKp, LockKpType, RcRefCellAccess,
StdMutexAccess, StdRwLockAccess,
};
#[cfg(feature = "parking_lot")]
pub use lock::{
DirectParkingLotMutexAccess, DirectParkingLotRwLockAccess, ParkingLotMutexAccess,
ParkingLotRwLockAccess,
};
pub mod async_lock;
#[cfg(feature = "pin_project")]
pub mod pin;
pub trait KeyPathValueTarget {
type Target: Sized;
}
impl<T> KeyPathValueTarget for &T {
type Target = T;
}
impl<T> KeyPathValueTarget for &mut T {
type Target = T;
}
#[macro_export]
macro_rules! keypath {
{ $root:ident . $field:ident } => { $root::$field() };
{ $root:ident . $field:ident . $($ty:ident . $f:ident).+ } => {
$root::$field() $(.then($ty::$f()))+
};
($root:ident . $field:ident) => { $root::$field() };
($root:ident . $field:ident . $($ty:ident . $f:ident).+) => {
$root::$field() $(.then($ty::$f()))+
};
}
#[macro_export]
macro_rules! get_or {
($kp:expr, $root:expr, $default:expr) => {
$kp.get($root).unwrap_or($default)
};
($root:expr => $($path:tt)*, $default:expr) => {
$crate::get_or!($crate::keypath!($($path)*), $root, $default)
};
}
#[macro_export]
macro_rules! get_or_else {
($kp:expr, $root:expr, $closure:expr) => {
$kp.get($root).map(|r| r.clone()).unwrap_or_else($closure)
};
($root:expr => ($($path:tt)*), $closure:expr) => {
$crate::get_or_else!($crate::keypath!($($path)*), $root, $closure)
};
}
#[macro_export]
macro_rules! zip_with_kp {
($root:expr, $closure:expr => $kp1:expr, $kp2:expr) => {
match ($kp1.get($root), $kp2.get($root)) {
(Some(__a), Some(__b)) => Some($closure((__a, __b))),
_ => None,
}
};
($root:expr, $closure:expr => $kp1:expr, $kp2:expr, $kp3:expr) => {
match ($kp1.get($root), $kp2.get($root), $kp3.get($root)) {
(Some(__a), Some(__b), Some(__c)) => Some($closure((__a, __b, __c))),
_ => None,
}
};
($root:expr, $closure:expr => $kp1:expr, $kp2:expr, $kp3:expr, $kp4:expr) => {
match (
$kp1.get($root),
$kp2.get($root),
$kp3.get($root),
$kp4.get($root),
) {
(Some(__a), Some(__b), Some(__c), Some(__d)) => Some($closure((__a, __b, __c, __d))),
_ => None,
}
};
($root:expr, $closure:expr => $kp1:expr, $kp2:expr, $kp3:expr, $kp4:expr, $kp5:expr) => {
match (
$kp1.get($root),
$kp2.get($root),
$kp3.get($root),
$kp4.get($root),
$kp5.get($root),
) {
(Some(__a), Some(__b), Some(__c), Some(__d), Some(__e)) => {
Some($closure((__a, __b, __c, __d, __e)))
}
_ => None,
}
};
($root:expr, $closure:expr => $kp1:expr, $kp2:expr, $kp3:expr, $kp4:expr, $kp5:expr, $kp6:expr) => {
match (
$kp1.get($root),
$kp2.get($root),
$kp3.get($root),
$kp4.get($root),
$kp5.get($root),
$kp6.get($root),
) {
(Some(__a), Some(__b), Some(__c), Some(__d), Some(__e), Some(__f)) => {
Some($closure((__a, __b, __c, __d, __e, __f)))
}
_ => None,
}
};
}
pub type KpValue<'a, R, V> = Kp<
R,
V,
&'a R,
V, &'a mut R,
V, for<'b> fn(&'b R) -> Option<V>,
for<'b> fn(&'b mut R) -> Option<V>,
>;
pub type KpOwned<R, V> = Kp<
R,
V,
R,
V, R,
V, fn(R) -> Option<V>,
fn(R) -> Option<V>,
>;
pub type KpRoot<R> = Kp<
R,
R,
R,
R, R,
R, fn(R) -> Option<R>,
fn(R) -> Option<R>,
>;
pub type KpVoid = Kp<(), (), (), (), (), (), fn() -> Option<()>, fn() -> Option<()>>;
pub type KpDynamic<R, V> = Kp<
R,
V,
&'static R,
&'static V,
&'static mut R,
&'static mut V,
Box<dyn for<'a> Fn(&'a R) -> Option<&'a V> + Send + Sync>,
Box<dyn for<'a> Fn(&'a mut R) -> Option<&'a mut V> + Send + Sync>,
>;
pub type KpBox<'a, R, V> = Kp<
R,
V,
&'a R,
&'a V,
&'a mut R,
&'a mut V,
Box<dyn Fn(&'a R) -> Option<&'a V> + 'a>,
Box<dyn Fn(&'a mut R) -> Option<&'a mut V> + 'a>,
>;
pub type KpArc<'a, R, V> = Kp<
R,
V,
&'a R,
&'a V,
&'a mut R,
&'a mut V,
Arc<dyn Fn(&'a R) -> Option<&'a V> + Send + Sync + 'a>,
Arc<dyn Fn(&'a mut R) -> Option<&'a mut V> + Send + Sync + 'a>,
>;
pub type KpType<'a, R, V> = Kp<
R,
V,
&'a R,
&'a V,
&'a mut R,
&'a mut V,
for<'b> fn(&'b R) -> Option<&'b V>,
for<'b> fn(&'b mut R) -> Option<&'b mut V>,
>;
pub type KpTraitType<'a, R, V> = dyn KpTrait<
R,
V,
&'a R,
&'a V,
&'a mut R,
&'a mut V,
for<'b> fn(&'b R) -> Option<&'b V>,
for<'b> fn(&'b mut R) -> Option<&'b mut V>,
>;
pub type KpOptionRefCellType<'a, R, V> = Kp<
R,
V,
&'a R,
std::cell::Ref<'a, V>,
&'a mut R,
std::cell::RefMut<'a, V>,
for<'b> fn(&'b R) -> Option<std::cell::Ref<'b, V>>,
for<'b> fn(&'b mut R) -> Option<std::cell::RefMut<'b, V>>,
>;
impl<'a, R, V> KpType<'a, R, V> {
#[inline]
pub fn to_dynamic(self) -> KpDynamic<R, V> {
self.into()
}
}
impl<'a, R, V> From<KpType<'a, R, V>> for KpDynamic<R, V> {
#[inline]
fn from(kp: KpType<'a, R, V>) -> Self {
let get_fn = kp.get;
let set_fn = kp.set;
Kp::new(
Box::new(move |t: &R| get_fn(t)),
Box::new(move |t: &mut R| set_fn(t)),
)
}
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S> Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value> + Send + Sync + 'static,
S: Fn(MutRoot) -> Option<MutValue> + Send + Sync + 'static,
R: 'static,
V: 'static,
{
#[inline]
pub fn into_dynamic(self) -> KpDynamic<R, V> {
let g = self.get;
let s = self.set;
Kp::new(
Box::new(move |t: &R| unsafe {
debug_assert_eq!(std::mem::size_of::<Root>(), std::mem::size_of::<&R>());
let root: Root = std::mem::transmute_copy(&t);
match g(root) {
None => None,
Some(v) => {
let r: &V = std::borrow::Borrow::borrow(&v);
Some(std::mem::transmute::<&V, &V>(r))
}
}
}),
Box::new(move |t: &mut R| unsafe {
debug_assert_eq!(std::mem::size_of::<MutRoot>(), std::mem::size_of::<&mut R>());
let root: MutRoot = std::mem::transmute_copy(&t);
match s(root) {
None => None,
Some(mut v) => {
let r: &mut V = std::borrow::BorrowMut::borrow_mut(&mut v);
Some(std::mem::transmute::<&mut V, &mut V>(r))
}
}
}),
)
}
}
pub type KpComposed<R, V> = Kp<
R,
V,
&'static R,
&'static V,
&'static mut R,
&'static mut V,
Box<dyn for<'b> Fn(&'b R) -> Option<&'b V> + Send + Sync>,
Box<dyn for<'b> Fn(&'b mut R) -> Option<&'b mut V> + Send + Sync>,
>;
impl<R, V>
Kp<
R,
V,
&'static R,
&'static V,
&'static mut R,
&'static mut V,
Box<dyn for<'b> Fn(&'b R) -> Option<&'b V> + Send + Sync>,
Box<dyn for<'b> Fn(&'b mut R) -> Option<&'b mut V> + Send + Sync>,
>
{
pub fn from_closures<G, S>(get: G, set: S) -> Self
where
G: for<'b> Fn(&'b R) -> Option<&'b V> + Send + Sync + 'static,
S: for<'b> Fn(&'b mut R) -> Option<&'b mut V> + Send + Sync + 'static,
{
Self::new(Box::new(get), Box::new(set))
}
}
pub struct AKp {
getter: Rc<dyn for<'r> Fn(&'r dyn Any) -> Option<&'r dyn Any>>,
root_type_id: TypeId,
value_type_id: TypeId,
}
impl AKp {
pub fn new<'a, R, V>(keypath: KpType<'a, R, V>) -> Self
where
R: Any + 'static,
V: Any + 'static,
{
let root_type_id = TypeId::of::<R>();
let value_type_id = TypeId::of::<V>();
let getter_fn = keypath.get;
Self {
getter: Rc::new(move |any: &dyn Any| {
if let Some(root) = any.downcast_ref::<R>() {
getter_fn(root).map(|value: &V| value as &dyn Any)
} else {
None
}
}),
root_type_id,
value_type_id,
}
}
pub fn from<'a, R, V>(keypath: KpType<'a, R, V>) -> Self
where
R: Any + 'static,
V: Any + 'static,
{
Self::new(keypath)
}
pub fn get<'r>(&self, root: &'r dyn Any) -> Option<&'r dyn Any> {
(self.getter)(root)
}
pub fn root_type_id(&self) -> TypeId {
self.root_type_id
}
pub fn value_type_id(&self) -> TypeId {
self.value_type_id
}
pub fn get_as<'a, Root: Any, Value: Any>(&self, root: &'a Root) -> Option<Option<&'a Value>> {
if self.root_type_id == TypeId::of::<Root>() && self.value_type_id == TypeId::of::<Value>()
{
Some(
self.get(root as &dyn Any)
.and_then(|any| any.downcast_ref::<Value>()),
)
} else {
None
}
}
pub fn kind_name(&self) -> String {
format!("{:?}", self.value_type_id)
}
pub fn root_kind_name(&self) -> String {
format!("{:?}", self.root_type_id)
}
pub fn for_arc<Root>(&self) -> AKp
where
Root: Any + 'static,
{
let value_type_id = self.value_type_id;
let getter = self.getter.clone();
AKp {
getter: Rc::new(move |any: &dyn Any| {
if let Some(arc) = any.downcast_ref::<Arc<Root>>() {
getter(arc.as_ref() as &dyn Any)
} else {
None
}
}),
root_type_id: TypeId::of::<Arc<Root>>(),
value_type_id,
}
}
pub fn for_box<Root>(&self) -> AKp
where
Root: Any + 'static,
{
let value_type_id = self.value_type_id;
let getter = self.getter.clone();
AKp {
getter: Rc::new(move |any: &dyn Any| {
if let Some(boxed) = any.downcast_ref::<Box<Root>>() {
getter(boxed.as_ref() as &dyn Any)
} else {
None
}
}),
root_type_id: TypeId::of::<Box<Root>>(),
value_type_id,
}
}
pub fn for_rc<Root>(&self) -> AKp
where
Root: Any + 'static,
{
let value_type_id = self.value_type_id;
let getter = self.getter.clone();
AKp {
getter: Rc::new(move |any: &dyn Any| {
if let Some(rc) = any.downcast_ref::<Rc<Root>>() {
getter(rc.as_ref() as &dyn Any)
} else {
None
}
}),
root_type_id: TypeId::of::<Rc<Root>>(),
value_type_id,
}
}
pub fn for_option<Root>(&self) -> AKp
where
Root: Any + 'static,
{
let value_type_id = self.value_type_id;
let getter = self.getter.clone();
AKp {
getter: Rc::new(move |any: &dyn Any| {
if let Some(opt) = any.downcast_ref::<Option<Root>>() {
opt.as_ref().and_then(|root| getter(root as &dyn Any))
} else {
None
}
}),
root_type_id: TypeId::of::<Option<Root>>(),
value_type_id,
}
}
pub fn for_result<Root, E>(&self) -> AKp
where
Root: Any + 'static,
E: Any + 'static,
{
let value_type_id = self.value_type_id;
let getter = self.getter.clone();
AKp {
getter: Rc::new(move |any: &dyn Any| {
if let Some(result) = any.downcast_ref::<Result<Root, E>>() {
result
.as_ref()
.ok()
.and_then(|root| getter(root as &dyn Any))
} else {
None
}
}),
root_type_id: TypeId::of::<Result<Root, E>>(),
value_type_id,
}
}
pub fn map<Root, OrigValue, MappedValue, F>(&self, mapper: F) -> AKp
where
Root: Any + 'static,
OrigValue: Any + 'static,
MappedValue: Any + 'static,
F: Fn(&OrigValue) -> MappedValue + 'static,
{
let orig_root_type_id = self.root_type_id;
let orig_value_type_id = self.value_type_id;
let getter = self.getter.clone();
let mapped_type_id = TypeId::of::<MappedValue>();
AKp {
getter: Rc::new(move |any_root: &dyn Any| {
if any_root.type_id() == orig_root_type_id {
getter(any_root).and_then(|any_value| {
if orig_value_type_id == TypeId::of::<OrigValue>() {
any_value.downcast_ref::<OrigValue>().map(|orig_val| {
let mapped = mapper(orig_val);
Box::leak(Box::new(mapped)) as &dyn Any
})
} else {
None
}
})
} else {
None
}
}),
root_type_id: orig_root_type_id,
value_type_id: mapped_type_id,
}
}
pub fn filter<Root, Value, F>(&self, predicate: F) -> AKp
where
Root: Any + 'static,
Value: Any + 'static,
F: Fn(&Value) -> bool + 'static,
{
let orig_root_type_id = self.root_type_id;
let orig_value_type_id = self.value_type_id;
let getter = self.getter.clone();
AKp {
getter: Rc::new(move |any_root: &dyn Any| {
if any_root.type_id() == orig_root_type_id {
getter(any_root).filter(|any_value| {
if orig_value_type_id == TypeId::of::<Value>() {
any_value
.downcast_ref::<Value>()
.map(|val| predicate(val))
.unwrap_or(false)
} else {
false
}
})
} else {
None
}
}),
root_type_id: orig_root_type_id,
value_type_id: orig_value_type_id,
}
}
}
impl fmt::Debug for AKp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AKp")
.field("root_type_id", &self.root_type_id)
.field("value_type_id", &self.value_type_id)
.finish_non_exhaustive()
}
}
impl fmt::Display for AKp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"AKp(root_type_id={:?}, value_type_id={:?})",
self.root_type_id, self.value_type_id
)
}
}
pub struct PKp<Root> {
getter: Rc<dyn for<'r> Fn(&'r Root) -> Option<&'r dyn Any>>,
value_type_id: TypeId,
_phantom: std::marker::PhantomData<Root>,
}
impl<Root> PKp<Root>
where
Root: 'static,
{
pub fn new<'a, V>(keypath: KpType<'a, Root, V>) -> Self
where
V: Any + 'static,
{
let value_type_id = TypeId::of::<V>();
let getter_fn = keypath.get;
Self {
getter: Rc::new(move |root: &Root| getter_fn(root).map(|val: &V| val as &dyn Any)),
value_type_id,
_phantom: std::marker::PhantomData,
}
}
pub fn from<'a, V>(keypath: KpType<'a, Root, V>) -> Self
where
V: Any + 'static,
{
Self::new(keypath)
}
pub fn get<'r>(&self, root: &'r Root) -> Option<&'r dyn Any> {
(self.getter)(root)
}
pub fn value_type_id(&self) -> TypeId {
self.value_type_id
}
pub fn get_as<'a, Value: Any>(&self, root: &'a Root) -> Option<&'a Value> {
if self.value_type_id == TypeId::of::<Value>() {
self.get(root).and_then(|any| any.downcast_ref::<Value>())
} else {
None
}
}
pub fn kind_name(&self) -> String {
format!("{:?}", self.value_type_id)
}
pub fn for_arc(&self) -> PKp<Arc<Root>> {
let getter = self.getter.clone();
let value_type_id = self.value_type_id;
PKp {
getter: Rc::new(move |arc: &Arc<Root>| getter(arc.as_ref())),
value_type_id,
_phantom: std::marker::PhantomData,
}
}
pub fn for_box(&self) -> PKp<Box<Root>> {
let getter = self.getter.clone();
let value_type_id = self.value_type_id;
PKp {
getter: Rc::new(move |boxed: &Box<Root>| getter(boxed.as_ref())),
value_type_id,
_phantom: std::marker::PhantomData,
}
}
pub fn for_rc(&self) -> PKp<Rc<Root>> {
let getter = self.getter.clone();
let value_type_id = self.value_type_id;
PKp {
getter: Rc::new(move |rc: &Rc<Root>| getter(rc.as_ref())),
value_type_id,
_phantom: std::marker::PhantomData,
}
}
pub fn for_option(&self) -> PKp<Option<Root>> {
let getter = self.getter.clone();
let value_type_id = self.value_type_id;
PKp {
getter: Rc::new(move |opt: &Option<Root>| opt.as_ref().and_then(|root| getter(root))),
value_type_id,
_phantom: std::marker::PhantomData,
}
}
pub fn for_result<E>(&self) -> PKp<Result<Root, E>>
where
E: 'static,
{
let getter = self.getter.clone();
let value_type_id = self.value_type_id;
PKp {
getter: Rc::new(move |result: &Result<Root, E>| {
result.as_ref().ok().and_then(|root| getter(root))
}),
value_type_id,
_phantom: std::marker::PhantomData,
}
}
pub fn map<OrigValue, MappedValue, F>(&self, mapper: F) -> PKp<Root>
where
OrigValue: Any + 'static,
MappedValue: Any + 'static,
F: Fn(&OrigValue) -> MappedValue + 'static,
{
let orig_type_id = self.value_type_id;
let getter = self.getter.clone();
let mapped_type_id = TypeId::of::<MappedValue>();
PKp {
getter: Rc::new(move |root: &Root| {
getter(root).and_then(|any_value| {
if orig_type_id == TypeId::of::<OrigValue>() {
any_value.downcast_ref::<OrigValue>().map(|orig_val| {
let mapped = mapper(orig_val);
Box::leak(Box::new(mapped)) as &dyn Any
})
} else {
None
}
})
}),
value_type_id: mapped_type_id,
_phantom: std::marker::PhantomData,
}
}
pub fn filter<Value, F>(&self, predicate: F) -> PKp<Root>
where
Value: Any + 'static,
F: Fn(&Value) -> bool + 'static,
{
let orig_type_id = self.value_type_id;
let getter = self.getter.clone();
PKp {
getter: Rc::new(move |root: &Root| {
getter(root).filter(|any_value| {
if orig_type_id == TypeId::of::<Value>() {
any_value
.downcast_ref::<Value>()
.map(|val| predicate(val))
.unwrap_or(false)
} else {
false
}
})
}),
value_type_id: orig_type_id,
_phantom: std::marker::PhantomData,
}
}
}
impl<Root> fmt::Debug for PKp<Root> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PKp")
.field("root_ty", &std::any::type_name::<Root>())
.field("value_type_id", &self.value_type_id)
.finish_non_exhaustive()
}
}
impl<Root> fmt::Display for PKp<Root> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"PKp<{}, value_type_id={:?}>",
std::any::type_name::<Root>(),
self.value_type_id
)
}
}
pub trait KpTrait<R, V, Root, Value, MutRoot, MutValue, G, S> {
fn type_id_of_root() -> TypeId
where
R: 'static,
{
std::any::TypeId::of::<R>()
}
fn type_id_of_value() -> TypeId
where
V: 'static,
{
std::any::TypeId::of::<V>()
}
fn get(&self, root: Root) -> Option<Value>;
fn get_mut(&self, root: MutRoot) -> Option<MutValue>;
fn then<SV, SubValue, MutSubValue, G2, S2>(
self,
next: Kp<V, SV, Value, SubValue, MutValue, MutSubValue, G2, S2>,
) -> Kp<
R,
SV,
Root,
SubValue,
MutRoot,
MutSubValue,
impl Fn(Root) -> Option<SubValue>,
impl Fn(MutRoot) -> Option<MutSubValue>,
>
where
Self: Sized,
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
SubValue: std::borrow::Borrow<SV>,
MutSubValue: std::borrow::BorrowMut<SV>,
G2: Fn(Value) -> Option<SubValue>,
S2: Fn(MutValue) -> Option<MutSubValue>,;
}
pub trait ChainExt<R, V, Root, Value, MutRoot, MutValue> {
fn then_lock<
Lock,
Mid,
V2,
LockValue,
MidValue,
Value2,
MutLock,
MutMid,
MutValue2,
G1,
S1,
L,
G2,
S2,
>(
self,
lock_kp: crate::lock::LockKp<
V,
Lock,
Mid,
V2,
Value,
LockValue,
MidValue,
Value2,
MutValue,
MutLock,
MutMid,
MutValue2,
G1,
S1,
L,
G2,
S2,
>,
) -> crate::lock::KpThenLockKp<
R,
V,
V2,
Root,
Value,
Value2,
MutRoot,
MutValue,
MutValue2,
Self,
crate::lock::LockKp<
V,
Lock,
Mid,
V2,
Value,
LockValue,
MidValue,
Value2,
MutValue,
MutLock,
MutMid,
MutValue2,
G1,
S1,
L,
G2,
S2,
>,
>
where
V: 'static + Clone,
V2: 'static,
Value: std::borrow::Borrow<V>,
Value2: std::borrow::Borrow<V2>,
MutValue: std::borrow::BorrowMut<V>,
MutValue2: std::borrow::BorrowMut<V2>,
LockValue: std::borrow::Borrow<Lock>,
MidValue: std::borrow::Borrow<Mid>,
MutLock: std::borrow::BorrowMut<Lock>,
MutMid: std::borrow::BorrowMut<Mid>,
G1: Fn(Value) -> Option<LockValue>,
S1: Fn(MutValue) -> Option<MutLock>,
L: crate::lock::LockAccess<Lock, MidValue> + crate::lock::LockAccess<Lock, MutMid>,
G2: Fn(MidValue) -> Option<Value2>,
S2: Fn(MutMid) -> Option<MutValue2>,
Self: Sized;
#[cfg(feature = "pin_project")]
fn then_pin_future<Struct, Output, L>(
self,
pin_fut: L,
) -> crate::pin::KpThenPinFuture<R, Struct, Output, Root, MutRoot, Value, MutValue, Self, L>
where
Struct: Unpin + 'static,
Output: 'static,
Value: std::borrow::Borrow<Struct>,
MutValue: std::borrow::BorrowMut<Struct>,
L: crate::pin::PinFutureAwaitLike<Struct, Output> + Sync,
Self: Sized;
fn then_async<AsyncKp>(
self,
async_kp: AsyncKp,
) -> crate::async_lock::KpThenAsyncKeyPath<
R,
V,
<AsyncKp::Value as KeyPathValueTarget>::Target,
Root,
Value,
AsyncKp::Value,
MutRoot,
MutValue,
AsyncKp::MutValue,
Self,
AsyncKp,
>
where
Value: std::borrow::Borrow<V>,
MutValue: std::borrow::BorrowMut<V>,
AsyncKp: crate::async_lock::AsyncKeyPathLike<Value, MutValue>,
AsyncKp::Value: KeyPathValueTarget
+ std::borrow::Borrow<<AsyncKp::Value as KeyPathValueTarget>::Target>,
AsyncKp::MutValue: std::borrow::BorrowMut<<AsyncKp::Value as KeyPathValueTarget>::Target>,
<AsyncKp::Value as KeyPathValueTarget>::Target: 'static,
Self: Sized;
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S> ChainExt<R, V, Root, Value, MutRoot, MutValue>
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
fn then_lock<
Lock,
Mid,
V2,
LockValue,
MidValue,
Value2,
MutLock,
MutMid,
MutValue2,
G1,
S1,
L,
G2,
S2,
>(
self,
lock_kp: crate::lock::LockKp<
V,
Lock,
Mid,
V2,
Value,
LockValue,
MidValue,
Value2,
MutValue,
MutLock,
MutMid,
MutValue2,
G1,
S1,
L,
G2,
S2,
>,
) -> crate::lock::KpThenLockKp<
R,
V,
V2,
Root,
Value,
Value2,
MutRoot,
MutValue,
MutValue2,
Self,
crate::lock::LockKp<
V,
Lock,
Mid,
V2,
Value,
LockValue,
MidValue,
Value2,
MutValue,
MutLock,
MutMid,
MutValue2,
G1,
S1,
L,
G2,
S2,
>,
>
where
V: 'static + Clone,
V2: 'static,
Value: std::borrow::Borrow<V>,
Value2: std::borrow::Borrow<V2>,
MutValue: std::borrow::BorrowMut<V>,
MutValue2: std::borrow::BorrowMut<V2>,
LockValue: std::borrow::Borrow<Lock>,
MidValue: std::borrow::Borrow<Mid>,
MutLock: std::borrow::BorrowMut<Lock>,
MutMid: std::borrow::BorrowMut<Mid>,
G1: Fn(Value) -> Option<LockValue>,
S1: Fn(MutValue) -> Option<MutLock>,
L: crate::lock::LockAccess<Lock, MidValue> + crate::lock::LockAccess<Lock, MutMid>,
G2: Fn(MidValue) -> Option<Value2>,
S2: Fn(MutMid) -> Option<MutValue2>,
{
crate::lock::KpThenLockKp {
first: self,
second: lock_kp,
_p: std::marker::PhantomData,
}
}
#[cfg(feature = "pin_project")]
fn then_pin_future<Struct, Output, L>(
self,
pin_fut: L,
) -> crate::pin::KpThenPinFuture<R, Struct, Output, Root, MutRoot, Value, MutValue, Self, L>
where
Struct: Unpin + 'static,
Output: 'static,
Value: std::borrow::Borrow<Struct>,
MutValue: std::borrow::BorrowMut<Struct>,
L: crate::pin::PinFutureAwaitLike<Struct, Output> + Sync,
{
crate::pin::KpThenPinFuture {
first: self,
second: pin_fut,
_p: std::marker::PhantomData,
}
}
fn then_async<AsyncKp>(
self,
async_kp: AsyncKp,
) -> crate::async_lock::KpThenAsyncKeyPath<
R,
V,
<AsyncKp::Value as KeyPathValueTarget>::Target,
Root,
Value,
AsyncKp::Value,
MutRoot,
MutValue,
AsyncKp::MutValue,
Self,
AsyncKp,
>
where
Value: std::borrow::Borrow<V>,
MutValue: std::borrow::BorrowMut<V>,
AsyncKp: crate::async_lock::AsyncKeyPathLike<Value, MutValue>,
AsyncKp::Value: KeyPathValueTarget
+ std::borrow::Borrow<<AsyncKp::Value as KeyPathValueTarget>::Target>,
AsyncKp::MutValue: std::borrow::BorrowMut<<AsyncKp::Value as KeyPathValueTarget>::Target>,
<AsyncKp::Value as KeyPathValueTarget>::Target: 'static,
{
crate::async_lock::KpThenAsyncKeyPath {
first: self,
second: async_kp,
_p: std::marker::PhantomData,
}
}
}
pub trait AccessorTrait<R, V, Root, Value, MutRoot, MutValue, G, S> {
fn get_optional(&self, root: Option<Root>) -> Option<Value>;
fn get_mut_optional(&self, root: Option<MutRoot>) -> Option<MutValue>;
fn get_or_else<F>(&self, root: Root, f: F) -> Value
where
F: FnOnce() -> Value;
#[inline]
fn get_mut_or_else<F>(&self, root: MutRoot, f: F) -> MutValue
where
F: FnOnce() -> MutValue;
}
pub trait CoercionTrait<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
fn for_arc<'b>(
&self,
) -> Kp<
std::sync::Arc<R>,
V,
std::sync::Arc<R>,
Value,
std::sync::Arc<R>,
MutValue,
impl Fn(std::sync::Arc<R>) -> Option<Value>,
impl Fn(std::sync::Arc<R>) -> Option<MutValue>,
>
where
R: 'b,
V: 'b,
Root: for<'a> From<&'a R>,
MutRoot: for<'a> From<&'a mut R>;
fn for_box<'a>(
&self,
) -> Kp<
Box<R>,
V,
Box<R>,
Value,
Box<R>,
MutValue,
impl Fn(Box<R>) -> Option<Value>,
impl Fn(Box<R>) -> Option<MutValue>,
>
where
R: 'a,
V: 'a,
Root: for<'b> From<&'b R>,
MutRoot: for<'b> From<&'b mut R>;
fn into_set(self) -> impl Fn(MutRoot) -> Option<MutValue>;
fn into_get(self) -> impl Fn(Root) -> Option<Value>;
}
pub trait HofTrait<R, V, Root, Value, MutRoot, MutValue, G, S>:
KpTrait<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
fn map<MappedValue, F>(
&self,
mapper: F,
) -> Kp<
R,
MappedValue,
Root,
MappedValue,
MutRoot,
MappedValue,
impl Fn(Root) -> Option<MappedValue> + '_,
impl Fn(MutRoot) -> Option<MappedValue> + '_,
>
where
F: Fn(&V) -> MappedValue + Copy + 'static,
MappedValue: 'static,
{
Kp::new(
move |root: Root| {
self.get(root).map(|value| {
let v: &V = value.borrow();
mapper(v)
})
},
move |root: MutRoot| {
self.get_mut(root).map(|value| {
let v: &V = value.borrow();
mapper(v)
})
},
)
}
fn filter<F>(
&self,
predicate: F,
) -> Kp<
R,
V,
Root,
Value,
MutRoot,
MutValue,
impl Fn(Root) -> Option<Value> + '_,
impl Fn(MutRoot) -> Option<MutValue> + '_,
>
where
F: Fn(&V) -> bool + Copy + 'static,
{
Kp::new(
move |root: Root| {
self.get(root).filter(|value| {
let v: &V = value.borrow();
predicate(v)
})
},
move |root: MutRoot| {
self.get_mut(root).filter(|value| {
let v: &V = value.borrow();
predicate(v)
})
},
)
}
fn filter_map<MappedValue, F>(
&self,
mapper: F,
) -> Kp<
R,
MappedValue,
Root,
MappedValue,
MutRoot,
MappedValue,
impl Fn(Root) -> Option<MappedValue> + '_,
impl Fn(MutRoot) -> Option<MappedValue> + '_,
>
where
F: Fn(&V) -> Option<MappedValue> + Copy + 'static,
{
Kp::new(
move |root: Root| {
self.get(root).and_then(|value| {
let v: &V = value.borrow();
mapper(v)
})
},
move |root: MutRoot| {
self.get_mut(root).and_then(|value| {
let v: &V = value.borrow();
mapper(v)
})
},
)
}
fn inspect<F>(
&self,
inspector: F,
) -> Kp<
R,
V,
Root,
Value,
MutRoot,
MutValue,
impl Fn(Root) -> Option<Value> + '_,
impl Fn(MutRoot) -> Option<MutValue> + '_,
>
where
F: Fn(&V) + Copy + 'static,
{
Kp::new(
move |root: Root| {
self.get(root).map(|value| {
let v: &V = value.borrow();
inspector(v);
value
})
},
move |root: MutRoot| {
self.get_mut(root).map(|value| {
let v: &V = value.borrow();
inspector(v);
value
})
},
)
}
fn flat_map<I, Item, F>(&self, mapper: F) -> impl Fn(Root) -> Vec<Item> + '_
where
F: Fn(&V) -> I + 'static,
I: IntoIterator<Item = Item>,
{
move |root: Root| {
self.get(root)
.map(|value| {
let v: &V = value.borrow();
mapper(v).into_iter().collect()
})
.unwrap_or_else(Vec::new)
}
}
fn fold_value<Acc, F>(&self, init: Acc, folder: F) -> impl Fn(Root) -> Acc + '_
where
F: Fn(Acc, &V) -> Acc + 'static,
Acc: Copy + 'static,
{
move |root: Root| {
self.get(root)
.map(|value| {
let v: &V = value.borrow();
folder(init, v)
})
.unwrap_or(init)
}
}
fn any<F>(&self, predicate: F) -> impl Fn(Root) -> bool + '_
where
F: Fn(&V) -> bool + 'static,
{
move |root: Root| {
self.get(root)
.map(|value| {
let v: &V = value.borrow();
predicate(v)
})
.unwrap_or(false)
}
}
fn all<F>(&self, predicate: F) -> impl Fn(Root) -> bool + '_
where
F: Fn(&V) -> bool + 'static,
{
move |root: Root| {
self.get(root)
.map(|value| {
let v: &V = value.borrow();
predicate(v)
})
.unwrap_or(true)
}
}
fn count_items<F>(&self, counter: F) -> impl Fn(Root) -> Option<usize> + '_
where
F: Fn(&V) -> usize + 'static,
{
move |root: Root| {
self.get(root).map(|value| {
let v: &V = value.borrow();
counter(v)
})
}
}
fn find_in<Item, F>(&self, finder: F) -> impl Fn(Root) -> Option<Item> + '_
where
F: Fn(&V) -> Option<Item> + 'static,
{
move |root: Root| {
self.get(root).and_then(|value| {
let v: &V = value.borrow();
finder(v)
})
}
}
fn take<Output, F>(&self, n: usize, taker: F) -> impl Fn(Root) -> Option<Output> + '_
where
F: Fn(&V, usize) -> Output + 'static,
{
move |root: Root| {
self.get(root).map(|value| {
let v: &V = value.borrow();
taker(v, n)
})
}
}
fn skip<Output, F>(&self, n: usize, skipper: F) -> impl Fn(Root) -> Option<Output> + '_
where
F: Fn(&V, usize) -> Output + 'static,
{
move |root: Root| {
self.get(root).map(|value| {
let v: &V = value.borrow();
skipper(v, n)
})
}
}
fn partition_value<Output, F>(&self, partitioner: F) -> impl Fn(Root) -> Option<Output> + '_
where
F: Fn(&V) -> Output + 'static,
{
move |root: Root| {
self.get(root).map(|value| {
let v: &V = value.borrow();
partitioner(v)
})
}
}
fn min_value<Item, F>(&self, min_fn: F) -> impl Fn(Root) -> Option<Item> + '_
where
F: Fn(&V) -> Option<Item> + 'static,
{
move |root: Root| {
self.get(root).and_then(|value| {
let v: &V = value.borrow();
min_fn(v)
})
}
}
fn max_value<Item, F>(&self, max_fn: F) -> impl Fn(Root) -> Option<Item> + '_
where
F: Fn(&V) -> Option<Item> + 'static,
{
move |root: Root| {
self.get(root).and_then(|value| {
let v: &V = value.borrow();
max_fn(v)
})
}
}
fn sum_value<Sum, F>(&self, sum_fn: F) -> impl Fn(Root) -> Option<Sum> + '_
where
F: Fn(&V) -> Sum + 'static,
{
move |root: Root| {
self.get(root).map(|value| {
let v: &V = value.borrow();
sum_fn(v)
})
}
}
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S> KpTrait<R, V, Root, Value, MutRoot, MutValue, G, S>
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
fn then<SV, SubValue, MutSubValue, G2, S2>(
self,
next: Kp<V, SV, Value, SubValue, MutValue, MutSubValue, G2, S2>,
) -> Kp<
R,
SV,
Root,
SubValue,
MutRoot,
MutSubValue,
impl Fn(Root) -> Option<SubValue>,
impl Fn(MutRoot) -> Option<MutSubValue>,
>
where
SubValue: std::borrow::Borrow<SV>,
MutSubValue: std::borrow::BorrowMut<SV>,
G2: Fn(Value) -> Option<SubValue>,
S2: Fn(MutValue) -> Option<MutSubValue>,
{
Kp::new(
move |root: Root| (self.get)(root).and_then(|value| (next.get)(value)),
move |root: MutRoot| (self.set)(root).and_then(|value| (next.set)(value)),
)
}
fn get(&self, root: Root) -> Option<Value> {
(self.get)(root)
}
fn get_mut(&self, root: MutRoot) -> Option<MutValue> {
(self.set)(root)
}
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S>
CoercionTrait<R, V, Root, Value, MutRoot, MutValue, G, S>
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
fn for_arc<'b>(
&self,
) -> Kp<
std::sync::Arc<R>,
V,
std::sync::Arc<R>,
Value,
std::sync::Arc<R>,
MutValue,
impl Fn(std::sync::Arc<R>) -> Option<Value>,
impl Fn(std::sync::Arc<R>) -> Option<MutValue>,
>
where
R: 'b,
V: 'b,
Root: for<'a> From<&'a R>,
MutRoot: for<'a> From<&'a mut R>,
{
Kp::new(
move |arc_root: std::sync::Arc<R>| {
let r_ref: &R = &*arc_root;
(self.get)(Root::from(r_ref))
},
move |mut arc_root: std::sync::Arc<R>| {
std::sync::Arc::get_mut(&mut arc_root)
.and_then(|r_mut| (self.set)(MutRoot::from(r_mut)))
},
)
}
fn for_box<'a>(
&self,
) -> Kp<
Box<R>,
V,
Box<R>,
Value,
Box<R>,
MutValue,
impl Fn(Box<R>) -> Option<Value>,
impl Fn(Box<R>) -> Option<MutValue>,
>
where
R: 'a,
V: 'a,
Root: for<'b> From<&'b R>,
MutRoot: for<'b> From<&'b mut R>,
{
Kp::new(
move |r: Box<R>| {
let r_ref: &R = r.as_ref();
(self.get)(Root::from(r_ref))
},
move |mut r: Box<R>| {
(self.set)(MutRoot::from(r.as_mut()))
},
)
}
#[inline]
fn into_set(self) -> impl Fn(MutRoot) -> Option<MutValue> {
self.set
}
#[inline]
fn into_get(self) -> impl Fn(Root) -> Option<Value> {
self.get
}
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S>
HofTrait<R, V, Root, Value, MutRoot, MutValue, G, S>
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S>
AccessorTrait<R, V, Root, Value, MutRoot, MutValue, G, S>
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
#[inline]
fn get_optional(&self, root: Option<Root>) -> Option<Value> {
root.and_then(|r| (self.get)(r))
}
#[inline]
fn get_mut_optional(&self, root: Option<MutRoot>) -> Option<MutValue> {
root.and_then(|r| (self.set)(r))
}
#[inline]
fn get_or_else<F>(&self, root: Root, f: F) -> Value
where
F: FnOnce() -> Value,
{
(self.get)(root).unwrap_or_else(f)
}
#[inline]
fn get_mut_or_else<F>(&self, root: MutRoot, f: F) -> MutValue
where
F: FnOnce() -> MutValue,
{
(self.set)(root).unwrap_or_else(f)
}
}
#[derive(Clone)]
pub struct Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
pub get: G,
pub set: S,
_p: std::marker::PhantomData<(R, V, Root, Value, MutRoot, MutValue)>,
}
unsafe impl<R, V, Root, Value, MutRoot, MutValue, G, S> Send
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value> + Send,
S: Fn(MutRoot) -> Option<MutValue> + Send,
{
}
unsafe impl<R, V, Root, Value, MutRoot, MutValue, G, S> Sync
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value> + Sync,
S: Fn(MutRoot) -> Option<MutValue> + Sync,
{
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S> Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
pub fn new(get: G, set: S) -> Self {
Self {
get: get,
set: set,
_p: std::marker::PhantomData,
}
}
#[inline]
pub fn then<SV, SubValue, MutSubValue, G2, S2>(
self,
next: Kp<V, SV, Value, SubValue, MutValue, MutSubValue, G2, S2>,
) -> Kp<
R,
SV,
Root,
SubValue,
MutRoot,
MutSubValue,
impl Fn(Root) -> Option<SubValue>,
impl Fn(MutRoot) -> Option<MutSubValue>,
>
where
SubValue: std::borrow::Borrow<SV>,
MutSubValue: std::borrow::BorrowMut<SV>,
G2: Fn(Value) -> Option<SubValue>,
S2: Fn(MutValue) -> Option<MutSubValue>,
{
Kp::new(
move |root: Root| (self.get)(root).and_then(|value| (next.get)(value)),
move |root: MutRoot| (self.set)(root).and_then(|value| (next.set)(value)),
)
}
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S> fmt::Debug
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Kp")
.field("root_ty", &std::any::type_name::<R>())
.field("value_ty", &std::any::type_name::<V>())
.finish_non_exhaustive()
}
}
impl<R, V, Root, Value, MutRoot, MutValue, G, S> fmt::Display
for Kp<R, V, Root, Value, MutRoot, MutValue, G, S>
where
Root: std::borrow::Borrow<R>,
Value: std::borrow::Borrow<V>,
MutRoot: std::borrow::BorrowMut<R>,
MutValue: std::borrow::BorrowMut<V>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Kp<{}, {}>",
std::any::type_name::<R>(),
std::any::type_name::<V>()
)
}
}
pub fn zip_kps<'a, RootType, Value1, Value2>(
kp1: &'a KpType<'a, RootType, Value1>,
kp2: &'a KpType<'a, RootType, Value2>,
) -> impl Fn(&'a RootType) -> Option<(&'a Value1, &'a Value2)> + 'a
where
RootType: 'a,
Value1: 'a,
Value2: 'a,
{
move |root: &'a RootType| {
let val1 = (kp1.get)(root)?;
let val2 = (kp2.get)(root)?;
Some((val1, val2))
}
}
impl<R, Root, MutRoot, G, S> Kp<R, R, Root, Root, MutRoot, MutRoot, G, S>
where
Root: std::borrow::Borrow<R>,
MutRoot: std::borrow::BorrowMut<R>,
G: Fn(Root) -> Option<Root>,
S: Fn(MutRoot) -> Option<MutRoot>,
{
pub fn identity_typed() -> Kp<
R,
R,
Root,
Root,
MutRoot,
MutRoot,
fn(Root) -> Option<Root>,
fn(MutRoot) -> Option<MutRoot>,
> {
Kp::new(|r: Root| Some(r), |r: MutRoot| Some(r))
}
pub fn identity<'a>() -> KpType<'a, R, R> {
KpType::new(|r| Some(r), |r| Some(r))
}
}
pub struct EnumKp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E>
where
Root: std::borrow::Borrow<Enum>,
Value: std::borrow::Borrow<Variant>,
MutRoot: std::borrow::BorrowMut<Enum>,
MutValue: std::borrow::BorrowMut<Variant>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
E: Fn(Variant) -> Enum,
{
extractor: Kp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S>,
embedder: E,
}
unsafe impl<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E> Send
for EnumKp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E>
where
Root: std::borrow::Borrow<Enum>,
Value: std::borrow::Borrow<Variant>,
MutRoot: std::borrow::BorrowMut<Enum>,
MutValue: std::borrow::BorrowMut<Variant>,
G: Fn(Root) -> Option<Value> + Send,
S: Fn(MutRoot) -> Option<MutValue> + Send,
E: Fn(Variant) -> Enum + Send,
{
}
unsafe impl<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E> Sync
for EnumKp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E>
where
Root: std::borrow::Borrow<Enum>,
Value: std::borrow::Borrow<Variant>,
MutRoot: std::borrow::BorrowMut<Enum>,
MutValue: std::borrow::BorrowMut<Variant>,
G: Fn(Root) -> Option<Value> + Sync,
S: Fn(MutRoot) -> Option<MutValue> + Sync,
E: Fn(Variant) -> Enum + Sync,
{
}
impl<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E>
EnumKp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E>
where
Root: std::borrow::Borrow<Enum>,
Value: std::borrow::Borrow<Variant>,
MutRoot: std::borrow::BorrowMut<Enum>,
MutValue: std::borrow::BorrowMut<Variant>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
E: Fn(Variant) -> Enum,
{
pub fn new(
extractor: Kp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S>,
embedder: E,
) -> Self {
Self {
extractor,
embedder,
}
}
pub fn get(&self, enum_value: Root) -> Option<Value> {
(self.extractor.get)(enum_value)
}
pub fn get_mut(&self, enum_value: MutRoot) -> Option<MutValue> {
(self.extractor.set)(enum_value)
}
pub fn embed(&self, value: Variant) -> Enum {
(self.embedder)(value)
}
pub fn as_kp(&self) -> &Kp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S> {
&self.extractor
}
pub fn into_kp(self) -> Kp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S> {
self.extractor
}
pub fn map<MappedValue, F>(
&self,
mapper: F,
) -> EnumKp<
Enum,
MappedValue,
Root,
MappedValue,
MutRoot,
MappedValue,
impl Fn(Root) -> Option<MappedValue>,
impl Fn(MutRoot) -> Option<MappedValue>,
impl Fn(MappedValue) -> Enum,
>
where
F: Fn(&Variant) -> MappedValue + Copy + 'static,
Variant: 'static,
MappedValue: 'static,
E: Fn(Variant) -> Enum + Copy + 'static,
{
let mapped_extractor = self.extractor.map(mapper);
let new_embedder = move |_value: MappedValue| -> Enum {
panic!(
"Cannot embed mapped values back into enum. Use the original EnumKp for embedding."
)
};
EnumKp::new(mapped_extractor, new_embedder)
}
pub fn filter<F>(
&self,
predicate: F,
) -> EnumKp<
Enum,
Variant,
Root,
Value,
MutRoot,
MutValue,
impl Fn(Root) -> Option<Value>,
impl Fn(MutRoot) -> Option<MutValue>,
E,
>
where
F: Fn(&Variant) -> bool + Copy + 'static,
Variant: 'static,
E: Copy,
{
let filtered_extractor = self.extractor.filter(predicate);
EnumKp::new(filtered_extractor, self.embedder)
}
}
impl<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E> fmt::Debug
for EnumKp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E>
where
Root: std::borrow::Borrow<Enum>,
Value: std::borrow::Borrow<Variant>,
MutRoot: std::borrow::BorrowMut<Enum>,
MutValue: std::borrow::BorrowMut<Variant>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
E: Fn(Variant) -> Enum,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EnumKp")
.field("enum_ty", &std::any::type_name::<Enum>())
.field("variant_ty", &std::any::type_name::<Variant>())
.finish_non_exhaustive()
}
}
impl<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E> fmt::Display
for EnumKp<Enum, Variant, Root, Value, MutRoot, MutValue, G, S, E>
where
Root: std::borrow::Borrow<Enum>,
Value: std::borrow::Borrow<Variant>,
MutRoot: std::borrow::BorrowMut<Enum>,
MutValue: std::borrow::BorrowMut<Variant>,
G: Fn(Root) -> Option<Value>,
S: Fn(MutRoot) -> Option<MutValue>,
E: Fn(Variant) -> Enum,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"EnumKp<{}, {}>",
std::any::type_name::<Enum>(),
std::any::type_name::<Variant>()
)
}
}
pub type EnumKpType<'a, Enum, Variant> = EnumKp<
Enum,
Variant,
&'a Enum,
&'a Variant,
&'a mut Enum,
&'a mut Variant,
for<'b> fn(&'b Enum) -> Option<&'b Variant>,
for<'b> fn(&'b mut Enum) -> Option<&'b mut Variant>,
fn(Variant) -> Enum,
>;
pub fn enum_variant<'a, Enum, Variant>(
getter: for<'b> fn(&'b Enum) -> Option<&'b Variant>,
setter: for<'b> fn(&'b mut Enum) -> Option<&'b mut Variant>,
embedder: fn(Variant) -> Enum,
) -> EnumKpType<'a, Enum, Variant> {
EnumKp::new(Kp::new(getter, setter), embedder)
}
pub fn enum_ok<'a, T, E>() -> EnumKpType<'a, Result<T, E>, T> {
EnumKp::new(
Kp::new(
|r: &Result<T, E>| r.as_ref().ok(),
|r: &mut Result<T, E>| r.as_mut().ok(),
),
|t: T| Ok(t),
)
}
pub fn enum_err<'a, T, E>() -> EnumKpType<'a, Result<T, E>, E> {
EnumKp::new(
Kp::new(
|r: &Result<T, E>| r.as_ref().err(),
|r: &mut Result<T, E>| r.as_mut().err(),
),
|e: E| Err(e),
)
}
pub fn enum_some<'a, T>() -> EnumKpType<'a, Option<T>, T> {
EnumKp::new(
Kp::new(|o: &Option<T>| o.as_ref(), |o: &mut Option<T>| o.as_mut()),
|t: T| Some(t),
)
}
pub fn variant_of<'a, Enum, Variant>(
getter: for<'b> fn(&'b Enum) -> Option<&'b Variant>,
setter: for<'b> fn(&'b mut Enum) -> Option<&'b mut Variant>,
embedder: fn(Variant) -> Enum,
) -> EnumKpType<'a, Enum, Variant> {
enum_variant(getter, setter, embedder)
}
pub fn kp_box<'a, T>() -> KpType<'a, Box<T>, T> {
Kp::new(
|b: &Box<T>| Some(b.as_ref()),
|b: &mut Box<T>| Some(b.as_mut()),
)
}
pub fn kp_arc<'a, T>() -> Kp<
Arc<T>,
T,
&'a Arc<T>,
&'a T,
&'a mut Arc<T>,
&'a mut T,
for<'b> fn(&'b Arc<T>) -> Option<&'b T>,
for<'b> fn(&'b mut Arc<T>) -> Option<&'b mut T>,
> {
Kp::new(
|arc: &Arc<T>| Some(arc.as_ref()),
|arc: &mut Arc<T>| Arc::get_mut(arc),
)
}
pub fn kp_rc<'a, T>() -> Kp<
std::rc::Rc<T>,
T,
&'a std::rc::Rc<T>,
&'a T,
&'a mut std::rc::Rc<T>,
&'a mut T,
for<'b> fn(&'b std::rc::Rc<T>) -> Option<&'b T>,
for<'b> fn(&'b mut std::rc::Rc<T>) -> Option<&'b mut T>,
> {
Kp::new(
|rc: &std::rc::Rc<T>| Some(rc.as_ref()),
|rc: &mut std::rc::Rc<T>| std::rc::Rc::get_mut(rc),
)
}
use std::any::{Any, TypeId};
use std::rc::Rc;
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
fn kp_adaptable<T, Root, Value, MutRoot, MutValue, G, S>(kp: T)
where
T: KpTrait<TestKP, String, Root, Value, MutRoot, MutValue, G, S>,
{
}
fn test_kp_trait() {}
#[derive(Debug)]
struct TestKP {
a: String,
b: String,
c: std::sync::Arc<String>,
d: std::sync::Mutex<String>,
e: std::sync::Arc<std::sync::Mutex<TestKP2>>,
f: Option<TestKP2>,
g: HashMap<i32, TestKP2>,
}
impl TestKP {
fn new() -> Self {
Self {
a: String::from("a"),
b: String::from("b"),
c: std::sync::Arc::new(String::from("c")),
d: std::sync::Mutex::new(String::from("d")),
e: std::sync::Arc::new(std::sync::Mutex::new(TestKP2::new())),
f: Some(TestKP2 {
a: String::from("a3"),
b: std::sync::Arc::new(std::sync::Mutex::new(TestKP3::new())),
}),
g: HashMap::new(),
}
}
fn g(index: i32) -> KpComposed<TestKP, TestKP2> {
KpComposed::from_closures(
move |r: &TestKP| r.g.get(&index),
move |r: &mut TestKP| r.g.get_mut(&index),
)
}
fn a_typed<Root, MutRoot, Value, MutValue>() -> Kp<
TestKP2,
String,
Root,
Value,
MutRoot,
MutValue,
impl Fn(Root) -> Option<Value>,
impl Fn(MutRoot) -> Option<MutValue>,
>
where
Root: std::borrow::Borrow<TestKP2>,
MutRoot: std::borrow::BorrowMut<TestKP2>,
Value: std::borrow::Borrow<String> + From<String>,
MutValue: std::borrow::BorrowMut<String> + From<String>,
{
Kp::new(
|r: Root| Some(Value::from(r.borrow().a.clone())),
|mut r: MutRoot| Some(MutValue::from(r.borrow_mut().a.clone())),
)
}
fn c<'a>() -> KpType<'a, TestKP, String> {
KpType::new(
|r: &TestKP| Some(r.c.as_ref()),
|r: &mut TestKP| match std::sync::Arc::get_mut(&mut r.c) {
Some(arc_str) => Some(arc_str),
None => None,
},
)
}
fn a<'a>() -> KpType<'a, TestKP, String> {
KpType::new(|r: &TestKP| Some(&r.a), |r: &mut TestKP| Some(&mut r.a))
}
fn f<'a>() -> KpType<'a, TestKP, TestKP2> {
KpType::new(|r: &TestKP| r.f.as_ref(), |r: &mut TestKP| r.f.as_mut())
}
fn identity<'a>() -> KpType<'a, TestKP, TestKP> {
KpType::identity()
}
}
#[test]
fn kp_debug_display_uses_type_names() {
let kp = TestKP::a();
let dbg = format!("{kp:?}");
assert!(dbg.starts_with("Kp {"), "{dbg}");
assert!(dbg.contains("root_ty") && dbg.contains("value_ty"), "{dbg}");
let disp = format!("{kp}");
assert!(disp.contains("TestKP"), "{disp}");
assert!(disp.contains("String"), "{disp}");
}
#[test]
fn akp_and_pkp_debug_display() {
let akp = AKp::new(TestKP::a());
assert!(format!("{akp:?}").starts_with("AKp"));
let pkp = PKp::new(TestKP::a());
let pkp_dbg = format!("{pkp:?}");
assert!(pkp_dbg.starts_with("PKp"), "{pkp_dbg}");
assert!(format!("{pkp}").contains("TestKP"));
}
#[test]
fn enum_kp_debug_display() {
let ok_kp = enum_ok::<i32, String>();
assert!(format!("{ok_kp:?}").contains("EnumKp"));
let s = format!("{ok_kp}");
assert!(s.contains("Result") && s.contains("i32"), "{s}");
}
#[test]
fn composed_kp_into_dynamic_stores_as_kp_dynamic() {
let path: KpDynamic<TestKP, String> = TestKP::f().then(TestKP2::a()).into_dynamic();
let mut t = TestKP::new();
assert_eq!(path.get(&t), Some(&"a3".to_string()));
path.get_mut(&mut t).map(|s| *s = "x".into());
assert_eq!(t.f.as_ref().unwrap().a, "x");
}
#[derive(Debug)]
struct TestKP2 {
a: String,
b: std::sync::Arc<std::sync::Mutex<TestKP3>>,
}
impl TestKP2 {
fn new() -> Self {
TestKP2 {
a: String::from("a2"),
b: std::sync::Arc::new(std::sync::Mutex::new(TestKP3::new())),
}
}
fn identity_typed<Root, MutRoot, G, S>() -> Kp<
TestKP2, TestKP2, Root, Root, MutRoot, MutRoot, fn(Root) -> Option<Root>,
fn(MutRoot) -> Option<MutRoot>,
>
where
Root: std::borrow::Borrow<TestKP2>,
MutRoot: std::borrow::BorrowMut<TestKP2>,
G: Fn(Root) -> Option<Root>,
S: Fn(MutRoot) -> Option<MutRoot>,
{
Kp::<TestKP2, TestKP2, Root, Root, MutRoot, MutRoot, G, S>::identity_typed()
}
fn a<'a>() -> KpType<'a, TestKP2, String> {
KpType::new(|r: &TestKP2| Some(&r.a), |r: &mut TestKP2| Some(&mut r.a))
}
fn b<'a>() -> KpType<'a, TestKP2, std::sync::Arc<std::sync::Mutex<TestKP3>>> {
KpType::new(|r: &TestKP2| Some(&r.b), |r: &mut TestKP2| Some(&mut r.b))
}
fn identity<'a>() -> KpType<'a, TestKP2, TestKP2> {
KpType::identity()
}
}
#[derive(Debug)]
struct TestKP3 {
a: String,
b: std::sync::Arc<std::sync::Mutex<String>>,
}
impl TestKP3 {
fn new() -> Self {
TestKP3 {
a: String::from("a2"),
b: std::sync::Arc::new(std::sync::Mutex::new(String::from("b2"))),
}
}
fn identity_typed<Root, MutRoot, G, S>() -> Kp<
TestKP3, TestKP3, Root, Root, MutRoot, MutRoot, fn(Root) -> Option<Root>,
fn(MutRoot) -> Option<MutRoot>,
>
where
Root: std::borrow::Borrow<TestKP3>,
MutRoot: std::borrow::BorrowMut<TestKP3>,
G: Fn(Root) -> Option<Root>,
S: Fn(MutRoot) -> Option<MutRoot>,
{
Kp::<TestKP3, TestKP3, Root, Root, MutRoot, MutRoot, G, S>::identity_typed()
}
fn identity<'a>() -> KpType<'a, TestKP3, TestKP3> {
KpType::identity()
}
}
impl TestKP3 {}
impl TestKP {}
#[test]
fn test_a() {
let instance2 = TestKP2::new();
let mut instance = TestKP::new();
let kp = TestKP::identity();
let kp_a = TestKP::a();
let wres = TestKP::f()
.then(TestKP2::a())
.get_mut(&mut instance)
.unwrap();
*wres = String::from("a3 changed successfully");
let res = (TestKP::f().then(TestKP2::a()).get)(&instance);
println!("{:?}", res);
let res = (TestKP::f().then(TestKP2::identity()).get)(&instance);
println!("{:?}", res);
let res = (kp.get)(&instance);
println!("{:?}", res);
let new_kp_from_hashmap = TestKP::g(0).then(TestKP2::a());
println!("{:?}", (new_kp_from_hashmap.get)(&instance));
}
#[test]
fn test_enum_kp_result_ok() {
let ok_result: Result<String, i32> = Ok("success".to_string());
let mut err_result: Result<String, i32> = Err(42);
let ok_kp = enum_ok();
assert_eq!(ok_kp.get(&ok_result), Some(&"success".to_string()));
assert_eq!(ok_kp.get(&err_result), None);
let embedded = ok_kp.embed("embedded".to_string());
assert_eq!(embedded, Ok("embedded".to_string()));
if let Some(val) = ok_kp.get_mut(&mut err_result) {
*val = "modified".to_string();
}
assert_eq!(err_result, Err(42));
let mut ok_result2 = Ok("original".to_string());
if let Some(val) = ok_kp.get_mut(&mut ok_result2) {
*val = "modified".to_string();
}
assert_eq!(ok_result2, Ok("modified".to_string()));
}
#[test]
fn test_enum_kp_result_err() {
let ok_result: Result<String, i32> = Ok("success".to_string());
let mut err_result: Result<String, i32> = Err(42);
let err_kp = enum_err();
assert_eq!(err_kp.get(&err_result), Some(&42));
assert_eq!(err_kp.get(&ok_result), None);
let embedded = err_kp.embed(99);
assert_eq!(embedded, Err(99));
if let Some(val) = err_kp.get_mut(&mut err_result) {
*val = 100;
}
assert_eq!(err_result, Err(100));
}
#[test]
fn test_enum_kp_option_some() {
let some_opt = Some("value".to_string());
let mut none_opt: Option<String> = None;
let some_kp = enum_some();
assert_eq!(some_kp.get(&some_opt), Some(&"value".to_string()));
assert_eq!(some_kp.get(&none_opt), None);
let embedded = some_kp.embed("embedded".to_string());
assert_eq!(embedded, Some("embedded".to_string()));
let mut some_opt2 = Some("original".to_string());
if let Some(val) = some_kp.get_mut(&mut some_opt2) {
*val = "modified".to_string();
}
assert_eq!(some_opt2, Some("modified".to_string()));
}
#[test]
fn test_enum_kp_custom_enum() {
#[derive(Debug, PartialEq)]
enum MyEnum {
A(String),
B(i32),
C,
}
let mut enum_a = MyEnum::A("hello".to_string());
let enum_b = MyEnum::B(42);
let enum_c = MyEnum::C;
let kp_a = enum_variant(
|e: &MyEnum| match e {
MyEnum::A(s) => Some(s),
_ => None,
},
|e: &mut MyEnum| match e {
MyEnum::A(s) => Some(s),
_ => None,
},
|s: String| MyEnum::A(s),
);
assert_eq!(kp_a.get(&enum_a), Some(&"hello".to_string()));
assert_eq!(kp_a.get(&enum_b), None);
assert_eq!(kp_a.get(&enum_c), None);
let embedded = kp_a.embed("world".to_string());
assert_eq!(embedded, MyEnum::A("world".to_string()));
if let Some(val) = kp_a.get_mut(&mut enum_a) {
*val = "modified".to_string();
}
assert_eq!(enum_a, MyEnum::A("modified".to_string()));
}
#[test]
fn test_container_kp_box() {
let boxed = Box::new("value".to_string());
let mut boxed_mut = Box::new("original".to_string());
let box_kp = kp_box();
assert_eq!((box_kp.get)(&boxed), Some(&"value".to_string()));
if let Some(val) = box_kp.get_mut(&mut boxed_mut) {
*val = "modified".to_string();
}
assert_eq!(*boxed_mut, "modified".to_string());
}
#[test]
fn test_container_kp_arc() {
let arc = Arc::new("value".to_string());
let mut arc_mut = Arc::new("original".to_string());
let arc_kp = kp_arc();
assert_eq!((arc_kp.get)(&arc), Some(&"value".to_string()));
if let Some(val) = arc_kp.get_mut(&mut arc_mut) {
*val = "modified".to_string();
}
assert_eq!(*arc_mut, "modified".to_string());
let arc_shared = Arc::new("shared".to_string());
let arc_shared2 = Arc::clone(&arc_shared);
let mut arc_shared_mut = arc_shared;
assert_eq!(arc_kp.get_mut(&mut arc_shared_mut), None);
}
#[test]
fn test_enum_kp_composition() {
#[derive(Debug, PartialEq)]
struct Inner {
value: String,
}
let result: Result<Inner, i32> = Ok(Inner {
value: "nested".to_string(),
});
let inner_kp = KpType::new(
|i: &Inner| Some(&i.value),
|i: &mut Inner| Some(&mut i.value),
);
let ok_kp = enum_ok::<Inner, i32>();
let ok_kp_base = ok_kp.into_kp();
let composed = ok_kp_base.then(inner_kp);
assert_eq!((composed.get)(&result), Some(&"nested".to_string()));
}
#[test]
fn test_pkp_basic() {
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
let user = User {
name: "Akash".to_string(),
age: 30,
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let name_pkp = PKp::new(name_kp);
let age_pkp = PKp::new(age_kp);
assert_eq!(name_pkp.get_as::<String>(&user), Some(&"Akash".to_string()));
assert_eq!(age_pkp.get_as::<i32>(&user), Some(&30));
assert_eq!(name_pkp.get_as::<i32>(&user), None);
assert_eq!(age_pkp.get_as::<String>(&user), None);
assert_eq!(name_pkp.value_type_id(), TypeId::of::<String>());
assert_eq!(age_pkp.value_type_id(), TypeId::of::<i32>());
}
#[test]
fn test_pkp_collection() {
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
let user = User {
name: "Bob".to_string(),
age: 25,
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let keypaths: Vec<PKp<User>> = vec![PKp::new(name_kp), PKp::new(age_kp)];
let name_value = keypaths[0].get_as::<String>(&user);
let age_value = keypaths[1].get_as::<i32>(&user);
assert_eq!(name_value, Some(&"Bob".to_string()));
assert_eq!(age_value, Some(&25));
}
#[test]
fn test_pkp_for_arc() {
#[derive(Debug)]
struct User {
name: String,
}
let user = Arc::new(User {
name: "Charlie".to_string(),
});
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let name_pkp = PKp::new(name_kp);
let arc_pkp = name_pkp.for_arc();
assert_eq!(
arc_pkp.get_as::<String>(&user),
Some(&"Charlie".to_string())
);
}
#[test]
fn test_pkp_for_option() {
#[derive(Debug)]
struct User {
name: String,
}
let some_user = Some(User {
name: "Diana".to_string(),
});
let none_user: Option<User> = None;
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let name_pkp = PKp::new(name_kp);
let opt_pkp = name_pkp.for_option();
assert_eq!(
opt_pkp.get_as::<String>(&some_user),
Some(&"Diana".to_string())
);
assert_eq!(opt_pkp.get_as::<String>(&none_user), None);
}
#[test]
fn test_akp_basic() {
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
#[derive(Debug)]
struct Product {
title: String,
price: f64,
}
let user = User {
name: "Eve".to_string(),
age: 28,
};
let product = Product {
title: "Book".to_string(),
price: 19.99,
};
let user_name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let user_name_akp = AKp::new(user_name_kp);
let product_title_kp = KpType::new(
|p: &Product| Some(&p.title),
|p: &mut Product| Some(&mut p.title),
);
let product_title_akp = AKp::new(product_title_kp);
assert_eq!(
user_name_akp.get_as::<User, String>(&user),
Some(Some(&"Eve".to_string()))
);
assert_eq!(
product_title_akp.get_as::<Product, String>(&product),
Some(Some(&"Book".to_string()))
);
assert_eq!(user_name_akp.get_as::<Product, String>(&product), None);
assert_eq!(product_title_akp.get_as::<User, String>(&user), None);
assert_eq!(user_name_akp.root_type_id(), TypeId::of::<User>());
assert_eq!(user_name_akp.value_type_id(), TypeId::of::<String>());
assert_eq!(product_title_akp.root_type_id(), TypeId::of::<Product>());
assert_eq!(product_title_akp.value_type_id(), TypeId::of::<String>());
}
#[test]
fn test_akp_heterogeneous_collection() {
#[derive(Debug)]
struct User {
name: String,
}
#[derive(Debug)]
struct Product {
title: String,
}
let user = User {
name: "Frank".to_string(),
};
let product = Product {
title: "Laptop".to_string(),
};
let user_name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let product_title_kp = KpType::new(
|p: &Product| Some(&p.title),
|p: &mut Product| Some(&mut p.title),
);
let keypaths: Vec<AKp> = vec![AKp::new(user_name_kp), AKp::new(product_title_kp)];
let user_any: &dyn Any = &user;
let product_any: &dyn Any = &product;
let user_value = keypaths[0].get(user_any);
let product_value = keypaths[1].get(product_any);
assert!(user_value.is_some());
assert!(product_value.is_some());
assert_eq!(
user_value.and_then(|v| v.downcast_ref::<String>()),
Some(&"Frank".to_string())
);
assert_eq!(
product_value.and_then(|v| v.downcast_ref::<String>()),
Some(&"Laptop".to_string())
);
}
#[test]
fn test_akp_for_option() {
#[derive(Debug)]
struct User {
name: String,
}
let some_user = Some(User {
name: "Grace".to_string(),
});
let none_user: Option<User> = None;
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let name_akp = AKp::new(name_kp);
let opt_akp = name_akp.for_option::<User>();
assert_eq!(
opt_akp.get_as::<Option<User>, String>(&some_user),
Some(Some(&"Grace".to_string()))
);
assert_eq!(
opt_akp.get_as::<Option<User>, String>(&none_user),
Some(None)
);
}
#[test]
fn test_akp_for_result() {
#[derive(Debug)]
struct User {
name: String,
}
let ok_user: Result<User, String> = Ok(User {
name: "Henry".to_string(),
});
let err_user: Result<User, String> = Err("Not found".to_string());
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let name_akp = AKp::new(name_kp);
let result_akp = name_akp.for_result::<User, String>();
assert_eq!(
result_akp.get_as::<Result<User, String>, String>(&ok_user),
Some(Some(&"Henry".to_string()))
);
assert_eq!(
result_akp.get_as::<Result<User, String>, String>(&err_user),
Some(None)
);
}
#[test]
fn test_kp_map() {
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
let user = User {
name: "Akash".to_string(),
age: 30,
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let len_kp = name_kp.map(|name: &String| name.len());
assert_eq!((len_kp.get)(&user), Some(5));
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let double_age_kp = age_kp.map(|age: &i32| age * 2);
assert_eq!((double_age_kp.get)(&user), Some(60));
let is_adult_kp = age_kp.map(|age: &i32| *age >= 18);
assert_eq!((is_adult_kp.get)(&user), Some(true));
}
#[test]
fn test_kp_filter() {
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
let adult = User {
name: "Akash".to_string(),
age: 30,
};
let minor = User {
name: "Bob".to_string(),
age: 15,
};
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let adult_age_kp = age_kp.filter(|age: &i32| *age >= 18);
assert_eq!((adult_age_kp.get)(&adult), Some(&30));
assert_eq!((adult_age_kp.get)(&minor), None);
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let short_name_kp = name_kp.filter(|name: &String| name.len() <= 4);
assert_eq!((short_name_kp.get)(&minor), Some(&"Bob".to_string()));
assert_eq!((short_name_kp.get)(&adult), None);
}
#[test]
fn test_kp_map_and_filter() {
#[derive(Debug)]
struct User {
scores: Vec<i32>,
}
let user = User {
scores: vec![85, 92, 78, 95],
};
let scores_kp = KpType::new(
|u: &User| Some(&u.scores),
|u: &mut User| Some(&mut u.scores),
);
let avg_kp =
scores_kp.map(|scores: &Vec<i32>| scores.iter().sum::<i32>() / scores.len() as i32);
let high_avg_kp = avg_kp.filter(|avg: &i32| *avg >= 85);
assert_eq!((high_avg_kp.get)(&user), Some(87)); }
#[test]
fn test_enum_kp_map() {
let ok_result: Result<String, i32> = Ok("hello".to_string());
let err_result: Result<String, i32> = Err(42);
let ok_kp = enum_ok::<String, i32>();
let len_kp = ok_kp.map(|s: &String| s.len());
assert_eq!(len_kp.get(&ok_result), Some(5));
assert_eq!(len_kp.get(&err_result), None);
let some_opt = Some(vec![1, 2, 3, 4, 5]);
let none_opt: Option<Vec<i32>> = None;
let some_kp = enum_some::<Vec<i32>>();
let count_kp = some_kp.map(|vec: &Vec<i32>| vec.len());
assert_eq!(count_kp.get(&some_opt), Some(5));
assert_eq!(count_kp.get(&none_opt), None);
}
#[test]
fn test_enum_kp_filter() {
let ok_result1: Result<i32, String> = Ok(42);
let ok_result2: Result<i32, String> = Ok(-5);
let err_result: Result<i32, String> = Err("error".to_string());
let ok_kp = enum_ok::<i32, String>();
let positive_kp = ok_kp.filter(|x: &i32| *x > 0);
assert_eq!((positive_kp.extractor.get)(&ok_result1), Some(&42));
assert_eq!(positive_kp.get(&ok_result2), None); assert_eq!(positive_kp.get(&err_result), None);
let long_str = Some("hello world".to_string());
let short_str = Some("hi".to_string());
let some_kp = enum_some::<String>();
let long_kp = some_kp.filter(|s: &String| s.len() > 5);
assert_eq!(long_kp.get(&long_str), Some(&"hello world".to_string()));
assert_eq!(long_kp.get(&short_str), None);
}
#[test]
fn test_pkp_filter() {
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
let adult = User {
name: "Akash".to_string(),
age: 30,
};
let minor = User {
name: "Bob".to_string(),
age: 15,
};
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let age_pkp = PKp::new(age_kp);
let adult_pkp = age_pkp.filter::<i32, _>(|age| *age >= 18);
assert_eq!(adult_pkp.get_as::<i32>(&adult), Some(&30));
assert_eq!(adult_pkp.get_as::<i32>(&minor), None);
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let name_pkp = PKp::new(name_kp);
let short_name_pkp = name_pkp.filter::<String, _>(|name| name.len() <= 4);
assert_eq!(
short_name_pkp.get_as::<String>(&minor),
Some(&"Bob".to_string())
);
assert_eq!(short_name_pkp.get_as::<String>(&adult), None);
}
#[test]
fn test_akp_filter() {
#[derive(Debug)]
struct User {
age: i32,
}
#[derive(Debug)]
struct Product {
price: f64,
}
let adult = User { age: 30 };
let minor = User { age: 15 };
let expensive = Product { price: 99.99 };
let cheap = Product { price: 5.0 };
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let age_akp = AKp::new(age_kp);
let adult_akp = age_akp.filter::<User, i32, _>(|age| *age >= 18);
assert_eq!(adult_akp.get_as::<User, i32>(&adult), Some(Some(&30)));
assert_eq!(adult_akp.get_as::<User, i32>(&minor), Some(None));
let price_kp = KpType::new(
|p: &Product| Some(&p.price),
|p: &mut Product| Some(&mut p.price),
);
let price_akp = AKp::new(price_kp);
let expensive_akp = price_akp.filter::<Product, f64, _>(|price| *price > 50.0);
assert_eq!(
expensive_akp.get_as::<Product, f64>(&expensive),
Some(Some(&99.99))
);
assert_eq!(expensive_akp.get_as::<Product, f64>(&cheap), Some(None));
}
#[test]
fn test_kp_filter_map() {
#[derive(Debug)]
struct User {
middle_name: Option<String>,
}
let user_with = User {
middle_name: Some("Marie".to_string()),
};
let user_without = User { middle_name: None };
let middle_kp = KpType::new(
|u: &User| Some(&u.middle_name),
|u: &mut User| Some(&mut u.middle_name),
);
let first_char_kp = middle_kp
.filter_map(|opt: &Option<String>| opt.as_ref().and_then(|s| s.chars().next()));
assert_eq!((first_char_kp.get)(&user_with), Some('M'));
assert_eq!((first_char_kp.get)(&user_without), None);
}
#[test]
fn test_kp_inspect() {
#[derive(Debug)]
struct User {
name: String,
}
let user = User {
name: "Akash".to_string(),
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let result = (name_kp.get)(&user);
assert_eq!(result, Some(&"Akash".to_string()));
}
#[test]
fn test_kp_fold_value() {
#[derive(Debug)]
struct User {
scores: Vec<i32>,
}
let user = User {
scores: vec![85, 92, 78, 95],
};
let scores_kp = KpType::new(
|u: &User| Some(&u.scores),
|u: &mut User| Some(&mut u.scores),
);
let sum_fn =
scores_kp.fold_value(0, |acc, scores: &Vec<i32>| scores.iter().sum::<i32>() + acc);
assert_eq!(sum_fn(&user), 350);
}
#[test]
fn test_kp_any_all() {
#[derive(Debug)]
struct User {
scores: Vec<i32>,
}
let user_high = User {
scores: vec![85, 92, 88],
};
let user_mixed = User {
scores: vec![65, 92, 78],
};
let scores_kp = KpType::new(
|u: &User| Some(&u.scores),
|u: &mut User| Some(&mut u.scores),
);
let has_high_fn = scores_kp.any(|scores: &Vec<i32>| scores.iter().any(|&s| s > 90));
assert!(has_high_fn(&user_high));
assert!(has_high_fn(&user_mixed));
let all_passing_fn = scores_kp.all(|scores: &Vec<i32>| scores.iter().all(|&s| s >= 80));
assert!(all_passing_fn(&user_high));
assert!(!all_passing_fn(&user_mixed));
}
#[test]
fn test_kp_count_items() {
#[derive(Debug)]
struct User {
tags: Vec<String>,
}
let user = User {
tags: vec!["rust".to_string(), "web".to_string(), "backend".to_string()],
};
let tags_kp = KpType::new(|u: &User| Some(&u.tags), |u: &mut User| Some(&mut u.tags));
let count_fn = tags_kp.count_items(|tags: &Vec<String>| tags.len());
assert_eq!(count_fn(&user), Some(3));
}
#[test]
fn test_kp_find_in() {
#[derive(Debug)]
struct User {
scores: Vec<i32>,
}
let user = User {
scores: vec![85, 92, 78, 95, 88],
};
let scores_kp = KpType::new(
|u: &User| Some(&u.scores),
|u: &mut User| Some(&mut u.scores),
);
let first_high_fn =
scores_kp.find_in(|scores: &Vec<i32>| scores.iter().find(|&&s| s > 90).copied());
assert_eq!(first_high_fn(&user), Some(92));
let perfect_fn =
scores_kp.find_in(|scores: &Vec<i32>| scores.iter().find(|&&s| s > 100).copied());
assert_eq!(perfect_fn(&user), None);
}
#[test]
fn test_kp_take_skip() {
#[derive(Debug)]
struct User {
tags: Vec<String>,
}
let user = User {
tags: vec![
"a".to_string(),
"b".to_string(),
"c".to_string(),
"d".to_string(),
],
};
let tags_kp = KpType::new(|u: &User| Some(&u.tags), |u: &mut User| Some(&mut u.tags));
let take_fn = tags_kp.take(2, |tags: &Vec<String>, n| {
tags.iter().take(n).cloned().collect::<Vec<_>>()
});
let taken = take_fn(&user).unwrap();
assert_eq!(taken, vec!["a".to_string(), "b".to_string()]);
let skip_fn = tags_kp.skip(2, |tags: &Vec<String>, n| {
tags.iter().skip(n).cloned().collect::<Vec<_>>()
});
let skipped = skip_fn(&user).unwrap();
assert_eq!(skipped, vec!["c".to_string(), "d".to_string()]);
}
#[test]
fn test_kp_partition() {
#[derive(Debug)]
struct User {
scores: Vec<i32>,
}
let user = User {
scores: vec![85, 92, 65, 95, 72, 58],
};
let scores_kp = KpType::new(
|u: &User| Some(&u.scores),
|u: &mut User| Some(&mut u.scores),
);
let partition_fn = scores_kp.partition_value(|scores: &Vec<i32>| -> (Vec<i32>, Vec<i32>) {
scores.iter().copied().partition(|&s| s >= 70)
});
let (passing, failing) = partition_fn(&user).unwrap();
assert_eq!(passing, vec![85, 92, 95, 72]);
assert_eq!(failing, vec![65, 58]);
}
#[test]
fn test_kp_min_max() {
#[derive(Debug)]
struct User {
scores: Vec<i32>,
}
let user = User {
scores: vec![85, 92, 78, 95, 88],
};
let scores_kp = KpType::new(
|u: &User| Some(&u.scores),
|u: &mut User| Some(&mut u.scores),
);
let min_fn = scores_kp.min_value(|scores: &Vec<i32>| scores.iter().min().copied());
assert_eq!(min_fn(&user), Some(78));
let max_fn = scores_kp.max_value(|scores: &Vec<i32>| scores.iter().max().copied());
assert_eq!(max_fn(&user), Some(95));
}
#[test]
fn test_kp_sum() {
#[derive(Debug)]
struct User {
scores: Vec<i32>,
}
let user = User {
scores: vec![85, 92, 78],
};
let scores_kp = KpType::new(
|u: &User| Some(&u.scores),
|u: &mut User| Some(&mut u.scores),
);
let sum_fn = scores_kp.sum_value(|scores: &Vec<i32>| scores.iter().sum::<i32>());
assert_eq!(sum_fn(&user), Some(255));
let avg_fn =
scores_kp.map(|scores: &Vec<i32>| scores.iter().sum::<i32>() / scores.len() as i32);
assert_eq!(avg_fn.get(&user), Some(85));
}
#[test]
fn test_kp_chain() {
#[derive(Debug)]
struct User {
profile: Profile,
}
#[derive(Debug)]
struct Profile {
settings: Settings,
}
#[derive(Debug)]
struct Settings {
theme: String,
}
let user = User {
profile: Profile {
settings: Settings {
theme: "dark".to_string(),
},
},
};
let profile_kp = KpType::new(
|u: &User| Some(&u.profile),
|u: &mut User| Some(&mut u.profile),
);
let settings_kp = KpType::new(
|p: &Profile| Some(&p.settings),
|p: &mut Profile| Some(&mut p.settings),
);
let theme_kp = KpType::new(
|s: &Settings| Some(&s.theme),
|s: &mut Settings| Some(&mut s.theme),
);
let profile_settings = profile_kp.then(settings_kp);
let theme_path = profile_settings.then(theme_kp);
assert_eq!(theme_path.get(&user), Some(&"dark".to_string()));
}
#[test]
fn test_kp_zip() {
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
let user = User {
name: "Akash".to_string(),
age: 30,
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let zipped_fn = zip_kps(&name_kp, &age_kp);
let result = zipped_fn(&user);
assert_eq!(result, Some((&"Akash".to_string(), &30)));
}
#[test]
fn test_kp_complex_pipeline() {
#[derive(Debug)]
struct User {
transactions: Vec<Transaction>,
}
#[derive(Debug)]
struct Transaction {
amount: f64,
category: String,
}
let user = User {
transactions: vec![
Transaction {
amount: 50.0,
category: "food".to_string(),
},
Transaction {
amount: 100.0,
category: "transport".to_string(),
},
Transaction {
amount: 25.0,
category: "food".to_string(),
},
Transaction {
amount: 200.0,
category: "shopping".to_string(),
},
],
};
let txns_kp = KpType::new(
|u: &User| Some(&u.transactions),
|u: &mut User| Some(&mut u.transactions),
);
let food_total = txns_kp.map(|txns: &Vec<Transaction>| {
txns.iter()
.filter(|t| t.category == "food")
.map(|t| t.amount)
.sum::<f64>()
});
assert_eq!(food_total.get(&user), Some(75.0));
let has_large =
txns_kp.any(|txns: &Vec<Transaction>| txns.iter().any(|t| t.amount > 150.0));
assert!(has_large(&user));
let count = txns_kp.count_items(|txns: &Vec<Transaction>| txns.len());
assert_eq!(count(&user), Some(4));
}
#[test]
fn test_no_clone_required_for_root() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
struct NonCloneableRoot {
data: Arc<AtomicUsize>,
cached_value: usize,
}
impl NonCloneableRoot {
fn new() -> Self {
Self {
data: Arc::new(AtomicUsize::new(42)),
cached_value: 42,
}
}
fn increment(&mut self) {
self.data.fetch_add(1, Ordering::SeqCst);
self.cached_value = self.data.load(Ordering::SeqCst);
}
fn get_value(&self) -> &usize {
&self.cached_value
}
fn get_value_mut(&mut self) -> &mut usize {
&mut self.cached_value
}
}
let mut root = NonCloneableRoot::new();
let data_kp = KpType::new(
|r: &NonCloneableRoot| Some(r.get_value()),
|r: &mut NonCloneableRoot| {
r.increment();
Some(r.get_value_mut())
},
);
assert_eq!(data_kp.get(&root), Some(&42));
{
let doubled = data_kp.map(|val: &usize| val * 2);
assert_eq!(doubled.get(&root), Some(84));
let filtered = data_kp.filter(|val: &usize| *val > 0);
assert_eq!(filtered.get(&root), Some(&42));
}
let value_ref = data_kp.get_mut(&mut root);
assert!(value_ref.is_some());
}
#[test]
fn test_no_clone_required_for_value() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
struct NonCloneableValue {
counter: Arc<AtomicUsize>,
}
impl NonCloneableValue {
fn new(val: usize) -> Self {
Self {
counter: Arc::new(AtomicUsize::new(val)),
}
}
fn get(&self) -> usize {
self.counter.load(Ordering::SeqCst)
}
}
struct Root {
value: NonCloneableValue,
}
let root = Root {
value: NonCloneableValue::new(100),
};
let value_kp = KpType::new(|r: &Root| Some(&r.value), |r: &mut Root| Some(&mut r.value));
let counter_kp = value_kp.map(|v: &NonCloneableValue| v.get());
assert_eq!(counter_kp.get(&root), Some(100));
let filtered = value_kp.filter(|v: &NonCloneableValue| v.get() >= 50);
assert!(filtered.get(&root).is_some());
}
#[test]
fn test_static_does_not_leak_memory() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
static CREATED: AtomicUsize = AtomicUsize::new(0);
static DROPPED: AtomicUsize = AtomicUsize::new(0);
struct Tracked {
id: usize,
}
impl Tracked {
fn new() -> Self {
let id = CREATED.fetch_add(1, Ordering::SeqCst);
Self { id }
}
}
impl Drop for Tracked {
fn drop(&mut self) {
DROPPED.fetch_add(1, Ordering::SeqCst);
}
}
struct Root {
data: Tracked,
}
CREATED.store(0, Ordering::SeqCst);
DROPPED.store(0, Ordering::SeqCst);
{
let root = Root {
data: Tracked::new(),
};
let data_kp = KpType::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
let mapped1 = data_kp.map(|t: &Tracked| t.id);
let mapped2 = data_kp.map(|t: &Tracked| t.id + 1);
let mapped3 = data_kp.map(|t: &Tracked| t.id + 2);
assert_eq!(mapped1.get(&root), Some(0));
assert_eq!(mapped2.get(&root), Some(1));
assert_eq!(mapped3.get(&root), Some(2));
assert_eq!(CREATED.load(Ordering::SeqCst), 1);
assert_eq!(DROPPED.load(Ordering::SeqCst), 0);
}
assert_eq!(CREATED.load(Ordering::SeqCst), 1);
assert_eq!(DROPPED.load(Ordering::SeqCst), 1);
}
#[test]
fn test_references_not_cloned() {
use std::sync::Arc;
struct ExpensiveData {
large_vec: Vec<u8>,
}
impl ExpensiveData {
fn new(size: usize) -> Self {
Self {
large_vec: vec![0u8; size],
}
}
fn size(&self) -> usize {
self.large_vec.len()
}
}
struct Root {
expensive: ExpensiveData,
}
let root = Root {
expensive: ExpensiveData::new(1_000_000), };
let expensive_kp = KpType::new(
|r: &Root| Some(&r.expensive),
|r: &mut Root| Some(&mut r.expensive),
);
let size_kp = expensive_kp.map(|e: &ExpensiveData| e.size());
assert_eq!(size_kp.get(&root), Some(1_000_000));
let large_filter = expensive_kp.filter(|e: &ExpensiveData| e.size() > 500_000);
assert!(large_filter.get(&root).is_some());
}
#[test]
fn test_hof_with_arc_no_extra_clones() {
use std::sync::Arc;
#[derive(Debug)]
struct SharedData {
value: String,
}
struct Root {
shared: Arc<SharedData>,
}
let shared = Arc::new(SharedData {
value: "shared".to_string(),
});
assert_eq!(Arc::strong_count(&shared), 1);
{
let root = Root {
shared: Arc::clone(&shared),
};
assert_eq!(Arc::strong_count(&shared), 2);
let shared_kp = KpType::new(
|r: &Root| Some(&r.shared),
|r: &mut Root| Some(&mut r.shared),
);
let value_kp = shared_kp.map(|arc: &Arc<SharedData>| arc.value.len());
assert_eq!(value_kp.get(&root), Some(6));
assert_eq!(Arc::strong_count(&shared), 2);
let filtered = shared_kp.filter(|arc: &Arc<SharedData>| !arc.value.is_empty());
assert!(filtered.get(&root).is_some());
assert_eq!(Arc::strong_count(&shared), 2); }
assert_eq!(Arc::strong_count(&shared), 1); }
#[test]
fn test_closure_captures_not_root_values() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
let call_count = Arc::new(AtomicUsize::new(0));
let call_count_clone = Arc::clone(&call_count);
struct Root {
value: i32,
}
let root = Root { value: 42 };
let value_kp = KpType::new(|r: &Root| Some(&r.value), |r: &mut Root| Some(&mut r.value));
let doubled = value_kp.fold_value(0, move |_acc, v: &i32| {
call_count_clone.fetch_add(1, Ordering::SeqCst);
v * 2
});
assert_eq!(doubled(&root), 84);
assert_eq!(doubled(&root), 84);
assert_eq!(doubled(&root), 84);
assert_eq!(call_count.load(Ordering::SeqCst), 3);
}
#[test]
fn test_static_with_borrowed_data() {
struct Root {
data: String,
}
{
let root = Root {
data: "temporary".to_string(),
};
let data_kp = KpType::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
let len_kp = data_kp.map(|s: &String| s.len());
assert_eq!(len_kp.get(&root), Some(9));
}
}
#[test]
fn test_multiple_hof_operations_no_accumulation() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
struct Tracked {
id: usize,
}
impl Drop for Tracked {
fn drop(&mut self) {
DROP_COUNT.fetch_add(1, Ordering::SeqCst);
}
}
struct Root {
values: Vec<Tracked>,
}
DROP_COUNT.store(0, Ordering::SeqCst);
{
let root = Root {
values: vec![Tracked { id: 1 }, Tracked { id: 2 }, Tracked { id: 3 }],
};
let values_kp = KpType::new(
|r: &Root| Some(&r.values),
|r: &mut Root| Some(&mut r.values),
);
let count = values_kp.count_items(|v| v.len());
let sum = values_kp.sum_value(|v| v.iter().map(|t| t.id).sum::<usize>());
let has_2 = values_kp.any(|v| v.iter().any(|t| t.id == 2));
let all_positive = values_kp.all(|v| v.iter().all(|t| t.id > 0));
assert_eq!(count(&root), Some(3));
assert_eq!(sum(&root), Some(6));
assert!(has_2(&root));
assert!(all_positive(&root));
assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 0);
}
assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3);
}
#[test]
fn test_copy_bound_only_for_function_not_data() {
#[derive(Debug)]
struct NonCopyData {
value: String,
}
struct Root {
data: NonCopyData,
}
let root = Root {
data: NonCopyData {
value: "test".to_string(),
},
};
let data_kp = KpType::new(|r: &Root| Some(&r.data), |r: &mut Root| Some(&mut r.data));
let len_kp = data_kp.map(|d: &NonCopyData| d.value.len());
assert_eq!(len_kp.get(&root), Some(4));
let filtered = data_kp.filter(|d: &NonCopyData| !d.value.is_empty());
assert!(filtered.get(&root).is_some());
}
#[test]
fn test_no_memory_leak_with_cyclic_references() {
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Weak};
static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
struct Node {
id: usize,
parent: Option<Weak<Node>>,
}
impl Drop for Node {
fn drop(&mut self) {
DROP_COUNT.fetch_add(1, Ordering::SeqCst);
}
}
struct Root {
node: Arc<Node>,
}
DROP_COUNT.store(0, Ordering::SeqCst);
{
let root = Root {
node: Arc::new(Node {
id: 1,
parent: None,
}),
};
let node_kp = KpType::new(|r: &Root| Some(&r.node), |r: &mut Root| Some(&mut r.node));
let id_kp = node_kp.map(|n: &Arc<Node>| n.id);
assert_eq!(id_kp.get(&root), Some(1));
assert_eq!(Arc::strong_count(&root.node), 1);
assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 0);
}
assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1);
}
#[test]
fn test_hof_operations_are_zero_cost_abstractions() {
struct Root {
value: i32,
}
let root = Root { value: 10 };
let value_kp = KpType::new(|r: &Root| Some(&r.value), |r: &mut Root| Some(&mut r.value));
let direct_result = value_kp.get(&root).map(|v| v * 2);
assert_eq!(direct_result, Some(20));
let mapped_kp = value_kp.map(|v: &i32| v * 2);
let hof_result = mapped_kp.get(&root);
assert_eq!(hof_result, Some(20));
assert_eq!(direct_result, hof_result);
}
#[test]
fn test_complex_closure_captures_allowed() {
use std::sync::Arc;
struct Root {
scores: Vec<i32>,
}
let root = Root {
scores: vec![85, 92, 78, 95, 88],
};
let scores_kp = KpType::new(
|r: &Root| Some(&r.scores),
|r: &mut Root| Some(&mut r.scores),
);
let threshold = 90;
let multiplier = Arc::new(2);
let high_scores_doubled = scores_kp.fold_value(0, move |acc, scores| {
let high: i32 = scores
.iter()
.filter(|&&s| s >= threshold)
.map(|&s| s * *multiplier)
.sum();
acc + high
});
assert_eq!(high_scores_doubled(&root), 374);
}
#[test]
fn test_pkp_filter_by_value_type() {
use std::any::TypeId;
#[derive(Debug)]
struct User {
name: String,
age: i32,
score: f64,
active: bool,
}
let user = User {
name: "Akash".to_string(),
age: 30,
score: 95.5,
active: true,
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let score_kp = KpType::new(|u: &User| Some(&u.score), |u: &mut User| Some(&mut u.score));
let active_kp = KpType::new(
|u: &User| Some(&u.active),
|u: &mut User| Some(&mut u.active),
);
let all_keypaths: Vec<PKp<User>> = vec![
PKp::new(name_kp),
PKp::new(age_kp),
PKp::new(score_kp),
PKp::new(active_kp),
];
let string_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<String>())
.collect();
assert_eq!(string_kps.len(), 1);
assert_eq!(
string_kps[0].get_as::<String>(&user),
Some(&"Akash".to_string())
);
let i32_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<i32>())
.collect();
assert_eq!(i32_kps.len(), 1);
assert_eq!(i32_kps[0].get_as::<i32>(&user), Some(&30));
let f64_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<f64>())
.collect();
assert_eq!(f64_kps.len(), 1);
assert_eq!(f64_kps[0].get_as::<f64>(&user), Some(&95.5));
let bool_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<bool>())
.collect();
assert_eq!(bool_kps.len(), 1);
assert_eq!(bool_kps[0].get_as::<bool>(&user), Some(&true));
}
#[test]
fn test_pkp_filter_by_struct_type() {
use std::any::TypeId;
#[derive(Debug, PartialEq)]
struct Address {
street: String,
city: String,
}
#[derive(Debug)]
struct User {
name: String,
age: i32,
address: Address,
}
let user = User {
name: "Bob".to_string(),
age: 25,
address: Address {
street: "123 Main St".to_string(),
city: "NYC".to_string(),
},
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let address_kp = KpType::new(
|u: &User| Some(&u.address),
|u: &mut User| Some(&mut u.address),
);
let all_keypaths: Vec<PKp<User>> =
vec![PKp::new(name_kp), PKp::new(age_kp), PKp::new(address_kp)];
let struct_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<Address>())
.collect();
assert_eq!(struct_kps.len(), 1);
assert_eq!(
struct_kps[0].get_as::<Address>(&user),
Some(&Address {
street: "123 Main St".to_string(),
city: "NYC".to_string(),
})
);
let primitive_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| {
pkp.value_type_id() == TypeId::of::<String>()
|| pkp.value_type_id() == TypeId::of::<i32>()
})
.collect();
assert_eq!(primitive_kps.len(), 2);
}
#[test]
fn test_pkp_filter_by_arc_type() {
use std::any::TypeId;
use std::sync::Arc;
#[derive(Debug)]
struct User {
name: String,
shared_data: Arc<String>,
shared_number: Arc<i32>,
}
let user = User {
name: "Charlie".to_string(),
shared_data: Arc::new("shared".to_string()),
shared_number: Arc::new(42),
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let shared_data_kp = KpType::new(
|u: &User| Some(&u.shared_data),
|u: &mut User| Some(&mut u.shared_data),
);
let shared_number_kp = KpType::new(
|u: &User| Some(&u.shared_number),
|u: &mut User| Some(&mut u.shared_number),
);
let all_keypaths: Vec<PKp<User>> = vec![
PKp::new(name_kp),
PKp::new(shared_data_kp),
PKp::new(shared_number_kp),
];
let arc_string_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<Arc<String>>())
.collect();
assert_eq!(arc_string_kps.len(), 1);
assert_eq!(
arc_string_kps[0]
.get_as::<Arc<String>>(&user)
.map(|arc| arc.as_str()),
Some("shared")
);
let arc_i32_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<Arc<i32>>())
.collect();
assert_eq!(arc_i32_kps.len(), 1);
assert_eq!(
arc_i32_kps[0].get_as::<Arc<i32>>(&user).map(|arc| **arc),
Some(42)
);
let all_arc_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| {
pkp.value_type_id() == TypeId::of::<Arc<String>>()
|| pkp.value_type_id() == TypeId::of::<Arc<i32>>()
})
.collect();
assert_eq!(all_arc_kps.len(), 2);
}
#[test]
fn test_pkp_filter_by_box_type() {
use std::any::TypeId;
#[derive(Debug)]
struct User {
name: String,
boxed_value: Box<i32>,
boxed_string: Box<String>,
}
let user = User {
name: "Diana".to_string(),
boxed_value: Box::new(100),
boxed_string: Box::new("boxed".to_string()),
};
let name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let boxed_value_kp = KpType::new(
|u: &User| Some(&u.boxed_value),
|u: &mut User| Some(&mut u.boxed_value),
);
let boxed_string_kp = KpType::new(
|u: &User| Some(&u.boxed_string),
|u: &mut User| Some(&mut u.boxed_string),
);
let all_keypaths: Vec<PKp<User>> = vec![
PKp::new(name_kp),
PKp::new(boxed_value_kp),
PKp::new(boxed_string_kp),
];
let box_i32_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<Box<i32>>())
.collect();
assert_eq!(box_i32_kps.len(), 1);
assert_eq!(
box_i32_kps[0].get_as::<Box<i32>>(&user).map(|b| **b),
Some(100)
);
let box_string_kps: Vec<_> = all_keypaths
.iter()
.filter(|pkp| pkp.value_type_id() == TypeId::of::<Box<String>>())
.collect();
assert_eq!(box_string_kps.len(), 1);
assert_eq!(
box_string_kps[0]
.get_as::<Box<String>>(&user)
.map(|b| b.as_str()),
Some("boxed")
);
}
#[test]
fn test_akp_filter_by_root_and_value_type() {
use std::any::TypeId;
#[derive(Debug)]
struct User {
name: String,
age: i32,
}
#[derive(Debug)]
struct Product {
title: String,
price: f64,
}
let user = User {
name: "Eve".to_string(),
age: 28,
};
let product = Product {
title: "Book".to_string(),
price: 19.99,
};
let user_name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let user_age_kp = KpType::new(|u: &User| Some(&u.age), |u: &mut User| Some(&mut u.age));
let product_title_kp = KpType::new(
|p: &Product| Some(&p.title),
|p: &mut Product| Some(&mut p.title),
);
let product_price_kp = KpType::new(
|p: &Product| Some(&p.price),
|p: &mut Product| Some(&mut p.price),
);
let all_keypaths: Vec<AKp> = vec![
AKp::new(user_name_kp),
AKp::new(user_age_kp),
AKp::new(product_title_kp),
AKp::new(product_price_kp),
];
let user_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<User>())
.collect();
assert_eq!(user_kps.len(), 2);
let product_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<Product>())
.collect();
assert_eq!(product_kps.len(), 2);
let string_value_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.value_type_id() == TypeId::of::<String>())
.collect();
assert_eq!(string_value_kps.len(), 2);
let user_string_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| {
akp.root_type_id() == TypeId::of::<User>()
&& akp.value_type_id() == TypeId::of::<String>()
})
.collect();
assert_eq!(user_string_kps.len(), 1);
assert_eq!(
user_string_kps[0].get_as::<User, String>(&user),
Some(Some(&"Eve".to_string()))
);
let product_f64_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| {
akp.root_type_id() == TypeId::of::<Product>()
&& akp.value_type_id() == TypeId::of::<f64>()
})
.collect();
assert_eq!(product_f64_kps.len(), 1);
assert_eq!(
product_f64_kps[0].get_as::<Product, f64>(&product),
Some(Some(&19.99))
);
}
#[test]
fn test_akp_filter_by_arc_root_type() {
use std::any::TypeId;
use std::sync::Arc;
#[derive(Debug)]
struct User {
name: String,
}
#[derive(Debug)]
struct Product {
title: String,
}
let user = User {
name: "Frank".to_string(),
};
let product = Product {
title: "Laptop".to_string(),
};
let user_name_kp = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let product_title_kp = KpType::new(
|p: &Product| Some(&p.title),
|p: &mut Product| Some(&mut p.title),
);
let user_akp = AKp::new(user_name_kp).for_arc::<User>();
let product_akp = AKp::new(product_title_kp).for_arc::<Product>();
let all_keypaths: Vec<AKp> = vec![user_akp, product_akp];
let arc_user_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<Arc<User>>())
.collect();
assert_eq!(arc_user_kps.len(), 1);
let arc_user = Arc::new(user);
assert_eq!(
arc_user_kps[0].get_as::<Arc<User>, String>(&arc_user),
Some(Some(&"Frank".to_string()))
);
let arc_product_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<Arc<Product>>())
.collect();
assert_eq!(arc_product_kps.len(), 1);
let arc_product = Arc::new(product);
assert_eq!(
arc_product_kps[0].get_as::<Arc<Product>, String>(&arc_product),
Some(Some(&"Laptop".to_string()))
);
}
#[test]
fn test_akp_filter_by_box_root_type() {
use std::any::TypeId;
#[derive(Debug)]
struct Config {
setting: String,
}
let config = Config {
setting: "enabled".to_string(),
};
let config_kp1 = KpType::new(
|c: &Config| Some(&c.setting),
|c: &mut Config| Some(&mut c.setting),
);
let config_kp2 = KpType::new(
|c: &Config| Some(&c.setting),
|c: &mut Config| Some(&mut c.setting),
);
let regular_akp = AKp::new(config_kp1);
let box_akp = AKp::new(config_kp2).for_box::<Config>();
let all_keypaths: Vec<AKp> = vec![regular_akp, box_akp];
let config_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<Config>())
.collect();
assert_eq!(config_kps.len(), 1);
assert_eq!(
config_kps[0].get_as::<Config, String>(&config),
Some(Some(&"enabled".to_string()))
);
let box_config_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<Box<Config>>())
.collect();
assert_eq!(box_config_kps.len(), 1);
let box_config = Box::new(Config {
setting: "enabled".to_string(),
});
assert_eq!(
box_config_kps[0].get_as::<Box<Config>, String>(&box_config),
Some(Some(&"enabled".to_string()))
);
}
#[test]
fn test_mixed_collection_type_filtering() {
use std::any::TypeId;
use std::sync::Arc;
#[derive(Debug)]
struct User {
name: String,
email: String,
}
#[derive(Debug)]
struct Product {
title: String,
sku: String,
}
let user = User {
name: "Grace".to_string(),
email: "grace@example.com".to_string(),
};
let product = Product {
title: "Widget".to_string(),
sku: "WID-001".to_string(),
};
let user_name_kp1 = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let user_name_kp2 = KpType::new(|u: &User| Some(&u.name), |u: &mut User| Some(&mut u.name));
let user_email_kp1 =
KpType::new(|u: &User| Some(&u.email), |u: &mut User| Some(&mut u.email));
let user_email_kp2 =
KpType::new(|u: &User| Some(&u.email), |u: &mut User| Some(&mut u.email));
let product_title_kp = KpType::new(
|p: &Product| Some(&p.title),
|p: &mut Product| Some(&mut p.title),
);
let product_sku_kp = KpType::new(
|p: &Product| Some(&p.sku),
|p: &mut Product| Some(&mut p.sku),
);
let all_keypaths: Vec<AKp> = vec![
AKp::new(user_name_kp1),
AKp::new(user_email_kp1),
AKp::new(product_title_kp),
AKp::new(product_sku_kp),
AKp::new(user_name_kp2).for_arc::<User>(),
AKp::new(user_email_kp2).for_box::<User>(),
];
let string_value_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.value_type_id() == TypeId::of::<String>())
.collect();
assert_eq!(string_value_kps.len(), 6);
let user_root_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<User>())
.collect();
assert_eq!(user_root_kps.len(), 2);
let arc_user_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<Arc<User>>())
.collect();
assert_eq!(arc_user_kps.len(), 1);
let box_user_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<Box<User>>())
.collect();
assert_eq!(box_user_kps.len(), 1);
let product_kps: Vec<_> = all_keypaths
.iter()
.filter(|akp| akp.root_type_id() == TypeId::of::<Product>())
.collect();
assert_eq!(product_kps.len(), 2);
let user_value = user_root_kps[0].get_as::<User, String>(&user);
assert!(user_value.is_some());
assert!(user_value.unwrap().is_some());
}
#[test]
fn test_kp_with_pin() {
use std::pin::Pin;
#[derive(Debug)]
struct SelfReferential {
value: String,
ptr_to_value: *const String, }
impl SelfReferential {
fn new(s: String) -> Self {
let mut sr = Self {
value: s,
ptr_to_value: std::ptr::null(),
};
sr.ptr_to_value = &sr.value as *const String;
sr
}
fn get_value(&self) -> &str {
&self.value
}
}
let boxed = Box::new(SelfReferential::new("pinned_data".to_string()));
let pinned: Pin<Box<SelfReferential>> = Box::into_pin(boxed);
let kp: KpType<Pin<Box<SelfReferential>>, String> = Kp::new(
|p: &Pin<Box<SelfReferential>>| {
Some(&p.as_ref().get_ref().value)
},
|p: &mut Pin<Box<SelfReferential>>| {
unsafe {
let sr = Pin::get_unchecked_mut(p.as_mut());
Some(&mut sr.value)
}
},
);
let result = kp.get(&pinned);
assert_eq!(result, Some(&"pinned_data".to_string()));
assert_eq!(pinned.get_value(), "pinned_data");
}
#[test]
fn test_kp_with_pin_arc() {
use std::pin::Pin;
use std::sync::Arc;
struct AsyncState {
status: String,
data: Vec<i32>,
}
let state = AsyncState {
status: "ready".to_string(),
data: vec![1, 2, 3, 4, 5],
};
let pinned_arc: Pin<Arc<AsyncState>> = Arc::pin(state);
let status_kp: KpType<Pin<Arc<AsyncState>>, String> = Kp::new(
|p: &Pin<Arc<AsyncState>>| Some(&p.as_ref().get_ref().status),
|_: &mut Pin<Arc<AsyncState>>| {
None::<&mut String>
},
);
let data_kp: KpType<Pin<Arc<AsyncState>>, Vec<i32>> = Kp::new(
|p: &Pin<Arc<AsyncState>>| Some(&p.as_ref().get_ref().data),
|_: &mut Pin<Arc<AsyncState>>| None::<&mut Vec<i32>>,
);
let status = status_kp.get(&pinned_arc);
assert_eq!(status, Some(&"ready".to_string()));
let data = data_kp.get(&pinned_arc);
assert_eq!(data, Some(&vec![1, 2, 3, 4, 5]));
}
#[test]
fn test_kp_with_maybe_uninit() {
use std::mem::MaybeUninit;
struct Config {
name: MaybeUninit<String>,
value: MaybeUninit<i32>,
initialized: bool,
}
impl Config {
fn new_uninit() -> Self {
Self {
name: MaybeUninit::uninit(),
value: MaybeUninit::uninit(),
initialized: false,
}
}
fn init(&mut self, name: String, value: i32) {
self.name.write(name);
self.value.write(value);
self.initialized = true;
}
fn get_name(&self) -> Option<&String> {
if self.initialized {
unsafe { Some(self.name.assume_init_ref()) }
} else {
None
}
}
fn get_value(&self) -> Option<&i32> {
if self.initialized {
unsafe { Some(self.value.assume_init_ref()) }
} else {
None
}
}
}
let name_kp: KpType<Config, String> = Kp::new(
|c: &Config| c.get_name(),
|c: &mut Config| {
if c.initialized {
unsafe { Some(c.name.assume_init_mut()) }
} else {
None
}
},
);
let value_kp: KpType<Config, i32> = Kp::new(
|c: &Config| c.get_value(),
|c: &mut Config| {
if c.initialized {
unsafe { Some(c.value.assume_init_mut()) }
} else {
None
}
},
);
let uninit_config = Config::new_uninit();
assert_eq!(name_kp.get(&uninit_config), None);
assert_eq!(value_kp.get(&uninit_config), None);
let mut init_config = Config::new_uninit();
init_config.init("test_config".to_string(), 42);
assert_eq!(name_kp.get(&init_config), Some(&"test_config".to_string()));
assert_eq!(value_kp.get(&init_config), Some(&42));
if let Some(val) = value_kp.get_mut(&mut init_config) {
*val = 100;
}
assert_eq!(value_kp.get(&init_config), Some(&100));
}
#[test]
fn test_kp_with_weak() {
use std::sync::{Arc, Weak};
#[derive(Debug, Clone)]
struct Node {
value: i32,
}
struct NodeWithParent {
value: i32,
parent: Option<Arc<Node>>, }
let parent = Arc::new(Node { value: 100 });
let child = NodeWithParent {
value: 42,
parent: Some(parent.clone()),
};
let parent_value_kp: KpType<NodeWithParent, i32> = Kp::new(
|n: &NodeWithParent| n.parent.as_ref().map(|arc| &arc.value),
|_: &mut NodeWithParent| None::<&mut i32>,
);
let parent_val = parent_value_kp.get(&child);
assert_eq!(parent_val, Some(&100));
}
#[test]
fn test_kp_with_rc_weak() {
use std::rc::Rc;
struct TreeNode {
value: String,
parent: Option<Rc<TreeNode>>, }
let root = Rc::new(TreeNode {
value: "root".to_string(),
parent: None,
});
let child1 = TreeNode {
value: "child1".to_string(),
parent: Some(root.clone()),
};
let child2 = TreeNode {
value: "child2".to_string(),
parent: Some(root.clone()),
};
let parent_name_kp: KpType<TreeNode, String> = Kp::new(
|node: &TreeNode| node.parent.as_ref().map(|rc| &rc.value),
|_: &mut TreeNode| None::<&mut String>,
);
assert_eq!(parent_name_kp.get(&child1), Some(&"root".to_string()));
assert_eq!(parent_name_kp.get(&child2), Some(&"root".to_string()));
assert_eq!(parent_name_kp.get(&root), None);
}
#[test]
fn test_kp_with_complex_weak_structure() {
use std::sync::Arc;
struct Cache {
data: String,
backup: Option<Arc<Cache>>, }
let primary = Arc::new(Cache {
data: "primary_data".to_string(),
backup: None,
});
let backup = Arc::new(Cache {
data: "backup_data".to_string(),
backup: Some(primary.clone()),
});
let backup_data_kp: KpType<Arc<Cache>, String> = Kp::new(
|cache_arc: &Arc<Cache>| cache_arc.backup.as_ref().map(|arc| &arc.data),
|_: &mut Arc<Cache>| None::<&mut String>,
);
let data = backup_data_kp.get(&backup);
assert_eq!(data, Some(&"primary_data".to_string()));
let no_backup = backup_data_kp.get(&primary);
assert_eq!(no_backup, None);
}
#[test]
fn test_kp_chain_with_pin_and_arc() {
use std::pin::Pin;
use std::sync::Arc;
struct Outer {
inner: Arc<Inner>,
}
struct Inner {
value: String,
}
let outer = Outer {
inner: Arc::new(Inner {
value: "nested_value".to_string(),
}),
};
let pinned_outer = Box::pin(outer);
let to_inner: KpType<Pin<Box<Outer>>, Arc<Inner>> = Kp::new(
|p: &Pin<Box<Outer>>| Some(&p.as_ref().get_ref().inner),
|_: &mut Pin<Box<Outer>>| None::<&mut Arc<Inner>>,
);
let to_value: KpType<Arc<Inner>, String> = Kp::new(
|a: &Arc<Inner>| Some(&a.value),
|_: &mut Arc<Inner>| None::<&mut String>,
);
let chained = to_inner.then(to_value);
let result = chained.get(&pinned_outer);
assert_eq!(result, Some(&"nested_value".to_string()));
}
#[test]
fn test_kp_with_maybe_uninit_array() {
use std::mem::MaybeUninit;
struct Buffer {
data: [MaybeUninit<u8>; 10],
len: usize,
}
impl Buffer {
fn new() -> Self {
Self {
data: unsafe { MaybeUninit::uninit().assume_init() },
len: 0,
}
}
fn push(&mut self, byte: u8) -> Result<(), &'static str> {
if self.len >= self.data.len() {
return Err("Buffer full");
}
self.data[self.len].write(byte);
self.len += 1;
Ok(())
}
fn get(&self, idx: usize) -> Option<&u8> {
if idx < self.len {
unsafe { Some(self.data[idx].assume_init_ref()) }
} else {
None
}
}
fn get_mut(&mut self, idx: usize) -> Option<&mut u8> {
if idx < self.len {
unsafe { Some(self.data[idx].assume_init_mut()) }
} else {
None
}
}
}
let len_kp: KpType<Buffer, usize> =
Kp::new(|b: &Buffer| Some(&b.len), |b: &mut Buffer| Some(&mut b.len));
let mut buffer = Buffer::new();
assert_eq!(len_kp.get(&buffer), Some(&0));
buffer.push(1).unwrap();
buffer.push(2).unwrap();
buffer.push(3).unwrap();
assert_eq!(len_kp.get(&buffer), Some(&3));
assert_eq!(buffer.get(0), Some(&1));
assert_eq!(buffer.get(1), Some(&2));
assert_eq!(buffer.get(2), Some(&3));
assert_eq!(buffer.get(10), None);
if let Some(elem) = buffer.get_mut(1) {
*elem = 20;
}
assert_eq!(buffer.get(1), Some(&20));
}
#[test]
fn test_kp_then_lock_deep_structs() {
use std::sync::{Arc, Mutex};
#[derive(Clone)]
struct Root {
guard: Arc<Mutex<Level1>>,
}
#[derive(Clone)]
struct Level1 {
name: String,
nested: Level2,
}
#[derive(Clone)]
struct Level2 {
count: i32,
}
let root = Root {
guard: Arc::new(Mutex::new(Level1 {
name: "deep".to_string(),
nested: Level2 { count: 42 },
})),
};
let kp_to_guard: KpType<Root, Arc<Mutex<Level1>>> =
Kp::new(|r: &Root| Some(&r.guard), |r: &mut Root| Some(&mut r.guard));
let lock_kp = {
let prev: KpType<Arc<Mutex<Level1>>, Arc<Mutex<Level1>>> = Kp::new(
|g: &Arc<Mutex<Level1>>| Some(g),
|g: &mut Arc<Mutex<Level1>>| Some(g),
);
let next: KpType<Level1, Level1> =
Kp::new(|l: &Level1| Some(l), |l: &mut Level1| Some(l));
crate::lock::LockKp::new(prev, crate::lock::ArcMutexAccess::new(), next)
};
let chained = kp_to_guard.then_lock(lock_kp);
let level1 = chained.get(&root);
assert!(level1.is_some());
assert_eq!(level1.unwrap().name, "deep");
assert_eq!(level1.unwrap().nested.count, 42);
let mut_root = &mut root.clone();
let mut_level1 = chained.get_mut(mut_root);
assert!(mut_level1.is_some());
mut_level1.unwrap().nested.count = 99;
assert_eq!(chained.get(&root).unwrap().nested.count, 99);
}
#[test]
fn test_kp_then_lock_with_enum() {
use std::sync::{Arc, Mutex};
#[derive(Clone)]
enum Message {
Request(LevelA),
Response(i32),
}
#[derive(Clone)]
struct LevelA {
data: Arc<Mutex<i32>>,
}
struct RootWithEnum {
msg: Arc<Mutex<Message>>,
}
let root = RootWithEnum {
msg: Arc::new(Mutex::new(Message::Request(LevelA {
data: Arc::new(Mutex::new(100)),
}))),
};
let kp_msg: KpType<RootWithEnum, Arc<Mutex<Message>>> = Kp::new(
|r: &RootWithEnum| Some(&r.msg),
|r: &mut RootWithEnum| Some(&mut r.msg),
);
let lock_kp_msg = {
let prev: KpType<Arc<Mutex<Message>>, Arc<Mutex<Message>>> = Kp::new(
|m: &Arc<Mutex<Message>>| Some(m),
|m: &mut Arc<Mutex<Message>>| Some(m),
);
let next: KpType<Message, Message> =
Kp::new(|m: &Message| Some(m), |m: &mut Message| Some(m));
crate::lock::LockKp::new(prev, crate::lock::ArcMutexAccess::new(), next)
};
let chained = kp_msg.then_lock(lock_kp_msg);
let msg = chained.get(&root);
assert!(msg.is_some());
match msg.unwrap() {
Message::Request(a) => assert_eq!(*a.data.lock().unwrap(), 100),
Message::Response(_) => panic!("expected Request"),
}
}
#[cfg(all(feature = "tokio", feature = "parking_lot"))]
#[tokio::test]
async fn test_kp_then_async_deep_chain() {
use crate::async_lock::{AsyncLockKp, TokioMutexAccess};
use std::sync::Arc;
#[derive(Clone)]
struct Root {
tokio_guard: Arc<tokio::sync::Mutex<Level1>>,
}
#[derive(Clone)]
struct Level1 {
value: i32,
}
let root = Root {
tokio_guard: Arc::new(tokio::sync::Mutex::new(Level1 { value: 7 })),
};
let kp_to_guard: KpType<Root, Arc<tokio::sync::Mutex<Level1>>> = Kp::new(
|r: &Root| Some(&r.tokio_guard),
|r: &mut Root| Some(&mut r.tokio_guard),
);
let async_kp = {
let prev: KpType<Arc<tokio::sync::Mutex<Level1>>, Arc<tokio::sync::Mutex<Level1>>> =
Kp::new(
|g: &Arc<tokio::sync::Mutex<Level1>>| Some(g),
|g: &mut Arc<tokio::sync::Mutex<Level1>>| Some(g),
);
let next: KpType<Level1, Level1> =
Kp::new(|l: &Level1| Some(l), |l: &mut Level1| Some(l));
AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
};
let chained = kp_to_guard.then_async(async_kp);
let level1 = chained.get(&root).await;
assert!(level1.is_some());
assert_eq!(level1.unwrap().value, 7);
}
#[cfg(all(feature = "tokio", feature = "parking_lot"))]
#[tokio::test]
async fn test_deep_nested_chain_kp_lock_async_lock_kp() {
use crate::async_lock::{AsyncLockKp, TokioMutexAccess};
use crate::lock::{ArcMutexAccess, LockKp};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
struct Root {
sync_mutex: Arc<Mutex<Level1>>,
}
#[derive(Clone)]
struct Level1 {
inner: Level2,
}
#[derive(Clone)]
struct Level2 {
tokio_mutex: Arc<tokio::sync::Mutex<Level3>>,
}
#[derive(Clone)]
struct Level3 {
leaf: i32,
}
let mut root = Root {
sync_mutex: Arc::new(Mutex::new(Level1 {
inner: Level2 {
tokio_mutex: Arc::new(tokio::sync::Mutex::new(Level3 { leaf: 42 })),
},
})),
};
let identity_l1: KpType<Level1, Level1> =
Kp::new(|l: &Level1| Some(l), |l: &mut Level1| Some(l));
let kp_sync: KpType<Root, Arc<Mutex<Level1>>> = Kp::new(
|r: &Root| Some(&r.sync_mutex),
|r: &mut Root| Some(&mut r.sync_mutex),
);
let lock_root_to_l1 = LockKp::new(kp_sync, ArcMutexAccess::new(), identity_l1);
let kp_l1_inner: KpType<Level1, Level2> = Kp::new(
|l: &Level1| Some(&l.inner),
|l: &mut Level1| Some(&mut l.inner),
);
let kp_l2_tokio: KpType<Level2, Arc<tokio::sync::Mutex<Level3>>> = Kp::new(
|l: &Level2| Some(&l.tokio_mutex),
|l: &mut Level2| Some(&mut l.tokio_mutex),
);
let async_l3 = {
let prev: KpType<Arc<tokio::sync::Mutex<Level3>>, Arc<tokio::sync::Mutex<Level3>>> =
Kp::new(|t: &_| Some(t), |t: &mut _| Some(t));
let next: KpType<Level3, Level3> =
Kp::new(|l: &Level3| Some(l), |l: &mut Level3| Some(l));
AsyncLockKp::new(prev, TokioMutexAccess::new(), next)
};
let kp_l3_leaf: KpType<Level3, i32> = Kp::new(
|l: &Level3| Some(&l.leaf),
|l: &mut Level3| Some(&mut l.leaf),
);
let step1 = lock_root_to_l1.then(kp_l1_inner);
let step2 = step1.then(kp_l2_tokio);
let step3 = step2.then_async(async_l3);
let deep_chain = step3.then(kp_l3_leaf);
let leaf = deep_chain.get(&root).await;
deep_chain.get_mut(&mut root).await.map(|l| *l = 100);
assert_eq!(leaf, Some(&100));
let mut root_mut = root.clone();
let leaf_mut = deep_chain.get_mut(&mut root_mut).await;
assert!(leaf_mut.is_some());
*leaf_mut.unwrap() = 99;
let leaf_after = deep_chain.get(&root_mut).await;
assert_eq!(leaf_after, Some(&99));
}
}