use serde::{ser::Serializer, Deserialize, Deserializer, Serialize};
use std::{
fmt::{self, Debug, Display},
hash::{Hash, Hasher},
ops::Deref,
};
mod span;
pub use span::Marker;
pub use span::Span;
pub struct Spanned<T> {
span: Span,
node: T,
}
impl<'de, T> Spanned<T>
where
T: Deserialize<'de>,
{
pub fn new(node: T) -> Self {
Spanned {
span: Default::default(),
node,
}
}
}
impl<T> Spanned<T> {
pub fn map<U, F>(self, f: F) -> Spanned<U>
where
F: FnOnce(T) -> U,
{
Spanned {
span: self.span,
node: f(self.node),
}
}
pub fn map_span<F>(self, f: F) -> Self
where
F: FnOnce(Span) -> Span,
{
Self {
span: f(self.span),
..self
}
}
pub fn into_inner(self) -> T {
self.node
}
pub fn span(&self) -> &Span {
&self.span
}
pub fn has_valid_span(&self) -> bool {
self.span.is_valid()
}
}
impl<T> Deref for Spanned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.node
}
}
impl<T> AsRef<T> for Spanned<T> {
fn as_ref(&self) -> &T {
&self.node
}
}
impl<T> AsMut<T> for Spanned<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.node
}
}
impl<T> Clone for Spanned<T>
where
T: Clone,
{
fn clone(&self) -> Self {
Spanned {
span: self.span.clone(),
node: self.node.clone(),
}
}
}
impl<T> Debug for Spanned<T>
where
T: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{{:?}}} ", self.span)?;
Debug::fmt(&self.node, f)
}
}
impl<T> Default for Spanned<T>
where
T: Default,
{
fn default() -> Self {
Spanned {
span: Default::default(),
node: T::default(),
}
}
}
impl<'de, T> From<T> for Spanned<T>
where
T: Deserialize<'de>,
{
fn from(node: T) -> Self {
Spanned::new(node)
}
}
impl<T> PartialEq for Spanned<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.node == other.node
}
}
impl<T> Eq for Spanned<T> where T: Eq {}
impl<T> PartialOrd for Spanned<T>
where
T: PartialOrd,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.node.partial_cmp(&other.node)
}
}
impl<T> Ord for Spanned<T>
where
T: Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.node.cmp(&other.node)
}
}
impl<T> Hash for Spanned<T>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.node.hash(state);
}
}
impl<T> Display for Spanned<T>
where
T: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as Display>::fmt(&self.node, f)
}
}
impl<T> Serialize for Spanned<T>
where
T: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
set_span(self.span.clone());
T::serialize(&self.node, serializer)
}
}
impl<'de, T> Deserialize<'de> for Spanned<T>
where
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let start_marker = get_marker();
let node = T::deserialize(deserializer)?;
let end_marker = get_marker();
let span: Span = (start_marker..end_marker).into();
#[cfg(feature = "filename")]
let span = span.maybe_capture_filename();
Ok(Spanned { span, node })
}
}
#[cfg(feature = "schemars")]
impl<T> schemars::JsonSchema for Spanned<T>
where
T: schemars::JsonSchema,
{
fn schema_name() -> String {
T::schema_name()
}
fn json_schema(generator: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
T::json_schema(generator)
}
fn is_referenceable() -> bool {
T::is_referenceable()
}
fn schema_id() -> std::borrow::Cow<'static, str> {
T::schema_id()
}
#[doc(hidden)]
fn _schemars_private_non_optional_json_schema(
generator: &mut schemars::gen::SchemaGenerator,
) -> schemars::schema::Schema {
T::_schemars_private_non_optional_json_schema(generator)
}
#[doc(hidden)]
fn _schemars_private_is_option() -> bool {
T::_schemars_private_is_option()
}
}
#[cfg(feature = "filename")]
pub struct WithFilenameScope {
original: Option<std::sync::Arc<std::path::PathBuf>>,
}
#[cfg(feature = "filename")]
impl Drop for WithFilenameScope {
fn drop(&mut self) {
FILENAME.with(|f| *f.borrow_mut() = std::mem::take(&mut self.original));
}
}
#[cfg(feature = "filename")]
pub fn with_filename(filename: Option<std::path::PathBuf>) -> WithFilenameScope {
let original = FILENAME.with(|f| f.borrow_mut().take());
FILENAME.with(|f| *f.borrow_mut() = filename.map(std::sync::Arc::new));
WithFilenameScope { original }
}
pub fn set_marker(marker: impl Into<Marker>) {
MARKER.with(|m| *m.borrow_mut() = Some(marker.into()));
}
pub fn reset_marker() {
MARKER.with(|m| *m.borrow_mut() = None);
}
pub(crate) fn get_marker() -> Option<Marker> {
MARKER.with(|m| *m.borrow())
}
pub(crate) fn set_span(span: Span) {
SPAN.with(|s| *s.borrow_mut() = Some(span));
}
pub(crate) fn take_span() -> Option<Span> {
SPAN.with(|s| s.borrow_mut().take())
}
#[cfg(feature = "filename")]
pub(crate) fn set_filename(filename: std::sync::Arc<std::path::PathBuf>) {
FILENAME.with(|f| *f.borrow_mut() = Some(filename));
}
#[cfg(feature = "filename")]
pub(crate) fn get_filename() -> Option<std::sync::Arc<std::path::PathBuf>> {
FILENAME.with(|f| f.borrow().clone())
}
thread_local! {
static MARKER: std::cell::RefCell<Option<Marker>> = const {
std::cell::RefCell::new(None)
};
#[cfg(feature = "filename")]
static FILENAME: std::cell::RefCell<Option<std::sync::Arc<std::path::PathBuf>>> = const {
std::cell::RefCell::new(None)
};
}
thread_local! {
static SPAN: std::cell::RefCell<Option<Span>> = const {
std::cell::RefCell::new(None)
};
}