Skip to content

Commit 616eeb8

Browse files
committed
Implement more jaq
1 parent 863276a commit 616eeb8

2 files changed

Lines changed: 112 additions & 25 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ hex = "0.4"
1616
clap = { version = "4.5", features = ["derive"] }
1717
simple_logger = { version = "5.0", features = ["stderr"], optional = true }
1818
serde = { version = "1.0.219", features = ["derive"], optional = true }
19-
jaq-all = { git = "https://github.com/01mf02/jaq", tag = "v3.0.0", version = "0.1.0-beta", optional = true }
20-
# FIXME: remove this after jaq support is complete
21-
fn_name = "0.1.0"
19+
jaq-all = { version = "0.1.0-beta", optional = true }
2220

2321
[dev-dependencies]
2422
assert_cmd = "2.0"

src/jaq.rs

Lines changed: 111 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::{cmp::Ordering, collections::BTreeMap, ops::{Add, Div, Mul, Neg, Rem, Sub}};
1+
use std::{cmp::Ordering, collections::{BTreeMap, btree_map::Entry}, ops::{Add, Div, Mul, Neg, Rem, Sub}};
22

3-
use jaq_all::jaq_core::{Error, ops};
3+
use jaq_all::jaq_core::{Error, Exn, ops};
44

55
use crate::{RpcValue, Value};
66

@@ -157,23 +157,38 @@ impl jaq_all::jaq_std::ValT for RpcValue {
157157
}
158158

159159
fn as_f64(&self) -> Option<f64> {
160-
todo!("{}", fn_name::uninstantiated!());
160+
if let Value::Double(double) = self.value {
161+
Some(double)
162+
} else {
163+
None
164+
}
161165
}
162166

163167
fn is_utf8_str(&self) -> bool {
164-
todo!("{}", fn_name::uninstantiated!());
168+
self.is_string()
165169
}
166170

167171
fn as_bytes(&self) -> Option<&[u8]> {
168-
todo!("{}", fn_name::uninstantiated!());
172+
if let Value::String(str) = &self.value {
173+
Some(str.as_bytes())
174+
} else {
175+
None
176+
}
169177
}
170178

171-
fn as_sub_str(&self, _sub: &[u8]) -> Self {
172-
todo!("{}", fn_name::uninstantiated!());
179+
fn as_sub_str(&self, sub: &[u8]) -> Self {
180+
if matches!(&self.value, Value::String(_)) {
181+
// We do not have any fancy bytes handling, so we will just believe that the sub range
182+
// is a substring of self, and create a string out of it.
183+
String::from_utf8_lossy(sub).to_string().into()
184+
} else {
185+
// jaq-json panics here, but I don't really like that, so if self is not a String, let's just give null.
186+
RpcValue::null()
187+
}
173188
}
174189

175-
fn from_utf8_bytes(_b: impl AsRef<[u8]> + Send + 'static) -> Self {
176-
todo!("{}", fn_name::uninstantiated!());
190+
fn from_utf8_bytes(b: impl AsRef<[u8]> + Send + 'static) -> Self {
191+
String::from_utf8_lossy(b.as_ref()).to_string().into()
177192
}
178193
}
179194

@@ -241,34 +256,108 @@ impl jaq_all::jaq_core::ValT for RpcValue {
241256
}
242257
}
243258

