pub mod builders;
use crate::{
protocol::{SyncEffect, Visitor},
Walker,
};
/// A buildable type.
pub trait Build<'ctx>: Sized {
/// The builder that can be used to build a value of `Self`.
type Builder: Builder<'ctx, Value = Self>;
}
/// Builder for a type.
///
/// The `'ctx` lifetime is some lifetime that is longer than the walker.
/// As such, the built value can borrow from other data with a `'ctx` lifetimes.
///
/// A builder allows creating a value of a type [`Self::Value`].
/// The way to use a builder is as follows.
/// - Call [`Default::default()`] to create an instance of the builder.
/// - Call [`Self::as_visitor()`] and give it to a walker's
/// [`walk()`][crate::walk::Walker::walk]. The walker will then fill
/// the builder with data from it's walk.
/// - Call [`Self::build()`] to finish building the value and get any errors
/// that happened during filling it with data.
pub trait Builder<'ctx>: Default {
/// Error that can happen during filling the builder with data.
type Error;
/// Type to be built.
type Value;
/// Get the builder as a visitor that a walker can use.
///
/// This is expected to just be `self`.
fn as_visitor(&mut self) -> &mut Visitor<'_, 'ctx>;
/// Finish the value.
///
/// If an error happened with the builder during the walk
/// it will be reported here.
fn build(self) -> Result<Self::Value, Self::Error>;
}
#[derive(Debug)]
pub enum BuildError<B, W> {
Builder(B),
Walker(W),
}
#[inline]
pub fn build<'ctx, T: Build<'ctx>, W: Walker<'ctx, Effect = SyncEffect>>(
walker: W,
) -> Result<T, BuildError<<<T as Build<'ctx>>::Builder as Builder<'ctx>>::Error, W::Error>> {
let mut builder = T::Builder::default();
if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()) {
return Err(BuildError::Walker(err));
}
builder.build().map_err(BuildError::Builder)
}
pub fn build_with<'ctx, B: Builder<'ctx>, W: Walker<'ctx, Effect = SyncEffect>>(
walker: W,
) -> Result<B::Value, BuildError<B::Error, W::Error>> {
let mut builder = B::default();
if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()) {
return Err(BuildError::Walker(err));
}
builder.build().map_err(BuildError::Builder)
}
#[cfg(feature = "alloc")]
use crate::protocol::AsyncEffect;
#[cfg(feature = "alloc")]
pub async fn async_build_with<'ctx, B: Builder<'ctx>, W: Walker<'ctx, Effect = AsyncEffect>>(
walker: W,
) -> Result<B::Value, BuildError<B::Error, W::Error>> {
let mut builder = B::default();
if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()).await {
return Err(BuildError::Walker(err));
}
builder.build().map_err(BuildError::Builder)
}