Skip to content

Commit 72ebe4e

Browse files
committed
Split format-specific filters into own module.
1 parent 31214a7 commit 72ebe4e

File tree

4 files changed

+151
-136
lines changed

4 files changed

+151
-136
lines changed

jaq-json/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ categories = ["data-structures"]
1212
rust-version = "1.70"
1313

1414
[features]
15-
default = ["parse", "std"]
16-
parse = ["cbor", "json", "toml", "xml", "yaml"]
15+
default = ["formats", "std"]
16+
formats = ["cbor", "json", "toml", "xml", "yaml"]
1717
std = ["hifijson/std"]
1818

1919
cbor = ["ciborium-ll", "ciborium-io"]

jaq-json/src/formats.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use crate::funs::bome;
2+
use crate::{cbor, json, toml, xml, yaml};
3+
use crate::{Error, Val, ValR, ValX};
4+
use alloc::{boxed::Box, string::ToString, vec::Vec};
5+
use bytes::Bytes;
6+
use core::fmt;
7+
use jaq_core::box_iter::{box_once, then, BoxIter};
8+
use jaq_core::{DataT, Exn, RunPtr};
9+
use jaq_std::{v, Filter, ValT as _};
10+
11+
impl Val {
12+
fn as_bytes_owned(&self) -> Option<Bytes> {
13+
if let Self::Str(b, _) = self {
14+
Some(b.clone())
15+
} else {
16+
None
17+
}
18+
}
19+
20+
fn as_utf8_bytes_owned(&self) -> Option<Bytes> {
21+
self.is_utf8_str().then(|| self.as_bytes_owned()).flatten()
22+
}
23+
24+
fn try_as_bytes_owned(&self) -> Result<Bytes, Error> {
25+
self.as_bytes_owned()
26+
.ok_or_else(|| Error::typ(self.clone(), "string"))
27+
}
28+
29+
fn try_as_utf8_bytes_owned(&self) -> Result<Bytes, Error> {
30+
self.as_utf8_bytes_owned()
31+
.ok_or_else(|| Error::typ(self.clone(), "string"))
32+
}
33+
}
34+
35+
/// Box Map, Map Error.
36+
fn bmme<'a>(iter: BoxIter<'a, ValR>) -> BoxIter<'a, ValX> {
37+
Box::new(iter.map(|r| r.map_err(Exn::from)))
38+
}
39+
40+
fn parse_fail(i: &impl fmt::Display, fmt: &str, e: impl fmt::Display) -> Error {
41+
Error::str(format_args!("cannot parse {i} as {fmt}: {e}"))
42+
}
43+
44+
fn serialise_fail(i: &impl fmt::Display, fmt: &str, e: impl fmt::Display) -> Error {
45+
Error::str(format_args!("cannot serialise {i} as {fmt}: {e}"))
46+
}
47+
48+
self_cell::self_cell!(
49+
struct BytesValRs {
50+
owner: Bytes,
51+
52+
#[not_covariant]
53+
dependent: ValRs,
54+
}
55+
);
56+
57+
impl Iterator for BytesValRs {
58+
type Item = ValR;
59+
fn next(&mut self) -> Option<Self::Item> {
60+
self.with_dependent_mut(|_owner, iter| iter.next())
61+
}
62+
}
63+
64+
type ValRs<'a> = BoxIter<'a, ValR>;
65+
66+
fn parse_byte_str(b: Bytes, parse: impl FnOnce(&str) -> ValRs) -> ValRs<'static> {
67+
Box::new(BytesValRs::new(b, |b| {
68+
then(core::str::from_utf8(b).map_err(Error::str), parse)
69+
}))
70+
}
71+
72+
fn parse_bytes(b: Bytes, parse: impl FnOnce(&[u8]) -> ValRs) -> ValRs<'static> {
73+
Box::new(BytesValRs::new(b, |b| parse(b)))
74+
}
75+
76+
pub fn funs<D: for<'a> DataT<V<'a> = Val>>() -> Box<[Filter<RunPtr<D>>]> {
77+
Box::new([
78+
("fromjson", v(0), |cv| {
79+
bmme(then(cv.1.try_as_utf8_bytes_owned(), |s| {
80+
let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "JSON", e));
81+
parse_bytes(s, |s| Box::new(json::parse_many(s).map(fail)))
82+
}))
83+
}),
84+
("fromcbor", v(0), |cv| {
85+
bmme(then(cv.1.try_as_bytes_owned(), |s| {
86+
let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "CBOR", e));
87+
parse_bytes(s, |s| Box::new(cbor::parse_many(s).map(fail)))
88+
}))
89+
}),
90+
("fromyaml", v(0), |cv| {
91+
bmme(then(cv.1.try_as_utf8_bytes_owned(), |s| {
92+
let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "YAML", e));
93+
parse_byte_str(s, |s| Box::new(yaml::parse_many(s).map(fail)))
94+
}))
95+
}),
96+
("fromxml", v(0), |cv| {
97+
bmme(then(cv.1.try_as_utf8_bytes_owned(), |s| {
98+
let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "XML", e));
99+
parse_byte_str(s, |s| Box::new(xml::parse_many(s).map(fail)))
100+
}))
101+
}),
102+
("fromtoml", v(0), |cv| {
103+
let from_utf8 = |b| core::str::from_utf8(b).map_err(Error::str);
104+
let parse = |b| toml::parse(b).map_err(|e| parse_fail(&cv.1, "TOML", e));
105+
bome(cv.1.try_as_utf8_bytes().and_then(from_utf8).and_then(parse))
106+
}),
107+
("tojson", v(0), |cv| {
108+
let mut buf = Vec::new();
109+
json::write(&mut buf, &cv.1).unwrap();
110+
box_once(Ok(Val::from_utf8_bytes(buf)))
111+
}),
112+
("tocbor", v(0), |cv| {
113+
let mut buf = Vec::new();
114+
cbor::write(&mut buf, &cv.1).unwrap();
115+
bome(Ok(Val::byte_str(buf)))
116+
}),
117+
("toyaml", v(0), |cv| {
118+
let mut buf = Vec::new();
119+
yaml::write(&mut buf, &cv.1).unwrap();
120+
box_once(Ok(Val::from_utf8_bytes(buf)))
121+
}),
122+
("totoml", v(0), |cv| {
123+
let ser = toml::serialise(&cv.1).map_err(|e| serialise_fail(&cv.1, "TOML", e));
124+
bome(ser.map(|ser| Val::utf8_str(ser.to_string())))
125+
}),
126+
("toxml", v(0), |cv| {
127+
let ser = xml::serialise(&cv.1).map_err(|e| serialise_fail(&cv.1, "XML", e));
128+
bome(ser.map(|ser| Val::utf8_str(ser.to_string())))
129+
}),
130+
])
131+
}

