Skip to content

Commit 6cfb972

Browse files
committed
impl map_index
1 parent 1917755 commit 6cfb972

File tree

5 files changed

+63
-11
lines changed

5 files changed

+63
-11
lines changed

tailcall-template/src/jq/jq.rs

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,8 @@ where
3636

3737
fn from_map<I: IntoIterator<Item = (Self, Self)>>(iter: I) -> ValR<Self> {
3838
iter.into_iter().fold(ValR::Ok(Self(JsonLike::object(JsonObjectLike::new()))), |acc, (key, value)| {
39-
let key = match JsonLike::as_str(&key.0) {
40-
Some(key) => key,
41-
None => return ValR::Err(jaq_core::Error::str("Key cannot be converted to String")),
39+
let Some(key) = JsonLike::as_str(&key.0) else {
40+
return ValR::Err(jaq_core::Error::str("Key cannot be converted to String"))
4241
};
4342

4443
match acc {
@@ -58,19 +57,17 @@ where
5857

5958
fn index(self, index: &Self) -> ValR<Self> {
6059
if let Some(obj) = self.0.as_object() {
61-
let key = match index.0.as_str() {
62-
Some(key) => key,
63-
None => return ValR::Err(jaq_core::Error::str("Key cannot be converted to String"))
60+
let Some(key) = index.0.as_str() else {
61+
return ValR::Err(jaq_core::Error::str("Key cannot be converted to String"))
6462
};
6563

6664
match obj.get_key(key) {
6765
Some(item) => ValR::Ok(JsonLikeHelper(item.clone())),
6866
None => ValR::Ok(JsonLikeHelper(JsonLike::null())),
6967
}
7068
} else if let Some(arr) = self.0.as_array() {
71-
let index: u64 = match index.0.as_u64() {
72-
Some(item) => item,
73-
None => return ValR::Err(jaq_core::Error::str("Index cannot be converted to u64"))
69+
let Some(index) = index.0.as_u64() else {
70+
return ValR::Err(jaq_core::Error::str("Index cannot be converted to u64"))
7471
};
7572

7673
match arr.get(index as usize) {
@@ -134,12 +131,53 @@ where
134131
}
135132

136133
fn map_index<'a, I: Iterator<Item = jaq_core::ValX<'a, Self>>>(
137-
self,
134+
mut self,
138135
index: &Self,
139136
opt: jaq_core::path::Opt,
140137
f: impl Fn(Self) -> I,
141138
) -> jaq_core::ValX<'a, Self> {
142-
todo!()
139+
if let Some(obj) = self.0.as_object_mut() {
140+
let Some(key) = index.0.as_str() else {
141+
return opt.fail(self, |_v| jaq_core::Exn::from(jaq_core::Error::str("Key cannot be converted to String")))
142+
};
143+
144+
match obj.get_key(key) {
145+
Some(e) => {
146+
match f(JsonLikeHelper(e.clone())).next().transpose()? {
147+
Some(value) => obj.insert_key(key, value.0),
148+
None => {obj.remove_key(key);},
149+
}
150+
},
151+
None => {
152+
if let Some(value) = f(JsonLikeHelper(JsonLike::null())).next().transpose()? {
153+
obj.insert_key(key, value.0);
154+
}
155+
},
156+
}
157+
Ok(self)
158+
} else if let Some(arr) = self.0.as_array_mut() {
159+
let Some(index) = index.0.as_u64() else {
160+
return opt.fail(self, |_v| jaq_core::Exn::from(jaq_core::Error::str("Index cannot be converted to u64")))
161+
};
162+
let abs_or = |i| {
163+
abs_index(i, arr.len()).ok_or(jaq_core::Error::str(format!("index {i} out of bounds")))
164+
};
165+
// TODO: perform error handling
166+
let index = match abs_or(index.try_into().unwrap()) {
167+
Ok(index) => index,
168+
Err(e) => return opt.fail(self, |_v| jaq_core::Exn::from(e)),
169+
};
170+
171+
let item = arr[index].clone();
172+
if let Some(value) = f(JsonLikeHelper(item)).next().transpose()? {
173+
arr[index] = value.0;
174+
} else {
175+
arr.remove(index);
176+
}
177+
Ok(self)
178+
} else {
179+
return opt.fail(self, |_v| jaq_core::Exn::from(jaq_core::Error::str("Value is not object or array")))
180+
}
143181
}
144182

145183
fn map_range<'a, I: Iterator<Item = jaq_core::ValX<'a, Self>>>(

tailcall-template/src/jsonlike/borrow.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ impl<'ctx> JsonObjectLike<'ctx> for ObjectAsVec<'ctx> {
2424
fn insert_key(&mut self, key: &'ctx str, value: Self::Value) {
2525
self.insert(key, value);
2626
}
27+
28+
fn remove_key(&mut self, _key: &'ctx str) -> Option<Self::Value> {
29+
// TODO: implement it
30+
unimplemented!()
31+
}
2732
}
2833

2934
impl<'ctx> JsonLike<'ctx> for Value<'ctx> {

tailcall-template/src/jsonlike/graphql.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ impl<'obj, Value: JsonLike<'obj> + Clone> JsonObjectLike<'obj> for IndexMap<Name
2525
fn insert_key(&mut self, key: &'obj str, value: Self::Value) {
2626
self.insert(Name::new(key), value);
2727
}
28+
29+
fn remove_key(&mut self, key: &'obj str) -> Option<Self::Value> {
30+
self.swap_remove(key)
31+
}
2832
}
2933

3034
impl<'json> JsonLike<'json> for ConstValue {

tailcall-template/src/jsonlike/json_like.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub trait JsonObjectLike<'obj>: Sized {
4141
fn with_capacity(n: usize) -> Self;
4242
fn get_key(&self, key: &str) -> Option<&Self::Value>;
4343
fn insert_key(&mut self, key: &'obj str, value: Self::Value);
44+
fn remove_key(&mut self, key: &'obj str) -> Option<Self::Value>;
4445
}
4546

4647
#[cfg(test)]

tailcall-template/src/jsonlike/serde.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ impl<'obj> JsonObjectLike<'obj> for serde_json::Map<String, serde_json::Value> {
2323
fn insert_key(&mut self, key: &'obj str, value: Self::Value) {
2424
self.insert(key.to_owned(), value);
2525
}
26+
27+
fn remove_key(&mut self, key: &'obj str) -> Option<Self::Value> {
28+
self.remove(key)
29+
}
2630
}
2731

2832
impl<'json> JsonLike<'json> for serde_json::Value {

0 commit comments

Comments
 (0)