diff --git a/CHANGELOG.md b/CHANGELOG.md index d5dd2a2..a3e5913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.3.0 +- Change the API of `try_*` functions on `Parc` and `Prc` to take functions returning `Result` instead of `Option` and make them return `Result` instead of `Option`. + ## 0.2.3 - Factor out the vtable to be shared between the `sync` and `prc` modules, as the type definition is identical - Fix tests that should fail and check that we're failing for the right reason on nightly diff --git a/Cargo.lock b/Cargo.lock index 5019085..137370d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,7 +10,7 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "pared" -version = "0.2.3" +version = "0.3.0" dependencies = [ "doc-comment", ] diff --git a/Cargo.toml b/Cargo.toml index 74b9fb1..a7f1195 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pared" -version = "0.2.3" +version = "0.3.0" authors = ["Radek Vít "] edition = "2021" rust-version = "1.56" diff --git a/src/prc.rs b/src/prc.rs index d05f94c..9846efb 100644 --- a/src/prc.rs +++ b/src/prc.rs @@ -195,24 +195,24 @@ impl Prc { /// /// let rc = Rc::new(Enum::Int(5)); /// let prc = Prc::try_from_rc(&rc, |x| match x { - /// Enum::Str(s) => None, - /// Enum::Int(i) => Some(i), + /// Enum::Str(s) => Err(()), + /// Enum::Int(i) => Ok(i), /// }); /// - /// assert!(matches!(prc, Some(prc) if *prc == 5 )); + /// assert!(matches!(prc, Ok(prc) if *prc == 5 )); /// ``` #[inline] - pub fn try_from_rc(rc: &Rc, project: F) -> Option + pub fn try_from_rc(rc: &Rc, project: F) -> Result where U: ?Sized, T: 'static, - F: FnOnce(&U) -> Option<&T>, + F: FnOnce(&U) -> Result<&T, E>, { let projected = project(rc)?; // SAFETY: fn shouldn't be able to capture any local references // which should mean that the projection done by f is safe let projected = unsafe { NonNull::new_unchecked(projected as *const T as *mut T) }; - Some(Self { + Ok(Self { rc: TypeErasedRc::new(rc.clone()), projected, }) @@ -271,23 +271,23 @@ impl Prc { /// /// let prc = Prc::new(Enum::Int(5)); /// let projected = prc.try_project(|x| match x { - /// Enum::Str(s) => None, - /// Enum::Int(i) => Some(i), + /// Enum::Str(s) => Err(()), + /// Enum::Int(i) => Ok(i), /// }); /// - /// assert!(matches!(projected, Some(p) if *p == 5 )); + /// assert!(matches!(projected, Ok(p) if *p == 5 )); /// ``` #[inline] - pub fn try_project(&self, project: F) -> Option> + pub fn try_project(&self, project: F) -> Result, E> where U: ?Sized + 'static, - F: FnOnce(&T) -> Option<&U>, + F: FnOnce(&T) -> Result<&U, E>, { let projected = project(self)?; // SAFETY: fn shouldn't be able to capture any local references // which should mean that the projection done by f is safe let projected = unsafe { NonNull::new_unchecked(projected as *const U as *mut U) }; - Some(Prc:: { + Ok(Prc:: { rc: self.rc.clone(), projected, }) diff --git a/src/sync.rs b/src/sync.rs index 0add8be..db041a2 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -223,9 +223,10 @@ impl Parc { } } - /// Constructs a new `Option>` from an existing `Arc` by trying to project a field. + /// Constructs a new `Result, E>` from an existing `Arc` + /// by trying to project a field. /// - /// If the function passed into this returns `None`, this method will also return `None`. + /// If the function passed into this returns `Err(x)`, this method will also return `Err(x)`. /// /// # Panics /// If `f` panics, the panic is propagated to the caller and the rc won't be cloned. @@ -242,24 +243,24 @@ impl Parc { /// /// let arc = Arc::new(Enum::Int(5)); /// let parc = Parc::try_from_arc(&arc, |x| match x { - /// Enum::Str(s) => None, - /// Enum::Int(i) => Some(i), + /// Enum::Str(s) => Err(()), + /// Enum::Int(i) => Ok(i), /// }); /// - /// assert!(matches!(parc, Some(parc) if *parc == 5 )); + /// assert!(matches!(parc, Ok(parc) if *parc == 5 )); /// ``` #[inline] - pub fn try_from_arc(arc: &Arc, project: F) -> Option + pub fn try_from_arc(arc: &Arc, project: F) -> Result where U: ?Sized + Sync + Send, T: 'static, - F: FnOnce(&U) -> Option<&T>, + F: FnOnce(&U) -> Result<&T, E>, { let projected = project(arc)?; // SAFETY: fn shouldn't be able to capture any local references // which should mean that the projection done by f is safe let projected = unsafe { NonNull::new_unchecked(projected as *const T as *mut T) }; - Some(Self { + Ok(Self { arc: TypeErasedArc::new(arc.clone()), projected, }) @@ -303,10 +304,10 @@ impl Parc { } } - /// Constructs a new `Option>` from an existing `Parc` + /// Constructs a new `Result, E>` from an existing `Parc` /// by trying to projecting a field. /// - /// If the function passed into this returns `None`, this method will also return `None`. + /// If the function passed into this returns `Err(x)`, this method will also return `Err(x)`. /// /// # Panics /// If `f` panics, the panic is propagated to the caller and the underlying rc won't be cloned. @@ -322,23 +323,23 @@ impl Parc { /// /// let prc = Parc::new(Enum::Int(5)); /// let projected = prc.try_project(|x| match x { - /// Enum::Str(s) => None, - /// Enum::Int(i) => Some(i), + /// Enum::Str(s) => Err(()), + /// Enum::Int(i) => Ok(i), /// }); /// - /// assert!(matches!(projected, Some(p) if *p == 5 )); + /// assert!(matches!(projected, Ok(p) if *p == 5 )); /// ``` - pub fn try_project(&self, project: F) -> Option> + pub fn try_project(&self, project: F) -> Result, E> where T: Send + Sync, U: ?Sized + 'static, - F: for<'x> FnOnce(&'x T) -> Option<&'x U>, + F: for<'x> FnOnce(&'x T) -> Result<&'x U, E>, { let projected = project(self)?; // SAFETY: fn shouldn't be able to capture any local references // which should mean that the projection done by f is safe let projected = unsafe { NonNull::new_unchecked(projected as *const U as *mut U) }; - Some(Parc:: { + Ok(Parc:: { arc: self.arc.clone(), projected, }) diff --git a/tests/parc.rs b/tests/parc.rs index 061e04d..49d632f 100644 --- a/tests/parc.rs +++ b/tests/parc.rs @@ -130,28 +130,28 @@ fn fallible_projections() { B, } - fn try_project(t: &Test) -> Option<&str> { + fn try_project(t: &Test) -> Result<&str, ()> { match t { - Test::A(s) => Some(s), - Test::B => None, + Test::A(s) => Ok(s), + Test::B => Err(()), } } let arc = Arc::new(Test::B); let parc = Parc::try_from_arc(&arc, try_project); - assert!(parc.is_none()); + assert!(parc.is_err()); let parc = Parc::new(Test::B); let parc = parc.try_project(try_project); - assert!(parc.is_none()); + assert!(parc.is_err()); let arc = Arc::new(Test::A("Hi!".to_owned())); let parc = Parc::try_from_arc(&arc, try_project); - assert!(matches!(parc, Some(p) if &*p == "Hi!")); + assert!(matches!(parc, Ok(p) if &*p == "Hi!")); let parc = Parc::new(Test::A("Hi!".to_owned())); let parc = parc.try_project(try_project); - assert!(matches!(parc, Some(p) if &*p == "Hi!")); + assert!(matches!(parc, Ok(p) if &*p == "Hi!")); } #[test] diff --git a/tests/prc.rs b/tests/prc.rs index e04d169..e79d556 100644 --- a/tests/prc.rs +++ b/tests/prc.rs @@ -131,28 +131,28 @@ fn fallible_projections() { B, } - fn try_project(t: &Test) -> Option<&str> { + fn try_project(t: &Test) -> Result<&str, ()> { match t { - Test::A(s) => Some(s), - Test::B => None, + Test::A(s) => Ok(s), + Test::B => Err(()), } } let rc = Rc::new(Test::B); let prc = Prc::try_from_rc(&rc, try_project); - assert!(prc.is_none()); + assert!(prc.is_err()); let prc = Prc::new(Test::B); let prc = prc.try_project(try_project); - assert!(prc.is_none()); + assert!(prc.is_err()); let rc = Rc::new(Test::A("Hi!".to_owned())); let prc = Prc::try_from_rc(&rc, try_project); - assert!(matches!(prc, Some(p) if &*p == "Hi!")); + assert!(matches!(prc, Ok(p) if &*p == "Hi!")); let prc = Prc::new(Test::A("Hi!".to_owned())); let prc = prc.try_project(try_project); - assert!(matches!(prc, Some(p) if &*p == "Hi!")); + assert!(matches!(prc, Ok(p) if &*p == "Hi!")); } #[test]