jaq_json/
funs.rs

1use crate::{read, Error, Num, Tag, Val, ValR, ValX};
2use alloc::{boxed::Box, vec::Vec};
3use bstr::ByteSlice;
4use bytes::{BufMut, Bytes, BytesMut};
5use core::fmt;
6use jaq_core::box_iter::{then, BoxIter};
7use jaq_core::{DataT, Exn, Native, RunPtr};
8use jaq_std::{bome, run, unary, v, Filter, ValT as _};
9
10impl Val {
11    /// Return 0 for null, the absolute value for numbers, and
12    /// the length for strings, arrays, and objects.
13    ///
14    /// Fail on booleans.
15    fn length(&self) -> ValR {
16        match self {
17            Val::Null => Ok(Val::from(0usize)),
18            Val::Num(n) => Ok(Val::Num(n.length())),
19            Val::Str(s, Tag::Utf8) => Ok(Val::from(s.chars().count() as isize)),
20            Val::Str(b, Tag::Bytes) => Ok(Val::from(b.len() as isize)),
21            Val::Arr(a) => Ok(Val::from(a.len() as isize)),
22            Val::Obj(o) => Ok(Val::from(o.len() as isize)),
23            Val::Bool(_) => Err(Error::str(format_args!("{self} has no length"))),
24        }
25    }
26
27    /// Return the indices of `y` in `self`.
28    fn indices<'a>(&'a self, y: &'a Val) -> Result<Box<dyn Iterator<Item = usize> + 'a>, Error> {
29        match (self, y) {
30            (Val::Str(_, tag @ (Tag::Bytes | Tag::Utf8)), Val::Str(y, tag_))
31                if tag == tag_ && y.is_empty() =>
32            {
33                Ok(Box::new(core::iter::empty()))
34            }
35            (Val::Arr(_), Val::Arr(y)) if y.is_empty() => Ok(Box::new(core::iter::empty())),
36            (Val::Str(x, Tag::Utf8), Val::Str(y, Tag::Utf8)) => {
37                let index = |(i, _, _)| x.get(i..i + y.len());
38                let iw = x.char_indices().map_while(index).enumerate();
39                Ok(Box::new(iw.filter_map(|(i, w)| (w == *y).then_some(i))))
40            }
41            (Val::Str(x, tag @ Tag::Bytes), Val::Str(y, tag_)) if tag == tag_ => {
42                let iw = x.windows(y.len()).enumerate();
43                Ok(Box::new(iw.filter_map(|(i, w)| (w == *y).then_some(i))))
44            }
45            (Val::Arr(x), Val::Arr(y)) => {
46                let iw = x.windows(y.len()).enumerate();
47                Ok(Box::new(iw.filter_map(|(i, w)| (w == **y).then_some(i))))
48            }
49            (Val::Arr(x), y) => {
50                let ix = x.iter().enumerate();
51                Ok(Box::new(ix.filter_map(move |(i, x)| (x == y).then_some(i))))
52            }
53            (x, y) => Err(Error::index(x.clone(), y.clone())),
54        }
55    }
56
57    /// Return true if `value | .[key]` is defined.
58    ///
59    /// Fail on values that are neither binaries, arrays nor objects.
60    fn has(&self, key: &Self) -> Result<bool, Error> {
61        match (self, key) {
62            (Self::Str(a, Tag::Bytes), Self::Num(Num::Int(i))) if *i >= 0 => {
63                Ok((*i as usize) < a.len())
64            }
65            (Self::Arr(a), Self::Num(Num::Int(i))) if *i >= 0 => Ok((*i as usize) < a.len()),
66            (a @ (Self::Str(_, Tag::Bytes) | Self::Arr(_)), Self::Num(Num::BigInt(i))) => {
67                a.has(&Self::from(crate::bigint_to_int_saturated(i)))
68            }
69            (Self::Obj(o), k) => Ok(o.contains_key(k)),
70            _ => Err(Error::index(self.clone(), key.clone())),
71        }
72    }
73
74    /// `a` contains `b` iff either
75    /// * the string `b` is a substring of `a`,
76    /// * every element in the array `b` is contained in some element of the array `a`,
77    /// * for every key-value pair `k, v` in `b`,
78    ///   there is a key-value pair `k, v'` in `a` such that `v'` contains `v`, or
79    /// * `a` equals `b`.
80    fn contains(&self, other: &Self) -> bool {
81        match (self, other) {
82            (Self::Str(l, tag), Self::Str(r, tag_)) if tag == tag_ => l.contains_str(r),
83            (Self::Arr(l), Self::Arr(r)) => r.iter().all(|r| l.iter().any(|l| l.contains(r))),
84            (Self::Obj(l), Self::Obj(r)) => r
85                .iter()
86                .all(|(k, r)| l.get(k).is_some_and(|l| l.contains(r))),
87            _ => self == other,
88        }
89    }
90
91    fn to_bytes(&self) -> Result<Bytes, Self> {
92        match self {
93            Val::Num(n) => n
94                .as_isize()
95                .and_then(|i| u8::try_from(i).ok())
96                .map(|u| Bytes::from(Vec::from([u])))
97                .ok_or_else(|| self.clone()),
98            Val::Str(b, _) => Ok(b.clone()),
99            Val::Arr(a) => {
100                let mut buf = BytesMut::new();
101                for x in a.iter() {
102                    buf.put(Val::to_bytes(x)?);
103                }
104                Ok(buf.into())
105            }
106            _ => Err(self.clone()),
107        }
108    }
109
110    fn as_bytes_owned(&self) -> Option<Bytes> {
111        if let Self::Str(b, _) = self {
112            Some(b.clone())
113        } else {
114            None
115        }
116    }
117
118    fn as_utf8_bytes_owned(&self) -> Option<Bytes> {
119        self.is_utf8_str().then(|| self.as_bytes_owned()).flatten()
120    }
121
122    /// Return bytes if the value is a (byte or text) string.
123    pub fn try_as_bytes_owned(&self) -> Result<Bytes, Error> {
124        self.as_bytes_owned()
125            .ok_or_else(|| Error::typ(self.clone(), "string"))
126    }
127
128    /// Return bytes if the value is a text string.
129    pub fn try_as_utf8_bytes_owned(&self) -> Result<Bytes, Error> {
130        self.as_utf8_bytes_owned()
131            .ok_or_else(|| Error::typ(self.clone(), "string"))
132    }
133}
134
135/// Box Map, Map Error.
136fn bmme<'a>(iter: BoxIter<'a, ValR>) -> BoxIter<'a, ValX> {
137    Box::new(iter.map(|r| r.map_err(Exn::from)))
138}
139
140fn parse_fail(i: &impl fmt::Display, fmt: &str, e: impl fmt::Display) -> Error {
141    Error::str(format_args!("cannot parse {i} as {fmt}: {e}"))
142}
143
144self_cell::self_cell!(
145    struct BytesValRs {
146        owner: Bytes,
147
148        #[not_covariant]
149        dependent: ValRs,
150    }
151);
152
153impl Iterator for BytesValRs {
154    type Item = ValR;
155    fn next(&mut self) -> Option<Self::Item> {
156        self.with_dependent_mut(|_owner, iter| iter.next())
157    }
158}
159
160type ValRs<'a> = BoxIter<'a, ValR>;
161
162/// Apply a function to bytes and yield the resulting value results.
163pub fn bytes_valrs(b: Bytes, f: impl FnOnce(&[u8]) -> ValRs) -> ValRs<'static> {
164    Box::new(BytesValRs::new(b, |b| f(b)))
165}
166
167/// Functions of the standard library.
168pub fn funs<D: for<'a> DataT<V<'a> = Val>>() -> impl Iterator<Item = Filter<Native<D>>> {
169    base().into_vec().into_iter().map(run)
170}
171
172fn base<D: for<'a> DataT<V<'a> = Val>>() -> Box<[Filter<RunPtr<D>>]> {
173    Box::new([
174        ("fromjson", v(0), |cv| {
175            bmme(then(cv.1.try_as_utf8_bytes_owned(), |s| {
176                let fail = move |r: Result<_, _>| r.map_err(|e| parse_fail(&cv.1, "JSON", e));
177                bytes_valrs(s, |s| Box::new(read::parse_many(s).map(fail)))
178            }))
179        }),
180        ("tojson", v(0), |cv| bome(Ok(Val::utf8_str(cv.1.to_json())))),
181        ("tobytes", v(0), |cv| {
182            let pass = |b| Val::Str(b, Tag::Bytes);
183            let fail = |v| Error::str(format_args!("cannot convert {v} to bytes"));
184            bome(cv.1.to_bytes().map(pass).map_err(fail))
185        }),
186        ("length", v(0), |cv| bome(cv.1.length())),
187        ("contains", v(1), |cv| {
188            unary(cv, |x, y| Ok(Val::from(x.contains(&y))))
189        }),
190        ("has", v(1), |cv| unary(cv, |v, k| v.has(&k).map(Val::from))),
191        ("indices", v(1), |cv| {
192            let to_int = |i: usize| Val::from(i as isize);
193            unary(cv, move |x, v| {
194                x.indices(&v).map(|idxs| idxs.map(to_int).collect())
195            })
196        }),
197        ("bsearch", v(1), |cv| {
198            let to_idx = |r: Result<_, _>| r.map_or_else(|i| -1 - i as isize, |i| i as isize);
199            unary(cv, move |a, x| {
200                a.as_arr().map(|a| Val::from(to_idx(a.binary_search(&x))))
201            })
202        }),
203    ])
204}