use super::ResolvedSchema;
use std::fmt;
use std::ops::Deref;
use std::sync::{Arc, Weak};
pub struct Shared<T>(Arc<T>);
impl<T> Shared<T> {
pub(super) fn new(item: Arc<T>) -> Self {
Self(item)
}
pub fn as_ptr(this: &Self) -> *const T {
Arc::as_ptr(&this.0)
}
}
impl<T> Deref for Shared<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: fmt::Debug> fmt::Debug for Shared<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: PartialEq> PartialEq for Shared<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
pub struct NestedSchema(Edge);
enum Edge {
Schema(Arc<ResolvedSchema>),
Recursive(Weak<ResolvedSchema>),
}
impl NestedSchema {
pub(super) fn schema(schema: Arc<ResolvedSchema>) -> Self {
Self(Edge::Schema(schema))
}
pub(super) fn recursive(schema: Weak<ResolvedSchema>) -> Self {
Self(Edge::Recursive(schema))
}
pub(super) fn duplicate(&self) -> Self {
Self(match &self.0 {
Edge::Schema(schema) => Edge::Schema(Arc::clone(schema)),
Edge::Recursive(schema) => Edge::Recursive(Weak::clone(schema)),
})
}
pub fn get(&self) -> SchemaGuard<'_> {
SchemaGuard(match &self.0 {
Edge::Schema(schema) => Guard::Borrowed(schema),
#[allow(clippy::expect_used)]
Edge::Recursive(schema) => Guard::Upgraded(
schema
.upgrade()
.expect("recursive schema edge outlived its document"),
),
})
}
pub fn is_recursive(&self) -> bool {
matches!(self.0, Edge::Recursive(_))
}
}
impl fmt::Debug for NestedSchema {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
Edge::Schema(schema) => schema.fmt(f),
Edge::Recursive(_) => f.write_str("Recursive(..)"),
}
}
}
impl PartialEq for NestedSchema {
fn eq(&self, other: &Self) -> bool {
match (&self.0, &other.0) {
(Edge::Schema(left), Edge::Schema(right)) => left == right,
(Edge::Recursive(left), Edge::Recursive(right)) => Weak::ptr_eq(left, right),
(Edge::Schema(_), Edge::Recursive(_)) | (Edge::Recursive(_), Edge::Schema(_)) => false,
}
}
}
pub struct SchemaGuard<'a>(Guard<'a>);
enum Guard<'a> {
Borrowed(&'a ResolvedSchema),
Upgraded(Arc<ResolvedSchema>),
}
impl SchemaGuard<'_> {
pub fn as_ptr(this: &Self) -> *const ResolvedSchema {
match &this.0 {
Guard::Borrowed(schema) => *schema,
Guard::Upgraded(schema) => Arc::as_ptr(schema),
}
}
}
impl Deref for SchemaGuard<'_> {
type Target = ResolvedSchema;
fn deref(&self) -> &ResolvedSchema {
match &self.0 {
Guard::Borrowed(schema) => schema,
Guard::Upgraded(schema) => schema,
}
}
}
impl fmt::Debug for SchemaGuard<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}