Skip to content

Commit

Permalink
feat!: add update method to ItemAccess
Browse files Browse the repository at this point in the history
  • Loading branch information
uint committed Nov 13, 2024
1 parent b47c699 commit 3ea04ae
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 17 deletions.
21 changes: 15 additions & 6 deletions packages/mocks/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,18 @@ use storey_encoding::{Cover, DecodableWithImpl, EncodableWithImpl, Encoding};

pub struct TestEncoding;

#[derive(Debug, PartialEq)]
pub struct MockError;

impl std::fmt::Display for MockError {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}

impl Encoding for TestEncoding {
type DecodeError = ();
type EncodeError = ();
type DecodeError = MockError;
type EncodeError = MockError;
}

// This is how we would implement `EncodableWith` and `DecodableWith` for
Expand Down Expand Up @@ -39,16 +48,16 @@ where
// Imagine `MyTestEncoding` is a third-party trait that we don't control.

trait MyTestEncoding: Sized {
fn my_encode(&self) -> Result<Vec<u8>, ()>;
fn my_decode(data: &[u8]) -> Result<Self, ()>;
fn my_encode(&self) -> Result<Vec<u8>, MockError>;
fn my_decode(data: &[u8]) -> Result<Self, MockError>;
}

impl MyTestEncoding for u64 {
fn my_encode(&self) -> Result<Vec<u8>, ()> {
fn my_encode(&self) -> Result<Vec<u8>, MockError> {
Ok(self.to_le_bytes().to_vec())
}

fn my_decode(data: &[u8]) -> Result<Self, ()> {
fn my_decode(data: &[u8]) -> Result<Self, MockError> {
let mut bytes = [0u8; 8];
bytes.copy_from_slice(data);
Ok(u64::from_le_bytes(bytes))
Expand Down
4 changes: 2 additions & 2 deletions packages/storey-encoding/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pub trait Encoding {
/// The error type returned when encoding fails.
type EncodeError;
type EncodeError: std::fmt::Display;

/// The error type returned when decoding fails.
type DecodeError;
type DecodeError: std::fmt::Display;
}

pub trait EncodableWith<E: Encoding>: sealed::SealedE<E> {
Expand Down
23 changes: 22 additions & 1 deletion packages/storey/src/containers/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ impl<E, T, S> ItemAccess<E, T, S>
where
E: Encoding,
T: EncodableWith<E> + DecodableWith<E>,
S: StorageMut,
S: Storage + StorageMut,
{
/// Set the value of the item.
///
Expand All @@ -234,6 +234,14 @@ where
Ok(())
}

pub fn update<F>(&mut self, f: F) -> Result<(), UpdateError<E>>
where
F: FnOnce(Option<T>) -> T,
{
let new_value = f(self.get().map_err(UpdateError::Decode)?);
self.set(&new_value).map_err(UpdateError::Encode)
}

/// Remove the value of the item.
///
/// # Example
Expand All @@ -254,6 +262,19 @@ where
}
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, thiserror::Error)]
pub enum UpdateError<E>
where
E: Encoding,
E::DecodeError: std::fmt::Display,
E::EncodeError: std::fmt::Display,
{
#[error("decode error: {0}")]
Decode(E::DecodeError),
#[error("encode error: {0}")]
Encode(E::EncodeError),
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
17 changes: 9 additions & 8 deletions packages/storey/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@
//! struct DisplayEncoding;
//!
//! impl Encoding for DisplayEncoding {
//! type DecodeError = ();
//! type EncodeError = ();
//! type DecodeError = String;
//! type EncodeError = String;
//! }
//!
//! impl<T> EncodableWithImpl<DisplayEncoding> for Cover<&T,>
//! where
//! T: std::fmt::Display,
//! {
//! fn encode_impl(self) -> Result<Vec<u8>, ()> {
//! fn encode_impl(self) -> Result<Vec<u8>, String> {
//! Ok(format!("{}", self.0).into_bytes())
//! }
//! }
Expand All @@ -67,17 +67,18 @@
//! struct DisplayEncoding;
//!
//! impl Encoding for DisplayEncoding {
//! type DecodeError = ();
//! type EncodeError = ();
//! type DecodeError = String;
//! type EncodeError = String;
//! }
//!
//! impl<T> DecodableWithImpl<DisplayEncoding> for Cover<T>
//! where
//! T: std::str::FromStr,
//! {
//! fn decode_impl(data: &[u8]) -> Result<Self, ()> {
//! let string = String::from_utf8(data.to_vec()).map_err(|_| ())?;
//! let value = string.parse().map_err(|_| ())?;
//! fn decode_impl(data: &[u8]) -> Result<Self, String> {
//! let string =
//! String::from_utf8(data.to_vec()).map_err(|_| "string isn't UTF-8".to_string())?;
//! let value = string.parse().map_err(|_| "parsing failed".to_string())?;
//! Ok(Cover(value))
//! }
//! }
Expand Down

0 comments on commit 3ea04ae

Please sign in to comment.