use std::{
    fmt::{Debug, Display},
    ops::Range,
};

#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Span {
    pub start: usize,
    pub end: usize,
}

impl Span {
    pub(crate) fn char(i: usize) -> Self {
        Self {
            start: i,
            end: i + 1,
        }
    }
}

impl Display for Span {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}..{}", self.start, self.end)
    }
}
impl Debug for Span {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{self}")
    }
}

impl From<Range<Span>> for Span {
    fn from(Range { start, end }: Range<Span>) -> Self {
        Self {
            start: start.start,
            end: end.end,
        }
    }
}

impl From<Range<usize>> for Span {
    fn from(Range { start, end }: Range<usize>) -> Self {
        Self { start, end }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Chunk<T> {
    pub data: T,
    pub span: Span,
}

impl<T> Chunk<T> {
    pub fn new(span: impl Into<Span>, data: T) -> Self {
        Self {
            span: span.into(),
            data,
        }
    }
}
