libvault 0.2.2

the libvault is modified from RustyVault
Documentation
use super::{Backend, Field, Operation, field::IntoFieldArc, request::Request, response::Response};
use crate::{context::Context, errors::RvError};
use std::{collections::HashMap, fmt, future::Future, pin::Pin, sync::Arc};

pub type PathOperationFuture<'a> =
    Pin<Box<dyn Future<Output = Result<Option<Response>, RvError>> + Send + 'a>>;
type PathOperationHandler =
    dyn for<'a> Fn(&'a dyn Backend, &'a mut Request) -> PathOperationFuture<'a> + Send + Sync;

#[derive(Debug, Clone)]
pub struct Path {
    pub ctx: Arc<Context>,
    pub pattern: String,
    pub fields: HashMap<String, Arc<Field>>,
    pub operations: Vec<PathOperation>,
    pub help: String,
}

impl Default for Path {
    fn default() -> Self {
        Self {
            ctx: Arc::new(Context::new()),
            pattern: String::new(),
            fields: HashMap::new(),
            operations: Vec::new(),
            help: String::new(),
        }
    }
}

#[derive(Debug, Clone, Default)]
pub struct PathBuilder {
    path: Path,
}

impl PathBuilder {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn context(mut self, ctx: Arc<Context>) -> Self {
        self.path.ctx = ctx;
        self
    }

    pub fn pattern(mut self, pattern: impl Into<String>) -> Self {
        self.path.pattern = pattern.into();
        self
    }

    pub fn help(mut self, help: impl Into<String>) -> Self {
        self.path.help = help.into();
        self
    }

    pub fn fields(mut self, fields: HashMap<String, Arc<Field>>) -> Self {
        self.path.fields = fields;
        self
    }

    pub fn field<F>(mut self, name: impl Into<String>, field: F) -> Self
    where
        F: IntoFieldArc,
    {
        self.path.fields.insert(name.into(), field.into_field_arc());
        self
    }

    pub fn operations(mut self, operations: Vec<PathOperation>) -> Self {
        self.path.operations = operations;
        self
    }

    pub fn operation<H>(mut self, op: Operation, handler: H) -> Self
    where
        H: for<'a> Fn(&'a dyn Backend, &'a mut Request) -> PathOperationFuture<'a>
            + Send
            + Sync
            + 'static,
    {
        self.path
            .operations
            .push(PathOperation::with_handler(op, handler));
        self
    }

    pub fn operation_entry(mut self, operation: PathOperation) -> Self {
        self.path.operations.push(operation);
        self
    }

    pub fn build(self) -> Path {
        self.path
    }
}

#[derive(Clone)]
pub struct PathOperation {
    pub op: Operation,
    pub handler: Arc<PathOperationHandler>,
}

impl fmt::Debug for PathOperation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("PathOperation")
            .field("op", &self.op)
            .finish()
    }
}

impl PathOperation {
    pub fn with_handler<H>(op: Operation, handler: H) -> Self
    where
        H: for<'a> Fn(&'a dyn Backend, &'a mut Request) -> PathOperationFuture<'a>
            + Send
            + Sync
            + 'static,
    {
        Self {
            op,
            handler: Arc::new(handler),
        }
    }
}

impl Path {
    pub fn new(pattern: &str) -> Self {
        Self {
            pattern: pattern.to_string(),
            ..Self::default()
        }
    }

    pub fn builder() -> PathBuilder {
        PathBuilder::new()
    }

    pub fn get_field(&self, key: &str) -> Option<Arc<Field>> {
        self.fields.get(key).cloned()
    }
}

impl PathOperation {
    pub fn new() -> Self {
        Self {
            op: Operation::Read,
            handler: Arc::new(|_backend, _req| Box::pin(async move { Ok(None) })),
        }
    }

    pub async fn handle_request(
        &self,
        backend: &dyn Backend,
        req: &mut Request,
    ) -> Result<Option<Response>, RvError> {
        (self.handler)(backend, req).await
    }
}