use crate::store::{StoreError, DEFAULT_CAPACITY};
use crate::Reducer;
use crate::StoreImpl;
use crate::{channel, Store};
use crate::{BackpressurePolicy, MiddlewareFnFactory};
use std::sync::Arc;
pub struct StoreBuilder<State, Action>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + 'static,
{
name: String,
state: State,
reducers: Vec<Box<dyn Reducer<State, Action> + Send + Sync>>,
without_reducer: bool,
capacity: usize,
policy: BackpressurePolicy<Action>,
middlewares: Vec<Arc<dyn MiddlewareFnFactory<State, Action> + Send + Sync>>,
}
impl<State, Action> StoreBuilder<State, Action>
where
State: Send + Sync + Clone + 'static,
Action: Send + Sync + Clone + std::fmt::Debug + 'static,
{
pub fn new(state: State) -> Self {
StoreBuilder {
name: "store".to_string(),
state,
reducers: vec![],
without_reducer: false,
capacity: DEFAULT_CAPACITY,
policy: Default::default(),
middlewares: Vec::new(),
}
}
pub fn new_with_reducer(
state: State,
reducer: Box<dyn Reducer<State, Action> + Send + Sync>,
) -> Self {
StoreBuilder {
name: "store".to_string(),
state,
reducers: vec![reducer],
without_reducer: false,
capacity: DEFAULT_CAPACITY,
policy: Default::default(),
middlewares: Vec::new(),
}
}
pub fn with_name(mut self, name: String) -> Self {
self.name = name;
self
}
pub fn with_reducer(mut self, reducer: Box<dyn Reducer<State, Action> + Send + Sync>) -> Self {
self.reducers = vec![reducer];
self.without_reducer = false;
self
}
pub fn with_reducers(
mut self,
reducers: Vec<Box<dyn Reducer<State, Action> + Send + Sync>>,
) -> Self {
self.reducers = reducers;
self.without_reducer = false;
self
}
pub fn add_reducer(mut self, reducer: Box<dyn Reducer<State, Action> + Send + Sync>) -> Self {
self.reducers.push(reducer);
self
}
pub fn with_capacity(mut self, capacity: usize) -> Self {
self.capacity = capacity;
self.without_reducer = false;
self
}
pub fn with_policy(mut self, policy: channel::BackpressurePolicy<Action>) -> Self {
self.policy = policy;
self
}
pub fn with_middleware(
mut self,
middleware: Arc<dyn MiddlewareFnFactory<State, Action> + Send + Sync>,
) -> Self {
self.middlewares = vec![middleware];
self
}
pub fn with_middlewares(
mut self,
middlewares: Vec<Arc<dyn MiddlewareFnFactory<State, Action> + Send + Sync>>,
) -> Self {
self.middlewares = middlewares;
self
}
pub fn add_middleware(
mut self,
middleware: Arc<dyn MiddlewareFnFactory<State, Action> + Send + Sync>,
) -> Self {
self.middlewares.push(middleware);
self
}
pub fn build(self) -> Result<Arc<dyn Store<State, Action>>, StoreError> {
if !self.without_reducer && self.reducers.is_empty() {
return Err(StoreError::InitError("reducers are empty".to_string()));
}
if self.name.is_empty() {
return Err(StoreError::InitError("name is empty".to_string()));
}
if self.capacity == 0 {
return Err(StoreError::InitError("capacity is 0".to_string()));
}
let store_impl = StoreImpl::new_with(
self.state,
self.reducers,
self.name,
self.capacity,
self.policy,
self.middlewares,
);
match store_impl {
Ok(store_impl) => Ok(store_impl),
Err(e) => Err(e),
}
}
}
#[cfg(test)]
mod tests {
use crate::MiddlewareFn;
use super::*;
struct TestReducer;
impl Reducer<i32, i32> for TestReducer {
fn reduce(&self, state: &i32, action: &i32) -> crate::DispatchOp<i32, i32> {
crate::DispatchOp::Dispatch(state + action, vec![])
}
}
#[test]
fn test_builder() {
let store = StoreBuilder::new(0).with_reducer(Box::new(TestReducer)).build();
assert!(store.is_ok());
}
#[test]
fn test_builder_with_name() {
let store = StoreBuilder::new(0)
.with_reducer(Box::new(TestReducer))
.with_name("test".to_string())
.build();
assert!(store.is_ok());
}
#[test]
fn test_builder_with_reducers() {
let store = StoreBuilder::new(0)
.with_reducers(vec![Box::new(TestReducer), Box::new(TestReducer)])
.build();
assert!(store.is_ok());
}
#[test]
fn test_builder_with_capacity() {
let store =
StoreBuilder::new(0).with_reducer(Box::new(TestReducer)).with_capacity(100).build();
assert!(store.is_ok());
}
struct TestMiddleware;
impl MiddlewareFnFactory<i32, i32> for TestMiddleware {
fn create(&self, inner: MiddlewareFn<i32, i32>) -> MiddlewareFn<i32, i32> {
Arc::new(move |state: &i32, action: &i32| {
println!("TestMiddleware: before action");
let r = inner(state, action);
println!("TestMiddleware: after action");
r
})
}
}
#[test]
fn test_builder_with_middleware() {
let store = StoreBuilder::new(0)
.with_reducer(Box::new(TestReducer))
.with_middleware(Arc::new(TestMiddleware))
.build();
assert!(store.is_ok());
}
#[test]
fn test_builder_build_droppable() {
let store = StoreBuilder::new(0).with_reducer(Box::new(TestReducer)).build();
assert!(store.is_ok());
drop(store);
}
}