jaq-json/src/funs.rs

Lines changed: 6 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
use crate::{cbor, json, toml, xml, yaml};
2-
use crate::{Error, Num, Tag, Type, Val, ValR, ValX};
1+
use crate::{Error, Num, Tag, Val, ValR, ValX};
32
use alloc::{boxed::Box, string::ToString, vec::Vec};
43
use bstr::ByteSlice;
54
use bytes::{BufMut, Bytes, BytesMut};
6-
use core::fmt;
7-
use jaq_core::box_iter::{box_once, then, BoxIter};
5+
use jaq_core::box_iter::{box_once, BoxIter};
86
use jaq_core::{DataT, Exn, Native, RunPtr};
9-
use jaq_std::{run, unary, v, Filter, ValT as _};
7+
use jaq_std::{run, unary, v, Filter};
108

119
impl Val {
1210
/// Return 0 for null, the absolute value for numbers, and
@@ -107,44 +105,17 @@ impl Val {
107105
_ => Err(self.clone()),
108106
}
109107
}
110-
111-
fn as_bytes_owned(&self) -> Option<Bytes> {
112-
if let Self::Str(b, _) = self {
113-
Some(b.clone())
114-
} else {
115-
None
116-
}
117-
}
118-
119-
fn as_utf8_bytes_owned(&self) -> Option<Bytes> {
120-
self.is_utf8_str().then(|| self.as_bytes_owned()).flatten()
121-
}
122-
123-
fn try_as_bytes_owned(&self) -> Result<Bytes, Error> {
124-
self.as_bytes_owned()
125-
.ok_or_else(|| Error::typ(self.clone(), Type::Str.as_str()))
126-
}
127-
128-
fn try_as_utf8_bytes_owned(&self) -> Result<Bytes, Error> {
129-
self.as_utf8_bytes_owned()
130-
.ok_or_else(|| Error::typ(self.clone(), Type::Str.as_str()))
131-
}
132108
}
133109

