Skip to content

Commit ebe6ffc

Browse files
authored
Feat: Add try_maps on AccountInfo Ref/RefMut (#229)
* Add try_maps on AccountInfo Ref/RefMut * update tests and api for try map ref
1 parent 243238a commit ebe6ffc

File tree

1 file changed

+61
-12
lines changed

1 file changed

+61
-12
lines changed

sdk/pinocchio/src/account_info.rs

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,6 @@ impl<'a, T: ?Sized> Ref<'a, T> {
670670
{
671671
// Avoid decrementing the borrow flag on Drop.
672672
let orig = ManuallyDrop::new(orig);
673-
674673
Ref {
675674
value: NonNull::from(f(&*orig)),
676675
state: orig.state,
@@ -679,6 +678,27 @@ impl<'a, T: ?Sized> Ref<'a, T> {
679678
}
680679
}
681680

681+
/// Tries to makes a new `Ref` for a component of the borrowed data.
682+
/// On failure, the original guard is returned alongside with the error
683+
/// returned by the closure.
684+
#[inline]
685+
pub fn try_map<U: ?Sized, E>(
686+
orig: Ref<'a, T>,
687+
f: impl FnOnce(&T) -> Result<&U, E>,
688+
) -> Result<Ref<'a, U>, (Self, E)> {
689+
// Avoid decrementing the borrow flag on Drop.
690+
let orig = ManuallyDrop::new(orig);
691+
match f(&*orig) {
692+
Ok(value) => Ok(Ref {
693+
value: NonNull::from(value),
694+
state: orig.state,
695+
borrow_shift: orig.borrow_shift,
696+
marker: PhantomData,
697+
}),
698+
Err(e) => Err((ManuallyDrop::into_inner(orig), e)),
699+
}
700+
}
701+
682702
/// Filters and maps a reference to a new type.
683703
#[inline]
684704
pub fn filter_map<U: ?Sized, F>(orig: Ref<'a, T>, f: F) -> Result<Ref<'a, U>, Self>
@@ -742,7 +762,6 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
742762
{
743763
// Avoid decrementing the borrow flag on Drop.
744764
let mut orig = ManuallyDrop::new(orig);
745-
746765
RefMut {
747766
value: NonNull::from(f(&mut *orig)),
748767
state: orig.state,
@@ -751,6 +770,27 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
751770
}
752771
}
753772

773+
/// Tries to makes a new `RefMut` for a component of the borrowed data.
774+
/// On failure, the original guard is returned alongside with the error
775+
/// returned by the closure.
776+
#[inline]
777+
pub fn try_map<U: ?Sized, E>(
778+
orig: RefMut<'a, T>,
779+
f: impl FnOnce(&mut T) -> Result<&mut U, E>,
780+
) -> Result<RefMut<'a, U>, (Self, E)> {
781+
// Avoid decrementing the borrow flag on Drop.
782+
let mut orig = ManuallyDrop::new(orig);
783+
match f(&mut *orig) {
784+
Ok(value) => Ok(RefMut {
785+
value: NonNull::from(value),
786+
state: orig.state,
787+
borrow_bitmask: orig.borrow_bitmask,
788+
marker: PhantomData,
789+
}),
790+
Err(e) => Err((ManuallyDrop::into_inner(orig), e)),
791+
}
792+
}
793+
754794
/// Filters and maps a mutable reference to a new type.
755795
#[inline]
756796
pub fn filter_map<U: ?Sized, F>(orig: RefMut<'a, T>, f: F) -> Result<RefMut<'a, U>, Self>
@@ -759,17 +799,13 @@ impl<'a, T: ?Sized> RefMut<'a, T> {
759799
{
760800
// Avoid decrementing the mutable borrow flag on Drop.
761801
let mut orig = ManuallyDrop::new(orig);
762-
763802
match f(&mut *orig) {
764-
Some(value) => {
765-
let value = NonNull::from(value);
766-
Ok(RefMut {
767-
value,
768-
state: orig.state,
769-
borrow_bitmask: orig.borrow_bitmask,
770-
marker: PhantomData,
771-
})
772-
}
803+
Some(value) => Ok(RefMut {
804+
value: NonNull::from(value),
805+
state: orig.state,
806+
borrow_bitmask: orig.borrow_bitmask,
807+
marker: PhantomData,
808+
}),
773809
None => Err(ManuallyDrop::into_inner(orig)),
774810
}
775811
}
@@ -827,6 +863,19 @@ mod tests {
827863
assert_eq!(state, NOT_BORROWED - (1 << DATA_BORROW_SHIFT));
828864
assert_eq!(*new_ref, 3);
829865

866+
let Ok(new_ref) = Ref::try_map::<_, u8>(new_ref, |_| Ok(&4)) else {
867+
unreachable!()
868+
};
869+
870+
assert_eq!(state, NOT_BORROWED - (1 << DATA_BORROW_SHIFT));
871+
assert_eq!(*new_ref, 4);
872+
873+
let (new_ref, err) = Ref::try_map::<u8, u8>(new_ref, |_| Err(5)).unwrap_err();
874+
assert_eq!(state, NOT_BORROWED - (1 << DATA_BORROW_SHIFT));
875+
assert_eq!(err, 5);
876+
// Unchanged
877+
assert_eq!(*new_ref, 4);
878+
830879
let new_ref = Ref::filter_map(new_ref, |_| Option::<&u8>::None);
831880

832881
assert_eq!(state, NOT_BORROWED - (1 << DATA_BORROW_SHIFT));

0 commit comments

Comments
 (0)