From 7863c3bcf8c7ca37bfc5652ec92e620968e635e4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 28 Dec 2022 16:57:35 +0100 Subject: Transform codebase to use thiserror Signed-off-by: Matthias Beyer --- src/async_dag.rs | 74 +++++++++++++++++++++++++++++++----------------------- src/dag_backend.rs | 7 +++--- src/error.rs | 11 ++++++++ src/lib.rs | 3 +++ src/node_id.rs | 2 +- src/test_impl.rs | 19 +++++++++++--- 6 files changed, 78 insertions(+), 38 deletions(-) create mode 100644 src/error.rs (limited to 'src') diff --git a/src/async_dag.rs b/src/async_dag.rs index 8b4c595..7abc6c5 100644 --- a/src/async_dag.rs +++ b/src/async_dag.rs @@ -6,8 +6,6 @@ use std::pin::Pin; -use anyhow::anyhow; -use anyhow::Result; use futures::stream::StreamExt; use futures::task::Poll; @@ -27,16 +25,17 @@ where _node: std::marker::PhantomData, } -impl AsyncDag +impl AsyncDag where Id: NodeId + Send, N: Node, - Backend: DagBackend, + Backend: DagBackend, + Error: From>, { /// Create a new DAG with a backend and a HEAD node /// /// The head node is `DagBackend::put` into the backend before the AsyncDag object is created. - pub async fn new(mut backend: Backend, head: N) -> Result { + pub async fn new(mut backend: Backend, head: N) -> Result { backend.put(head).await.map(|id| AsyncDag { head: id, backend, @@ -49,16 +48,16 @@ where /// # Warning /// /// This fails if backend.get(head) fails. - pub async fn load(backend: Backend, head: Id) -> Result { + pub async fn load(backend: Backend, head: Id) -> Result { backend - .get(head) + .get(head.clone()) .await? .map(|(id, _)| AsyncDag { head: id, backend, _node: std::marker::PhantomData, }) - .ok_or_else(|| anyhow!("Node not found")) + .ok_or_else(|| crate::Error::NodeNotFound(head).into()) } pub fn head(&self) -> &Id { @@ -74,10 +73,10 @@ where } /// Check whether an `id` is in the DAG. - pub async fn has_id(&self, id: &Id) -> Result { + pub async fn has_id(&self, id: &Id) -> Result { self.stream() - .map(|r| -> Result { r.map(|(ref node_id, _)| node_id == id) }) - .collect::>>() + .map(|r| -> Result { r.map(|(ref node_id, _)| node_id == id) }) + .collect::>>() .await .into_iter() .fold(Ok(false), |acc, e| match (acc, e) { @@ -94,7 +93,7 @@ where /// # Warning /// /// The order of the nodes is not (yet) guaranteed. - pub fn stream(&self) -> Stream { + pub fn stream(&self) -> Stream { Stream { dag: self, backlog: { @@ -110,11 +109,11 @@ where /// # Warning /// /// fails if the passed node does not point to the current HEAD in its parents. - pub async fn update_head(&mut self, node: N) -> Result { + pub async fn update_head(&mut self, node: N) -> Result { if node.parent_ids().iter().any(|id| id == &self.head) { self.update_head_unchecked(node).await } else { - Err(anyhow!("Node does not have HEAD as parent")) + Err(Error::from(crate::Error::HeadNotAParent)) } } @@ -124,7 +123,7 @@ where /// /// Does not check whether the passed `node` does point to the current (then old) HEAD in its /// parents. Be careful to not lose nodes from the DAG with this. - pub async fn update_head_unchecked(&mut self, node: N) -> Result { + pub async fn update_head_unchecked(&mut self, node: N) -> Result { let id = self.backend.put(node).await?; self.head = id.clone(); Ok(id) @@ -149,9 +148,13 @@ where /// /// Use the `merger` function to merge the two head IDs and generate a new Node instance for /// the new HEAD of `self`. - pub async fn merge(&mut self, other: &AsyncDag, merger: M) -> Result + pub async fn merge( + &mut self, + other: &AsyncDag, + merger: M, + ) -> Result where - M: Merger, + M: Merger, { let node = merger.create_merge_node(&self.head, &other.head)?; let id = self.backend.put(node).await?; @@ -165,41 +168,49 @@ where Id: NodeId, N: Node, { - fn create_merge_node(&self, left_id: &Id, right_id: &Id) -> Result; + type Error; + + fn create_merge_node(&self, left_id: &Id, right_id: &Id) -> Result; } -impl Merger for F +impl Merger for F where Id: NodeId, N: Node, - F: Fn(&Id, &Id) -> Result, + F: Fn(&Id, &Id) -> Result, + Error: From>, { - fn create_merge_node(&self, left_id: &Id, right_id: &Id) -> Result { + type Error = Error; + + fn create_merge_node(&self, left_id: &Id, right_id: &Id) -> Result { (self)(left_id, right_id) } } /// Stream adapter for streaming all nodes in a DAG -pub struct Stream<'a, Id, N, Backend> +pub struct Stream<'a, Id, N, Backend, Error> where Id: NodeId + Send, N: Node, Backend: DagBackend, + Error: From>, { dag: &'a AsyncDag, - backlog: Vec>>, + backlog: Vec>>, } -pub type Backlog<'a, Id, N> = - Box<(dyn futures::future::Future>> + std::marker::Send + 'a)>; +pub type Backlog<'a, Id, N, Error> = Box< + (dyn futures::future::Future, Error>> + std::marker::Send + 'a), +>; -impl<'a, Id, N, Backend> futures::stream::Stream for Stream<'a, Id, N, Backend> +impl<'a, Id, N, Backend, Error> futures::stream::Stream for Stream<'a, Id, N, Backend, Error> where Id: NodeId + Send, N: Node, - Backend: DagBackend, + Backend: DagBackend, + Error: From>, { - type Item = Result<(Id, N)>; + type Item = Result<(Id, N), Error>; fn poll_next( mut self: std::pin::Pin<&mut Self>, @@ -235,11 +246,10 @@ where #[cfg(test)] mod tests { - - use anyhow::Result; use futures::StreamExt; use crate::test_impl as test; + use crate::test_impl::TestError; use crate::AsyncDag; use crate::DagBackend; @@ -445,11 +455,13 @@ mod tests { struct M; impl super::Merger for M { + type Error = TestError; + fn create_merge_node( &self, left_id: &test::Id, right_id: &test::Id, - ) -> Result { + ) -> Result { Ok(test::Node { parents: vec![*left_id, *right_id], data: 3, diff --git a/src/dag_backend.rs b/src/dag_backend.rs index 2be9736..09dc428 100644 --- a/src/dag_backend.rs +++ b/src/dag_backend.rs @@ -4,7 +4,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. // -use anyhow::Result; use async_trait::async_trait; use crate::Node; @@ -20,6 +19,8 @@ where N: Node, Id: NodeId + Send, { + type Error; + /// Get a `Node` from the backend that is identified by `id` /// /// # Returns @@ -27,12 +28,12 @@ where /// * Should return Err(_) if the operation failed. /// * Should return Ok(None) if there is no node that is identified by `id` /// * Otherwise return the Id along with the node identified by it - async fn get(&self, id: Id) -> Result>; + async fn get(&self, id: Id) -> Result, Self::Error>; /// Store a `node` in the backend, returning its `Id` /// /// This function should store the `node` in the backend and return the `id` the node has. - async fn put(&mut self, node: N) -> Result; + async fn put(&mut self, node: N) -> Result; } #[cfg(test)] diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..fd91045 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,11 @@ +#[derive(Debug, thiserror::Error)] +pub enum Error +where + Id: crate::NodeId, +{ + #[error("Node not found: {:?}", .0)] + NodeNotFound(Id), + + #[error("Node does not have HEAD as parent")] + HeadNotAParent, +} diff --git a/src/lib.rs b/src/lib.rs index bcb6ae0..67bce67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,5 +16,8 @@ pub use node::*; mod node_id; pub use node_id::*; +mod error; +pub use error::*; + #[cfg(test)] mod test_impl; diff --git a/src/node_id.rs b/src/node_id.rs index df1e4d4..5d0663a 100644 --- a/src/node_id.rs +++ b/src/node_id.rs @@ -7,4 +7,4 @@ /// A unique identifier for a `Node` /// /// The `NodeId` should be cheap to clone (for example a UUID or some form of a hash value). -pub trait NodeId: Clone + Eq + PartialEq {} +pub trait NodeId: Clone + Eq + PartialEq + std::fmt::Debug {} diff --git a/src/test_impl.rs b/src/test_impl.rs index a95c4c6..c8f2b51 100644 --- a/src/test_impl.rs +++ b/src/test_impl.rs @@ -7,9 +7,20 @@ use std::sync::Arc; use std::sync::RwLock; -use anyhow::Result; use async_trait::async_trait; +#[derive(Debug)] +pub struct TestError; + +impl From> for TestError +where + Id: crate::NodeId, +{ + fn from(_ce: crate::Error) -> Self { + TestError + } +} + #[derive(Copy, Clone, Eq, PartialEq, std::hash::Hash, Debug)] pub struct Id(pub(crate) usize); @@ -46,7 +57,9 @@ impl Backend { #[async_trait] impl crate::DagBackend for Backend { - async fn get(&self, id: Id) -> Result> { + type Error = TestError; + + async fn get(&self, id: Id) -> Result, Self::Error> { if self.0.read().unwrap().len() < id.0 + 1 { Ok(None) } else { @@ -54,7 +67,7 @@ impl crate::DagBackend for Backend { } } - async fn put(&mut self, node: Node) -> Result { + async fn put(&mut self, node: Node) -> Result { while self.0.read().unwrap().len() < node.data + 1 { self.0.write().unwrap().push(None) } -- cgit v1.2.3