134110
/// Box Once, Map Error.
135-
fn bome<'a>(r: ValR) -> BoxIter<'a, ValX> {
111+
pub(crate) fn bome<'a>(r: ValR) -> BoxIter<'a, ValX> {
136112
box_once(r.map_err(Exn::from))
137113
}
138114

139-
/// Box Map, Map Error.
140-
fn bmme<'a>(iter: BoxIter<'a, ValR>) -> BoxIter<'a, ValX> {
141-
Box::new(iter.map(|r| r.map_err(Exn::from)))
142-
}
143-
144115
/// Functions of the standard library.
145-
#[cfg(feature = "parse")]
116+
#[cfg(feature = "formats")]
146117
pub fn funs<D: for<'a> DataT<V<'a> = Val>>() -> impl Iterator<Item = Filter<Native<D>>> {
147-
base_funs().chain(parse_funs().into_vec().into_iter().map(run))
118+
base_funs().chain(crate::formats::funs().into_vec().into_iter().map(run))
148119
}
149120

150121
/// Minimal set of filters.
@@ -154,11 +125,6 @@ pub fn base_funs<D: for<'a> DataT<V<'a> = Val>>() -> impl Iterator<Item = Filter
154125

155126
fn base<D: for<'a> DataT<V<'a> = Val>>() -> Box<[Filter<RunPtr<D>>]> {
156127
Box::new([
157-
("tojson", v(0), |cv| {
158-
let mut buf = Vec::new();
159-
json::write(&mut buf, &cv.1).unwrap();
160-
box_once(Ok(Val::from_utf8_bytes(buf)))
161-
}),
162128
("tobytes", v(0), |cv| {
163129
let pass = |b| Val::Str(b, Tag::Bytes);
164130
let fail = |v| Error::str(format_args!("cannot convert {v} to bytes"));
@@ -189,92 +155,3 @@ fn base<D: for<'a> DataT<V<'a> = Val>>() -> Box<[Filter<RunPtr<D>>]> {
189155
}),
190156
])
191157
}
192-
193-
fn parse_fail(i: &impl fmt::Display, fmt: &str, e: impl fmt::Display) -> Error {
194-
Error::str(format_args!("cannot parse {i} as {fmt}: {e}"))
195-
}
196-
197-
fn serialise_fail(i: &impl fmt::Display, fmt: &str, e: impl fmt::Display) -> Error {
198-
Error::str(format_args!("cannot serialise {i} as {fmt}: {e}"))
199-
}
200-
201-
self_cell::self_cell!(
202-
struct BytesValRs {
203-
owner: Bytes,
204-
205-
#[not_covariant]
206-
dependent: ValRs,
207-
}
208-
);
209-
210-
impl Iterator for BytesValRs {
211-
type Item = ValR;
212-
fn next(&mut self) -> Option<Self::Item> {
213-
self.with_dependent_mut(|_owner, iter| iter.next())
214-
}
215-
}
216-
217-
type ValRs<'a> = BoxIter<'a, ValR>;
218-
219-
fn parse_byte_str(b: Bytes, parse: impl FnOnce(&str) -> ValRs) -> ValRs<'static> {
220-
Box::new(BytesValRs::new(b, |b| {
221-
then(core::str::from_utf8(b).map_err(Error::str), parse)
222-
}))
223-
}
224-
225-
fn parse_bytes(b: Bytes, parse: impl FnOnce(&[u8]) -> ValRs) -> ValRs<'static> {
226-
Box::new(BytesValRs::new(b, |b| parse(b)))
227-
}
228-
229-
#[cfg(feature = "parse")]
230-
fn parse_funs<D: for<'a> DataT<V<'a> = Val>>() -> Box<[Filter<RunPtr<D>>]> {
231-
Box::new([
232-
("fromjson", v(0), |cv| {
233-
bmme(then(cv.1.try_as_utf8_bytes_owned(), |s| {
234-
let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "JSON", e));
235-
parse_bytes(s, |s| Box::new(json::parse_many(s).map(fail)))
236-
}))
237-
}),
238-
("fromcbor", v(0), |cv| {
239-
bmme(then(cv.1.try_as_bytes_owned(), |s| {
240-
let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "CBOR", e));
241-
parse_bytes(s, |s| Box::new(cbor::parse_many(s).map(fail)))
242-
}))
243-
}),
244-
("fromyaml", v(0), |cv| {
245-
bmme(then(cv.1.try_as_utf8_bytes_owned(), |s| {
246-
let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "YAML", e));
247-
parse_byte_str(s, |s| Box::new(yaml::parse_many(s).map(fail)))
248-
}))
249-
}),
250-
("fromxml", v(0), |cv| {
251-
bmme(then(cv.1.try_as_utf8_bytes_owned(), |s| {
252-
let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "XML", e));
253-
parse_byte_str(s, |s| Box::new(xml::parse_many(s).map(fail)))
254-
}))
255-
}),
256-
("fromtoml", v(0), |cv| {
257-
let from_utf8 = |b| core::str::from_utf8(b).map_err(Error::str);
258-
let parse = |b| toml::parse(b).map_err(|e| parse_fail(&cv.1, "TOML", e));
259-
bome(cv.1.try_as_utf8_bytes().and_then(from_utf8).and_then(parse))
260-
}),
261-
("tocbor", v(0), |cv| {
262-
let mut buf = Vec::new();
263-
cbor::write(&mut buf, &cv.1).unwrap();
264-
bome(Ok(Val::byte_str(buf)))
265-
}),
266-
("toyaml", v(0), |cv| {
267-
let mut buf = Vec::new();
268-
yaml::write(&mut buf, &cv.1).unwrap();
269-
box_once(Ok(Val::from_utf8_bytes(buf)))
270-
}),
271-
("totoml", v(0), |cv| {
272-
let ser = toml::serialise(&cv.1).map_err(|e| serialise_fail(&cv.1, "TOML", e));
273-
bome(ser.map(|ser| Val::utf8_str(ser.to_string())))
274-
}),
275-
("toxml", v(0), |cv| {
276-
let ser = xml::serialise(&cv.1).map_err(|e| serialise_fail(&cv.1, "XML", e));
277-
bome(ser.map(|ser| Val::utf8_str(ser.to_string())))
278-
}),
279-
])
280-
}

