From f00e86085e13a342fbd2300e49f3e7f7242cdd9c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 6 Jul 2024 10:43:56 +0200 Subject: [PATCH] persistence: add API to name stored data --- src/persistence/fs.rs | 109 ++------------------------- src/persistence/index.rs | 3 + src/persistence/memory.rs | 151 ++++++++++++++++++++++++++++++-------- src/persistence/stash.rs | 3 + src/persistence/stock.rs | 77 +++++++++++++++++++ 5 files changed, 211 insertions(+), 132 deletions(-) diff --git a/src/persistence/fs.rs b/src/persistence/fs.rs index 22640d1a..a58283b0 100644 --- a/src/persistence/fs.rs +++ b/src/persistence/fs.rs @@ -19,110 +19,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::path::Path; +use std::path::{Path, PathBuf}; -use amplify::confinement::U32; -use strict_encoding::{DeserializeError, SerializeError, StrictDeserialize, StrictSerialize}; +use strict_encoding::{DeserializeError, SerializeError}; -use crate::persistence::{ - IndexProvider, MemIndex, MemStash, MemState, StashProvider, StateProvider, Stock, -}; +pub trait FsStored: Sized { + fn new(path: impl ToOwned) -> Self; + fn load(path: impl ToOwned) -> Result; -pub trait LoadFs: Sized { - fn load(path: impl AsRef) -> Result; -} + fn is_dirty(&self) -> bool; + fn filename(&self) -> &Path; + fn set_filename(&mut self, filename: impl ToOwned) -> PathBuf; -pub trait StoreFs { fn store(&self) -> Result<(), SerializeError>; } - -impl LoadFs for Stock -where - S: LoadFs, - H: LoadFs, - I: LoadFs, -{ - fn load(path: impl AsRef) -> Result { - let path = path.as_ref(); - let stash = S::load(path)?; - let state = H::load(path)?; - let index = I::load(path)?; - - Ok(Stock::with(stash, state, index)) - } -} - -impl StoreFs for Stock -where - S: StoreFs, - H: StoreFs, - I: StoreFs, -{ - fn store(&self) -> Result<(), SerializeError> { - self.as_stash_provider().store()?; - self.as_state_provider().store()?; - self.as_index_provider().store()?; - - Ok(()) - } -} - -impl LoadFs for MemStash { - fn load(path: impl AsRef) -> Result { - let mut file = path.as_ref().to_owned(); - file.push("stash.dat"); - let mut me = Self::strict_deserialize_from_file::(&file)?; - me.set_filename(file); - Ok(me) - } -} - -impl StoreFs for MemStash { - fn store(&self) -> Result<(), SerializeError> { - if self.is_dirty() { - self.strict_serialize_to_file::(&self.filename()) - } else { - Ok(()) - } - } -} - -impl LoadFs for MemState { - fn load(path: impl AsRef) -> Result { - let mut file = path.as_ref().to_owned(); - file.push("state.dat"); - let mut me = Self::strict_deserialize_from_file::(&file)?; - me.set_filename(file); - Ok(me) - } -} - -impl StoreFs for MemState { - fn store(&self) -> Result<(), SerializeError> { - if self.is_dirty() { - self.strict_serialize_to_file::(&self.filename()) - } else { - Ok(()) - } - } -} - -impl LoadFs for MemIndex { - fn load(path: impl AsRef) -> Result { - let mut file = path.as_ref().to_owned(); - file.push("index.dat"); - let mut me = Self::strict_deserialize_from_file::(&file)?; - me.set_filename(file); - Ok(me) - } -} - -impl StoreFs for MemIndex { - fn store(&self) -> Result<(), SerializeError> { - if self.is_dirty() { - self.strict_serialize_to_file::(&self.filename()) - } else { - Ok(()) - } - } -} diff --git a/src/persistence/index.rs b/src/persistence/index.rs index fc49f0e1..0ad897f2 100644 --- a/src/persistence/index.rs +++ b/src/persistence/index.rs @@ -147,6 +147,9 @@ impl Index

{ #[doc(hidden)] pub fn as_provider(&self) -> &P { &self.provider } + #[doc(hidden)] + pub(super) fn as_provider_mut(&mut self) -> &mut P { &mut self.provider } + pub(super) fn index_consignment( &mut self, consignment: &Consignment, diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index c0797cdc..6f4d267e 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -22,7 +22,7 @@ use std::collections::BTreeSet; use std::convert::Infallible; #[cfg(feature = "fs")] -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use aluvm::library::{Lib, LibId}; use amplify::confinement::{ @@ -86,16 +86,6 @@ pub struct MemStash { impl StrictSerialize for MemStash {} impl StrictDeserialize for MemStash {} -impl MemStash { - pub fn new() -> Self { MemStash::default() } - - pub(crate) fn is_dirty(&self) -> bool { self.dirty } - #[cfg(feature = "fs")] - pub(crate) fn filename(&self) -> &Path { &self.filename } - #[cfg(feature = "fs")] - pub(crate) fn set_filename(&mut self, filename: PathBuf) { self.filename = filename } -} - impl StoreTransaction for MemStash { type TransactionErr = confinement::Error; @@ -446,16 +436,6 @@ pub struct MemState { impl StrictSerialize for MemState {} impl StrictDeserialize for MemState {} -impl MemState { - pub fn new() -> Self { MemState::default() } - - pub(crate) fn is_dirty(&self) -> bool { self.dirty } - #[cfg(feature = "fs")] - pub(crate) fn filename(&self) -> &Path { &self.filename } - #[cfg(feature = "fs")] - pub(crate) fn set_filename(&mut self, filename: PathBuf) { self.filename = filename } -} - impl StoreTransaction for MemState { type TransactionErr = confinement::Error; @@ -560,16 +540,6 @@ pub struct MemIndex { impl StrictSerialize for MemIndex {} impl StrictDeserialize for MemIndex {} -impl MemIndex { - pub fn new() -> Self { MemIndex::default() } - - pub(crate) fn is_dirty(&self) -> bool { self.dirty } - #[cfg(feature = "fs")] - pub(crate) fn filename(&self) -> &Path { &self.filename } - #[cfg(feature = "fs")] - pub(crate) fn set_filename(&mut self, filename: PathBuf) { self.filename = filename } -} - impl StoreTransaction for MemIndex { type TransactionErr = confinement::Error; @@ -830,3 +800,122 @@ impl IndexWriteProvider for MemIndex { Ok(()) } } + +#[cfg(feature = "fs")] +mod fs { + use std::path::{Path, PathBuf}; + + use amplify::confinement::U32; + use strict_encoding::{DeserializeError, SerializeError, StrictDeserialize, StrictSerialize}; + + use crate::persistence::fs::FsStored; + use crate::persistence::{MemIndex, MemStash, MemState}; + + impl FsStored for MemStash { + fn new(filename: impl ToOwned) -> Self { + Self { + dirty: true, + filename: filename.to_owned(), + ..default!() + } + } + + fn load(path: impl ToOwned) -> Result { + let path = path.to_owned(); + let mut me = Self::strict_deserialize_from_file::(&path)?; + me.set_filename(path); + Ok(me) + } + + fn is_dirty(&self) -> bool { self.dirty } + + fn filename(&self) -> &Path { &self.filename } + + fn set_filename(&mut self, filename: impl ToOwned) -> PathBuf { + let prev = self.filename.to_owned(); + self.filename = filename.to_owned(); + self.dirty = self.filename != prev; + prev + } + + fn store(&self) -> Result<(), SerializeError> { + if self.is_dirty() { + self.strict_serialize_to_file::(&self.filename()) + } else { + Ok(()) + } + } + } + + impl FsStored for MemState { + fn new(filename: impl ToOwned) -> Self { + Self { + dirty: true, + filename: filename.to_owned(), + ..default!() + } + } + + fn load(path: impl ToOwned) -> Result { + let path = path.to_owned(); + let mut me = Self::strict_deserialize_from_file::(&path)?; + me.set_filename(path); + Ok(me) + } + + fn is_dirty(&self) -> bool { self.dirty } + + fn filename(&self) -> &Path { &self.filename } + + fn set_filename(&mut self, filename: impl ToOwned) -> PathBuf { + let prev = self.filename.to_owned(); + self.filename = filename.to_owned(); + self.dirty = self.filename != prev; + prev + } + + fn store(&self) -> Result<(), SerializeError> { + if self.is_dirty() { + self.strict_serialize_to_file::(&self.filename()) + } else { + Ok(()) + } + } + } + + impl FsStored for MemIndex { + fn new(filename: impl ToOwned) -> Self { + Self { + dirty: true, + filename: filename.to_owned(), + ..default!() + } + } + + fn load(path: impl ToOwned) -> Result { + let path = path.to_owned(); + let mut me = Self::strict_deserialize_from_file::(&path)?; + me.set_filename(path); + Ok(me) + } + + fn is_dirty(&self) -> bool { self.dirty } + + fn filename(&self) -> &Path { &self.filename } + + fn set_filename(&mut self, filename: impl ToOwned) -> PathBuf { + let prev = self.filename.to_owned(); + self.filename = filename.to_owned(); + self.dirty = self.filename != prev; + prev + } + + fn store(&self) -> Result<(), SerializeError> { + if self.is_dirty() { + self.strict_serialize_to_file::(&self.filename()) + } else { + Ok(()) + } + } + } +} diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index 23a97cbf..0382da53 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -205,6 +205,9 @@ impl Stash

{ #[doc(hidden)] pub fn as_provider(&self) -> &P { &self.provider } + #[doc(hidden)] + pub(super) fn as_provider_mut(&mut self) -> &mut P { &mut self.provider } + pub(super) fn ifaces(&self) -> Result + '_, StashError

> { self.provider.ifaces().map_err(StashError::ReadProvider) } diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 71a5d8e8..85004fc0 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -372,6 +372,83 @@ impl Stock { pub fn in_memory() -> Self { Self::default() } } +#[cfg(feature = "fs")] +mod fs { + use std::path::PathBuf; + + use strict_encoding::{DeserializeError, SerializeError}; + + use super::*; + use crate::persistence::fs::FsStored; + + impl Stock + where + S: FsStored, + H: FsStored, + I: FsStored, + { + pub fn new(path: impl ToOwned) -> Self { + let mut filename = path.to_owned(); + filename.push("stash.dat"); + let stash = S::new(filename); + + let mut filename = path.to_owned(); + filename.push("state.dat"); + let state = H::new(filename); + + let mut filename = path.to_owned(); + filename.push("index.dat"); + let index = I::new(filename); + + Stock::with(stash, state, index) + } + + pub fn load(path: impl ToOwned) -> Result { + let mut filename = path.to_owned(); + filename.push("stash.dat"); + let stash = S::load(filename)?; + + let mut filename = path.to_owned(); + filename.push("state.dat"); + let state = H::load(filename)?; + + let mut filename = path.to_owned(); + filename.push("index.dat"); + let index = I::load(filename)?; + + Ok(Stock::with(stash, state, index)) + } + + pub fn is_dirty(&self) -> bool { + self.as_stash_provider().is_dirty() || + self.as_state_provider().is_dirty() || + self.as_index_provider().is_dirty() + } + + pub fn set_path(&mut self, path: impl ToOwned) { + let mut filename = path.to_owned(); + filename.push("stash.dat"); + self.stash.as_provider_mut().set_filename(filename); + + let mut filename = path.to_owned(); + filename.push("state.dat"); + self.state.set_filename(filename); + + let mut filename = path.to_owned(); + filename.push("index.dat"); + self.index.as_provider_mut().set_filename(filename); + } + + pub fn store(&self) -> Result<(), SerializeError> { + self.as_stash_provider().store()?; + self.as_state_provider().store()?; + self.as_index_provider().store()?; + + Ok(()) + } + } +} + impl Stock { pub fn with(stash_provider: S, state_provider: H, index_provider: P) -> Self { Stock {