rdf_model/default_graph.rs
1// This is free and unencumbered software released into the public domain.
2
3use crate::{Term, TermKind};
4
5/// The reserved default-graph identifier for term-only external protocols.
6///
7/// Prefer a protocol's native default-graph representation when available.
8/// This URN is a boundary convention, not an ordinary IRI that the model
9/// automatically reclassifies: an IRI containing this string is distinct from
10/// [`DEFAULT_GRAPH`] internally. A protocol using this convention must reserve
11/// the URN in its graph-name namespace.
12pub const DEFAULT_GRAPH_URN: &str = "urn:rdf:default-graph";
13
14/// The singleton default-graph marker.
15///
16/// In a pattern, `None` selects any graph, `Some(DEFAULT_GRAPH.into())` selects
17/// the default graph, and another term selects that named graph. In a concrete
18/// quad, `None` is the canonical default-graph representation.
19pub const DEFAULT_GRAPH: DefaultGraph = DefaultGraph;
20
21/// An allocation-free singleton denoting the default graph.
22///
23/// Use this marker in graph slots, not as an ordinary RDF subject, predicate,
24/// or object. It has its own [`TermKind::DefaultGraph`] identity. [`Display`](core::fmt::Display)
25/// and Serde use [`DEFAULT_GRAPH_URN`] for external representation; decoding an
26/// IRI as this marker requires the explicit [`Self::from_urn`] convention.
27/// Built-in owned/Cow terms implement `From<DefaultGraph>` without allocating.
28///
29/// # Examples
30///
31/// ```rust
32/// # #[cfg(feature = "alloc")] {
33/// use rdf_model::{DEFAULT_GRAPH, HeapQuad, HeapQuadPattern, HeapTerm, StatementPattern};
34/// let pattern = HeapQuadPattern::new(None, None, None, Some(DEFAULT_GRAPH.into()));
35/// let quad = HeapQuad::new(HeapTerm::iri("urn:s"), HeapTerm::iri("urn:p"), HeapTerm::string("o"), None);
36/// assert!(pattern.matches_statement(&quad));
37/// assert!(!pattern.matches_statement(&quad.with_context(HeapTerm::iri("urn:g"))));
38/// # }
39/// ```
40#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
41#[cfg_attr(
42 feature = "borsh",
43 derive(borsh::BorshSerialize, borsh::BorshDeserialize)
44)]
45pub struct DefaultGraph;
46
47impl DefaultGraph {
48 /// Recognizes the exact reserved URN at a boundary that opts into this
49 /// convention. Returns `None` for any other identifier.
50 pub fn from_urn(urn: &str) -> Option<Self> {
51 (urn == DEFAULT_GRAPH_URN).then_some(Self)
52 }
53}
54
55impl Term for DefaultGraph {
56 fn kind(&self) -> TermKind {
57 TermKind::DefaultGraph
58 }
59
60 #[cfg(feature = "alloc")]
61 fn value_str(&self) -> alloc::borrow::Cow<'_, str> {
62 alloc::borrow::Cow::Borrowed(DEFAULT_GRAPH_URN)
63 }
64}
65
66impl core::fmt::Display for DefaultGraph {
67 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68 f.write_str(DEFAULT_GRAPH_URN)
69 }
70}
71
72impl Term for &DefaultGraph {
73 fn kind(&self) -> TermKind {
74 TermKind::DefaultGraph
75 }
76
77 #[cfg(feature = "alloc")]
78 fn value_str(&self) -> alloc::borrow::Cow<'_, str> {
79 alloc::borrow::Cow::Borrowed(DEFAULT_GRAPH_URN)
80 }
81}
82
83impl From<DefaultGraph> for &DefaultGraph {
84 fn from(_: DefaultGraph) -> Self {
85 &DEFAULT_GRAPH
86 }
87}
88
89#[cfg(feature = "serde")]
90impl serde::Serialize for DefaultGraph {
91 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
92 serializer.serialize_str(DEFAULT_GRAPH_URN)
93 }
94}
95
96#[cfg(feature = "serde")]
97impl<'de> serde::Deserialize<'de> for DefaultGraph {
98 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
99 let urn = <alloc::string::String as serde::Deserialize>::deserialize(deserializer)?;
100 Self::from_urn(&urn)
101 .ok_or_else(|| serde::de::Error::custom("expected urn:rdf:default-graph"))
102 }
103}
104
105#[cfg(feature = "oxrdf")]
106impl From<DefaultGraph> for oxrdf::GraphName {
107 fn from(_: DefaultGraph) -> Self {
108 Self::DefaultGraph
109 }
110}