jaq-json/src/lib.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ extern crate alloc;
1111
#[cfg(feature = "std")]
1212
extern crate std;
1313

14+
#[cfg(feature = "formats")]
15+
mod formats;
1416
mod funs;
1517
mod num;
1618
#[macro_use]
@@ -28,7 +30,9 @@ use jaq_core::{load, ops, path, val, Exn};
2830
use num_bigint::BigInt;
2931
use num_traits::{cast::ToPrimitive, Signed};
3032

31-
pub use funs::{base_funs, funs};
33+
pub use funs::base_funs;
34+
#[cfg(feature = "formats")]
35+
pub use funs::funs;
3236
pub use num::Num;
3337

3438
#[cfg(feature = "cbor")]
@@ -93,8 +97,10 @@ enum Type {
9397
Float,
9498
/// `-"a"`, `"a" | round`
9599
Num,
100+
/*
96101
/// `{(0): 1}` or `0 | fromjson` or `0 | explode` or `"a b c" | split(0)`
97102
Str,
103+
*/
98104
/// `0 | sort` or `0 | implode` or `[] | .[0:] = 0`
99105
Arr,
100106
/// `0 | .[]` or `0 | .[0]` or `0 | keys` (array or object)
@@ -109,7 +115,7 @@ impl Type {
109115
Self::Int => "integer",
110116
Self::Float => "floating-point number",
111117
Self::Num => "number",
112-
Self::Str => "string",
118+
//Self::Str => "string",
113119
Self::Arr => "array",
114120
Self::Iter => "iterable (array or object)",
115121
Self::Range => "rangeable (array or string)",
@@ -309,6 +315,7 @@ impl jaq_core::ValT for Val {
309315
if let Self::Str(b, _tag) = self {
310316
Self::utf8_str(b)
311317
} else {
318+
// TODO: do not corrupt non-UTF-8 characters
312319
Self::utf8_str(self.to_string())
313320
}
314321
}
@@ -738,14 +745,14 @@ pub fn bstr(s: &(impl core::convert::AsRef<[u8]> + ?Sized)) -> impl fmt::Display
738745

739746
impl fmt::Display for Val {
740747
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
741-
json::format_with(f, self, |f, v| write!(f, "{v}"))
748+
write_val!(f, self, |v: &Val| v.fmt(f))
742749
}
743750
}
744751

745-
#[cfg(feature = "parse")]
752+
#[cfg(feature = "formats")]
746753
type BoxError = Box<dyn std::error::Error + Send + Sync>;
747754

748-
#[cfg(feature = "parse")]
755+
#[cfg(feature = "formats")]
749756
fn invalid_data(e: impl Into<BoxError>) -> std::io::Error {
750757
std::io::Error::new(std::io::ErrorKind::InvalidData, e)
751758
}

0 commit comments

Comments
 (0)