244-
fn range(self, _range: jaq_all::jaq_core::val::Range<&Self>) -> ValR {
245-
todo!("{}", fn_name::uninstantiated!());
259+
fn range(self, range: jaq_all::jaq_core::val::Range<&Self>) -> ValR {
260+
let start = range.start.map_or(0, RpcValue::as_usize);
261+
let end = range.end.map_or(0, RpcValue::as_usize);
262+
match &self.value {
263+
Value::String(str) => {
264+
let bytes = str.as_bytes();
265+
bytes.get(start..end).map(|bytes| String::from_utf8_lossy(bytes).to_string().into()).ok_or_else(|| Error::typ(self, ".."))
266+
}
267+
Value::List(lst) => {
268+
lst
269+
.get(start..end)
270+
.map(|new_range| new_range.to_vec().into())
271+
.ok_or_else(|| Error::typ(self, ".."))
272+
}
273+
_ => Err(Error::typ(self, "")),
274+
}
246275
}
247276

248-
fn map_values<'a, I: Iterator<Item = ValX<'a>>>(
249-
self,
250-
_opt: jaq_all::jaq_core::path::Opt,
251-
_f: impl Fn(Self) -> I,
277+
fn map_values<'a, I: Iterator<Item = ValX<'a>>>(self, opt: jaq_all::jaq_core::path::Opt, f: impl Fn(Self) -> I,
252278
) -> ValX<'a> {
253-
todo!("{}", fn_name::uninstantiated!());
279+
match self.value {
280+
Value::List(lst) => {
281+
lst
282+
.into_iter()
283+
.flat_map(f)
284+
.collect::<Result<Vec<_>,_>>()
285+
.map(Into::into)
286+
}
287+
Value::Map(map) => {
288+
map
289+
.into_iter()
290+
.filter_map(|(k, v)| f(v)
291+
.next()
292+
.map(|v| Ok((k, v?))))
293+
.collect::<Result<BTreeMap<_,_>,_>>()
294+
.map(Into::into)
295+
}
296+
v => opt.fail(RpcValue { meta: None, value: v }, |v| jaq_all::jaq_core::Exn::from(Error::typ(v, ""))),
297+
}
254298
}
255299

256300
fn map_index<'a, I: Iterator<Item = ValX<'a>>>(
257301
self,
258-
_index: &Self,
259-
_opt: jaq_all::jaq_core::path::Opt,
260-
_f: impl Fn(Self) -> I,
302+
index: &Self,
303+
opt: jaq_all::jaq_core::path::Opt,
304+
f: impl Fn(Self) -> I,
261305
) -> ValX<'a> {
262-
todo!("{}", fn_name::uninstantiated!());
306+
if let (Value::String(..) | Value::List(..), Value::Map(o)) = (&self.value, &index.value) {
307+
let range = o.get("start")..o.get("end");
308+
return self.map_range(range, opt, f);
309+
}
310+
match self.value {
311+
Value::Map(map) => {
312+
let mut map = *map;
313+
let Value::String(index) = &index.value else {
314+
return opt.fail(RpcValue { meta: None, value: index.value.clone() }, |v| jaq_all::jaq_core::Exn::from(Error::typ(v, "")))
315+
};
316+
match map.entry(index.to_string()) {
317+
Entry::Occupied(mut e) => {
318+
let v = e.get_mut();
319+
match f(v.clone()).next().transpose()? {
320+
Some(y) => e.insert(y),
321+
None => e.remove(),
322+
};
323+
},
324+
Entry::Vacant(e) => {
325+
if let Some(y) = f(RpcValue::null()).next().transpose()? {
326+
e.insert(y);
327+
}
328+
},
329+
}
330+
Ok(map.into())
331+
},
332+
#[expect(clippy::cast_possible_truncation, reason = "For now, we hope that usizes are 64-bit")]
333+
Value::List(lst) => {
334+
let mut lst = *lst;
335+
let Value::UInt(index) = &index.value else {
336+
return opt.fail(RpcValue { meta: None, value: index.value.clone() }, |v| jaq_all::jaq_core::Exn::from(Error::typ(v, "")))
337+
};
338+
let Some(x) = lst.get(*index as usize) else {
339+
return opt.fail(lst.into(), |oof| Exn::from(Error::typ(oof, "")));
340+
};
341+
342+
if let Some(y) = f(x.clone()).next().transpose()? {
343+
lst.insert(*index as usize, y);
344+
} else {
345+
lst.remove(*index as usize);
346+
}
347+
348+
Ok(lst.into())
349+
},
350+
v => opt.fail(RpcValue { meta: None, value: v }, |v| jaq_all::jaq_core::Exn::from(Error::typ(v, ""))),
351+
}
263352
}
264353

265354
fn map_range<'a, I: Iterator<Item = ValX<'a>>>(
266355
self,
267356
_range: jaq_all::jaq_core::val::Range<&Self>,
268-
_opt: jaq_all::jaq_core::path::Opt,
357+
opt: jaq_all::jaq_core::path::Opt,
269358
_f: impl Fn(Self) -> I,
270359
) -> ValX<'a> {
271-
todo!("{}", fn_name::uninstantiated!());
360+
opt.fail(RpcValue { meta: None, value: self.value }, |v| jaq_all::jaq_core::Exn::from(Error::typ(v, "")))
272361
}
273362

274363
fn as_bool(&self) -> bool {

0 commit comments

Comments
 (0)