use core::fmt;
use core::ops::Range;
use musli::context::Error;
use musli::Context;
use crate::allocator::Allocator;
use crate::context::rich_error::{RichError, Step};
use crate::fixed::{FixedString, FixedVec};
pub struct NoStdContext<const P: usize, const S: usize, A, E> {
mark: usize,
alloc: A,
error: Option<(Range<usize>, E)>,
path: FixedVec<Step<FixedString<S>>, P>,
path_cap: usize,
include_type: bool,
}
impl<A, E> NoStdContext<16, 32, A, E> {
pub fn new(alloc: A) -> Self {
Self::new_with(alloc)
}
}
impl<const P: usize, const S: usize, A, E> NoStdContext<P, S, A, E> {
pub fn new_with(alloc: A) -> Self {
Self {
mark: 0,
alloc,
error: None,
path: FixedVec::new(),
path_cap: 0,
include_type: false,
}
}
pub fn include_type(&mut self) -> &mut Self {
self.include_type = true;
self
}
pub fn iter(&self) -> impl Iterator<Item = RichError<'_, impl AsRef<str>, E>> {
self.error
.iter()
.map(|(range, error)| RichError::new(&self.path, self.path_cap, range.clone(), error))
}
fn push_error(&mut self, range: Range<usize>, error: E) {
self.error = Some((range, error));
}
fn push_path(&mut self, step: Step<FixedString<S>>) {
if self.path.try_push(step).is_err() {
self.path_cap += 1;
}
}
fn pop_path(&mut self) {
if self.path_cap > 0 {
self.path_cap -= 1;
return;
}
self.path.pop();
}
}
impl<const V: usize, const S: usize, A, E> Context for NoStdContext<V, S, A, E>
where
A: Allocator,
E: musli::error::Error,
{
type Input = E;
type Error = Error;
type Mark = usize;
type Buf = A::Buf;
#[inline(always)]
fn alloc(&mut self) -> Self::Buf {
self.alloc.alloc()
}
#[inline(always)]
fn report<T>(&mut self, error: T) -> Self::Error
where
E: From<T>,
{
self.push_error(self.mark..self.mark, E::from(error));
Error
}
#[inline]
fn marked_report<T>(&mut self, mark: Self::Mark, message: T) -> Self::Error
where
E: From<T>,
{
self.push_error(mark..self.mark, E::from(message));
Error
}
#[inline(always)]
fn custom<T>(&mut self, message: T) -> Self::Error
where
T: 'static + Send + Sync + fmt::Display + fmt::Debug,
{
self.push_error(self.mark..self.mark, E::custom(message));
Error
}
#[inline(always)]
fn message<T>(&mut self, message: T) -> Self::Error
where
T: fmt::Display,
{
self.push_error(self.mark..self.mark, E::message(message));
Error
}
#[inline]
fn marked_message<T>(&mut self, mark: Self::Mark, message: T) -> Self::Error
where
T: fmt::Display,
{
self.push_error(mark..self.mark, E::message(message));
Error
}
#[inline]
fn mark(&mut self) -> Self::Mark {
self.mark
}
#[inline]
fn advance(&mut self, n: usize) {
self.mark = self.mark.wrapping_add(n);
}
#[inline]
fn enter_named_field<T>(&mut self, name: &'static str, _: T)
where
T: fmt::Display,
{
self.push_path(Step::Named(name));
}
#[inline]
fn enter_unnamed_field<T>(&mut self, index: u32, _: T)
where
T: fmt::Display,
{
self.push_path(Step::Unnamed(index));
}
#[inline]
fn leave_field(&mut self) {
self.pop_path();
}
#[inline]
fn enter_struct(&mut self, name: &'static str) {
if self.include_type {
self.push_path(Step::Struct(name));
}
}
#[inline]
fn leave_struct(&mut self) {
if self.include_type {
self.pop_path();
}
}
#[inline]
fn enter_enum(&mut self, name: &'static str) {
if self.include_type {
self.push_path(Step::Enum(name));
}
}
#[inline]
fn leave_enum(&mut self) {
if self.include_type {
self.pop_path();
}
}
#[inline]
fn enter_variant<T>(&mut self, name: &'static str, _: T) {
self.push_path(Step::Variant(name));
}
#[inline]
fn leave_variant(&mut self) {
self.pop_path();
}
#[inline]
fn enter_sequence_index(&mut self, index: usize) {
self.push_path(Step::Index(index));
}
#[inline]
fn leave_sequence_index(&mut self) {
self.pop_path();
}
#[inline]
fn enter_map_key<T>(&mut self, field: T)
where
T: fmt::Display,
{
use core::fmt::Write;
let mut string = FixedString::new();
let _ = write!(string, "{}", field);
self.push_path(Step::Key(string));
}
#[inline]
fn leave_map_key(&mut self) {
self.pop_path();
}
}