Skip to main content

jstrict/print/
contextual.rs

1//! Printing adapters for the [`contextual`] crate.
2//!
3//! These mirror [`Print`](super::Print), [`PrintWithSize`](super::PrintWithSize)
4//! and [`PrecomputeSize`](super::PrecomputeSize), threading a `&C` context
5//! through so that types whose rendering depends on external state (an IRI
6//! namespace, a vocabulary, …) can be printed as JSON. Wrapping such a value
7//! in `contextual::Contextual` gives back the plain print traits.
8use contextual::{Contextual, WithContext};
9use core::hash::BuildHasher;
10use std::collections::HashSet;
11use std::fmt;
12
13use super::{Options, Size};
14
15/// [`Print`](super::Print) with an additional context.
16pub trait PrintWithContext<C> {
17	/// Writes the value to `f`, resolving it against `context`.
18	/// # Errors
19	///
20	/// Returns [`fmt::Error`] if writing to the formatter fails.
21	fn contextual_fmt_with(
22		&self,
23		context: &C,
24		f: &mut fmt::Formatter,
25		options: &Options,
26		indent: usize,
27	) -> fmt::Result;
28}
29
30impl<T: PrintWithContext<C> + ?Sized, C> PrintWithContext<C> for &T {
31	fn contextual_fmt_with(
32		&self,
33		context: &C,
34		f: &mut fmt::Formatter,
35		options: &Options,
36		indent: usize,
37	) -> fmt::Result {
38		T::contextual_fmt_with(*self, context, f, options, indent)
39	}
40}
41
42impl<T: PrintWithContext<C>, C> super::Print for Contextual<T, &C> {
43	fn fmt_with(&self, f: &mut fmt::Formatter, options: &Options, indent: usize) -> fmt::Result {
44		self.0.contextual_fmt_with(self.1, f, options, indent)
45	}
46}
47
48/// [`PrintWithSize`](super::PrintWithSize) with an additional context.
49pub trait PrintWithSizeAndContext<C> {
50	/// Writes the value to `f` against `context`, taking its layout from
51	/// `sizes[*index]`.
52	/// # Errors
53	///
54	/// Returns [`fmt::Error`] if writing to the formatter fails.
55	fn contextual_fmt_with_size(
56		&self,
57		context: &C,
58		f: &mut fmt::Formatter,
59		options: &Options,
60		indent: usize,
61		sizes: &[Size],
62		index: &mut usize,
63	) -> fmt::Result;
64}
65
66impl<T: PrintWithSizeAndContext<C> + ?Sized, C> PrintWithSizeAndContext<C> for &T {
67	fn contextual_fmt_with_size(
68		&self,
69		context: &C,
70		f: &mut fmt::Formatter,
71		options: &Options,
72		indent: usize,
73		sizes: &[Size],
74		index: &mut usize,
75	) -> fmt::Result {
76		T::contextual_fmt_with_size(*self, context, f, options, indent, sizes, index)
77	}
78}
79
80impl<T: PrintWithSizeAndContext<C>, C> super::PrintWithSize for Contextual<T, &C> {
81	fn fmt_with_size(
82		&self,
83		f: &mut fmt::Formatter,
84		options: &Options,
85		indent: usize,
86		sizes: &[Size],
87		index: &mut usize,
88	) -> fmt::Result {
89		self.0
90			.contextual_fmt_with_size(self.1, f, options, indent, sizes, index)
91	}
92}
93
94/// [`PrecomputeSize`](super::PrecomputeSize) with an additional context.
95pub trait PrecomputeSizeWithContext<C> {
96	/// Computes the printed size of this value against `context`.
97	fn contextual_pre_compute_size(
98		&self,
99		context: &C,
100		options: &Options,
101		sizes: &mut Vec<Size>,
102	) -> Size;
103}
104
105impl<T: PrecomputeSizeWithContext<C> + ?Sized, C> PrecomputeSizeWithContext<C> for &T {
106	fn contextual_pre_compute_size(
107		&self,
108		context: &C,
109		options: &Options,
110		sizes: &mut Vec<Size>,
111	) -> Size {
112		T::contextual_pre_compute_size(*self, context, options, sizes)
113	}
114}
115
116impl<T: PrecomputeSizeWithContext<C>, C> super::PrecomputeSize for Contextual<T, &C> {
117	fn pre_compute_size(&self, options: &Options, sizes: &mut Vec<Size>) -> Size {
118		self.0.contextual_pre_compute_size(self.1, options, sizes)
119	}
120}
121
122impl<T: PrecomputeSizeWithContext<C>, C> PrecomputeSizeWithContext<C> for [T] {
123	fn contextual_pre_compute_size(
124		&self,
125		context: &C,
126		options: &Options,
127		sizes: &mut Vec<Size>,
128	) -> Size {
129		super::pre_compute_array_size(self.iter().map(|i| i.with(context)), options, sizes)
130	}
131}
132
133impl<T: PrintWithSizeAndContext<C>, C> PrintWithSizeAndContext<C> for [T] {
134	fn contextual_fmt_with_size(
135		&self,
136		context: &C,
137		f: &mut fmt::Formatter,
138		options: &Options,
139		indent: usize,
140		sizes: &[Size],
141		index: &mut usize,
142	) -> fmt::Result {
143		super::print_array(
144			self.iter().map(|i| i.with(context)),
145			f,
146			options,
147			indent,
148			sizes,
149			index,
150		)
151	}
152}
153
154impl<T: PrecomputeSizeWithContext<C>, C, S: BuildHasher> PrecomputeSizeWithContext<C>
155	for HashSet<T, S>
156{
157	fn contextual_pre_compute_size(
158		&self,
159		context: &C,
160		options: &Options,
161		sizes: &mut Vec<Size>,
162	) -> Size {
163		super::pre_compute_array_size(self.iter().map(|i| i.with(context)), options, sizes)
164	}
165}
166
167impl<T: PrintWithSizeAndContext<C>, C, S: BuildHasher> PrintWithSizeAndContext<C>
168	for HashSet<T, S>
169{
170	fn contextual_fmt_with_size(
171		&self,
172		context: &C,
173		f: &mut fmt::Formatter,
174		options: &Options,
175		indent: usize,
176		sizes: &[Size],
177		index: &mut usize,
178	) -> fmt::Result {
179		super::print_array(
180			self.iter().map(|i| i.with(context)),
181			f,
182			options,
183			indent,
184			sizes,
185			index,
186		)
187	}
188}