1use indexmap::indexmap;
2use indexmap::set::IndexSet;
3use itertools::Itertools;
4use nu_errors::{ExpectedRange, ShellError};
5use nu_protocol::{
6 ColumnPath, MaybeOwned, PathMember, Primitive, ShellTypeName, SpannedTypeName,
7 UnspannedPathMember, UntaggedValue, Value,
8};
9use nu_source::{
10 HasFallibleSpan, HasSpan, PrettyDebug, Span, Spanned, SpannedItem, Tag, Tagged, TaggedItem,
11};
12use num_traits::cast::ToPrimitive;
13
14#[cfg(feature = "dataframe")]
15use nu_protocol::dataframe::NuDataFrame;
16
17pub trait ValueExt {
18 fn into_parts(self) -> (UntaggedValue, Tag);
19 fn get_data(&self, desc: &str) -> MaybeOwned<'_, Value>;
20 fn get_data_by_key(&self, name: Spanned<&str>) -> Option<Value>;
21 fn get_data_by_member(&self, name: &PathMember) -> Result<Value, ShellError>;
22 fn get_data_by_column_path(
23 &self,
24 path: &ColumnPath,
25 callback: Box<dyn FnOnce(&Value, &PathMember, ShellError) -> ShellError>,
26 ) -> Result<Value, ShellError>;
27 fn swap_data_by_column_path(
28 &self,
29 path: &ColumnPath,
30 callback: Box<dyn FnOnce(&Value) -> Result<Value, ShellError>>,
31 ) -> Result<Value, ShellError>;
32 fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option<Value>;
33 fn insert_data_at_member(
34 &mut self,
35 member: &PathMember,
36 new_value: Value,
37 ) -> Result<(), ShellError>;
38 fn forgiving_insert_data_at_column_path(
39 &self,
40 split_path: &ColumnPath,
41 new_value: Value,
42 ) -> Result<Value, ShellError>;
43 fn insert_data_at_column_path(
44 &self,
45 split_path: &ColumnPath,
46 new_value: Value,
47 ) -> Result<Value, ShellError>;
48 fn replace_data_at_column_path(
49 &self,
50 split_path: &ColumnPath,
51 replaced_value: Value,
52 ) -> Option<Value>;
53 fn as_column_path(&self) -> Result<Tagged<ColumnPath>, ShellError>;
54 fn as_path_member(&self) -> Result<PathMember, ShellError>;
55 fn as_string(&self) -> Result<String, ShellError>;
56}
57
58impl ValueExt for Value {
59 fn into_parts(self) -> (UntaggedValue, Tag) {
60 (self.value, self.tag)
61 }
62
63 fn get_data(&self, desc: &str) -> MaybeOwned<'_, Value> {
64 get_data(self, desc)
65 }
66
67 fn get_data_by_key(&self, name: Spanned<&str>) -> Option<Value> {
68 get_data_by_key(self, name)
69 }
70
71 fn get_data_by_member(&self, name: &PathMember) -> Result<Value, ShellError> {
72 get_data_by_member(self, name)
73 }
74
75 fn get_data_by_column_path(
76 &self,
77 path: &ColumnPath,
78 get_error: Box<dyn FnOnce(&Value, &PathMember, ShellError) -> ShellError>,
79 ) -> Result<Value, ShellError> {
80 get_data_by_column_path(self, path, get_error)
81 }
82
83 fn swap_data_by_column_path(
84 &self,
85 path: &ColumnPath,
86 callback: Box<dyn FnOnce(&Value) -> Result<Value, ShellError>>,
87 ) -> Result<Value, ShellError> {
88 swap_data_by_column_path(self, path, callback)
89 }
90
91 fn insert_data_at_path(&self, path: &str, new_value: Value) -> Option<Value> {
92 insert_data_at_path(self, path, new_value)
93 }
94
95 fn insert_data_at_member(
96 &mut self,
97 member: &PathMember,
98 new_value: Value,
99 ) -> Result<(), ShellError> {
100 insert_data_at_member(self, member, new_value)
101 }
102
103 fn forgiving_insert_data_at_column_path(
104 &self,
105 split_path: &ColumnPath,
106 new_value: Value,
107 ) -> Result<Value, ShellError> {
108 forgiving_insert_data_at_column_path(self, split_path, new_value)
109 }
110
111 fn insert_data_at_column_path(
112 &self,
113 split_path: &ColumnPath,
114 new_value: Value,
115 ) -> Result<Value, ShellError> {
116 insert_data_at_column_path(self, split_path, new_value)
117 }
118
119 fn replace_data_at_column_path(
120 &self,
121 split_path: &ColumnPath,
122 replaced_value: Value,
123 ) -> Option<Value> {
124 replace_data_at_column_path(self, split_path, replaced_value)
125 }
126
127 fn as_column_path(&self) -> Result<Tagged<ColumnPath>, ShellError> {
128 as_column_path(self)
129 }
130
131 fn as_path_member(&self) -> Result<PathMember, ShellError> {
132 as_path_member(self)
133 }
134
135 fn as_string(&self) -> Result<String, ShellError> {
136 as_string(self)
137 }
138}
139
140pub fn get_data_by_member(value: &Value, name: &PathMember) -> Result<Value, ShellError> {
141 match &value.value {
142 UntaggedValue::Row(o) => match &name.unspanned {
144 UnspannedPathMember::String(string) => o
146 .get_data_by_key(string[..].spanned(name.span))
147 .ok_or_else(|| {
148 ShellError::missing_property(
149 "row".spanned(value.tag.span),
150 string.spanned(name.span),
151 )
152 }),
153
154 UnspannedPathMember::Int(_) => Err(ShellError::invalid_integer_index(
156 "row".spanned(value.tag.span),
157 name.span,
158 )),
159 },
160
161 UntaggedValue::Table(l) => {
163 match &name.unspanned {
164 UnspannedPathMember::String(string) => {
166 let mut out = vec![];
167
168 for item in l {
169 if let Value {
170 value: UntaggedValue::Row(o),
171 ..
172 } = item
173 {
174 if let Some(v) = o.get_data_by_key(string[..].spanned(name.span)) {
175 out.push(v)
176 }
177 }
178 }
179
180 if out.is_empty() {
181 Err(ShellError::missing_property(
182 "table".spanned(value.tag.span),
183 string.spanned(name.span),
184 ))
185 } else {
186 Ok(UntaggedValue::Table(out)
187 .into_value(Tag::new(value.anchor(), name.span)))
188 }
189 }
190 UnspannedPathMember::Int(int) => {
191 let index = int.to_usize().ok_or_else(|| {
192 ShellError::range_error(
193 ExpectedRange::Usize,
194 &"massive integer".spanned(name.span),
195 "indexing",
196 )
197 })?;
198
199 get_data_by_index(value, index.spanned(value.tag.span)).ok_or_else(|| {
200 ShellError::range_error(0..(l.len()), &int.spanned(name.span), "indexing")
201 })
202 }
203 }
204 }
205 #[cfg(feature = "dataframe")]
206 UntaggedValue::DataFrame(df) => match &name.unspanned {
207 UnspannedPathMember::String(string) => {
208 let column = df.as_ref().select(string.as_str()).map_err(|e| {
209 ShellError::labeled_error("Dataframe error", e.to_string(), &name.span)
210 })?;
211
212 Ok(NuDataFrame::dataframe_to_value(
213 column,
214 Tag::new(value.anchor(), name.span),
215 ))
216 }
217 UnspannedPathMember::Int(int) => {
218 if df.is_series() {
219 df.get_value(*int as usize, name.span)
220 } else {
221 Err(ShellError::labeled_error(
222 "Column not found",
223 "Column name not found in the dataframe",
224 name.span,
225 ))
226 }
227 }
228 },
229 other => Err(ShellError::type_error(
230 "row or table",
231 other.type_name().spanned(value.tag.span),
232 )),
233 }
234}
235
236pub fn get_data_by_column_path<F>(
237 value: &Value,
238 path: &ColumnPath,
239 get_error: F,
240) -> Result<Value, ShellError>
241where
242 F: FnOnce(&Value, &PathMember, ShellError) -> ShellError,
243{
244 let mut current = value.clone();
245
246 for p in path {
247 let value = get_data_by_member(¤t, p);
248
249 match value {
250 Ok(v) => current = v.clone(),
251 Err(e) => return Err(get_error(¤t, p, e)),
252 }
253 }
254
255 Ok(current)
256}
257
258pub fn swap_data_by_column_path<F>(
259 value: &Value,
260 path: &ColumnPath,
261 callback: F,
262) -> Result<Value, ShellError>
263where
264 F: FnOnce(&Value) -> Result<Value, ShellError>,
265{
266 let fields = path.clone();
267
268 let to_replace =
269 get_data_by_column_path(value, path, move |obj_source, column_path_tried, error| {
270 let path_members_span = fields.maybe_span().unwrap_or_else(Span::unknown);
271
272 match &obj_source.value {
273 UntaggedValue::Table(rows) => match column_path_tried {
274 PathMember {
275 unspanned: UnspannedPathMember::String(column),
276 ..
277 } => {
278 let primary_label = format!("There isn't a column named '{}'", &column);
279
280 let suggestions: IndexSet<_> = rows
281 .iter()
282 .filter_map(|r| {
283 nu_protocol::did_you_mean(r, column_path_tried.as_string())
284 })
285 .map(|s| s[0].to_owned())
286 .collect();
287 let mut existing_columns: IndexSet<_> = IndexSet::default();
288 let mut names: Vec<String> = vec![];
289
290 for row in rows {
291 for field in row.data_descriptors() {
292 if !existing_columns.contains(&field[..]) {
293 existing_columns.insert(field.clone());
294 names.push(field);
295 }
296 }
297 }
298
299 if names.is_empty() {
300 return ShellError::labeled_error_with_secondary(
301 "Unknown column",
302 primary_label,
303 column_path_tried.span,
304 "Appears to contain rows. Try indexing instead.",
305 column_path_tried.span.since(path_members_span),
306 );
307 } else {
308 return ShellError::labeled_error_with_secondary(
309 "Unknown column",
310 primary_label,
311 column_path_tried.span,
312 format!(
313 "Perhaps you meant '{}'? Columns available: {}",
314 suggestions
315 .iter()
316 .map(|x| x.to_owned())
317 .collect::<Vec<String>>()
318 .join(","),
319 names.join(", ")
320 ),
321 column_path_tried.span.since(path_members_span),
322 );
323 };
324 }
325 PathMember {
326 unspanned: UnspannedPathMember::Int(idx),
327 ..
328 } => {
329 let total = rows.len();
330
331 let secondary_label = if total == 1 {
332 "The table only has 1 row".to_owned()
333 } else {
334 format!("The table only has {} rows (0 to {})", total, total - 1)
335 };
336
337 return ShellError::labeled_error_with_secondary(
338 "Row not found",
339 format!("There isn't a row indexed at {}", idx),
340 column_path_tried.span,
341 secondary_label,
342 column_path_tried.span.since(path_members_span),
343 );
344 }
345 },
346 UntaggedValue::Row(columns) => match column_path_tried {
347 PathMember {
348 unspanned: UnspannedPathMember::String(column),
349 ..
350 } => {
351 let primary_label = format!("There isn't a column named '{}'", &column);
352
353 if let Some(suggestions) =
354 nu_protocol::did_you_mean(obj_source, column_path_tried.as_string())
355 {
356 return ShellError::labeled_error_with_secondary(
357 "Unknown column",
358 primary_label,
359 column_path_tried.span,
360 format!(
361 "Perhaps you meant '{}'? Columns available: {}",
362 suggestions[0],
363 &obj_source.data_descriptors().join(",")
364 ),
365 column_path_tried.span.since(path_members_span),
366 );
367 }
368 }
369 PathMember {
370 unspanned: UnspannedPathMember::Int(idx),
371 ..
372 } => {
373 return ShellError::labeled_error_with_secondary(
374 "No rows available",
375 format!("A row at '{}' can't be indexed.", &idx),
376 column_path_tried.span,
377 format!(
378 "Appears to contain columns. Columns available: {}",
379 columns.keys().join(",")
380 ),
381 column_path_tried.span.since(path_members_span),
382 )
383 }
384 },
385 _ => {}
386 }
387
388 if let Some(suggestions) =
389 nu_protocol::did_you_mean(obj_source, column_path_tried.as_string())
390 {
391 return ShellError::labeled_error(
392 "Unknown column",
393 format!("did you mean '{}'?", suggestions[0]),
394 column_path_tried.span.since(path_members_span),
395 );
396 }
397
398 error
399 });
400
401 let old_value = to_replace?;
402 let replacement = callback(&old_value)?;
403
404 value
405 .replace_data_at_column_path(path, replacement)
406 .ok_or_else(|| {
407 ShellError::labeled_error("missing column-path", "missing column-path", value.tag.span)
408 })
409}
410
411pub fn insert_data_at_path(value: &Value, path: &str, new_value: Value) -> Option<Value> {
412 let mut new_obj = value.clone();
413
414 let split_path: Vec<_> = path.split('.').collect();
415
416 if let UntaggedValue::Row(ref mut o) = new_obj.value {
417 let mut current = o;
418
419 if split_path.len() == 1 {
420 current
422 .entries
423 .insert(path.to_string(), new_value.value.into_value(&value.tag));
424 return Some(new_obj);
425 }
426
427 for idx in 0..split_path.len() {
428 match current.entries.get_mut(split_path[idx]) {
429 Some(next) => {
430 if idx == (split_path.len() - 2) {
431 if let UntaggedValue::Row(o) = &mut next.value {
432 o.entries.insert(
433 split_path[idx + 1].to_string(),
434 new_value.value.into_value(&value.tag),
435 );
436 }
437 return Some(new_obj.clone());
438 } else {
439 match next.value {
440 UntaggedValue::Row(ref mut o) => {
441 current = o;
442 }
443 _ => return None,
444 }
445 }
446 }
447 _ => return None,
448 }
449 }
450 }
451
452 None
453}
454
455pub fn insert_data_at_member(
456 value: &mut Value,
457 member: &PathMember,
458 new_value: Value,
459) -> Result<(), ShellError> {
460 match &mut value.value {
461 UntaggedValue::Row(dict) => match &member.unspanned {
462 UnspannedPathMember::String(key) => {
463 dict.insert_data_at_key(key, new_value);
464 Ok(())
465 }
466 UnspannedPathMember::Int(_) => Err(ShellError::type_error(
467 "column name",
468 "integer".spanned(member.span),
469 )),
470 },
471 UntaggedValue::Table(array) => match &member.unspanned {
472 UnspannedPathMember::String(_) => Err(ShellError::type_error(
473 "list index",
474 "string".spanned(member.span),
475 )),
476 UnspannedPathMember::Int(int) => {
477 let int = int.to_usize().ok_or_else(|| {
478 ShellError::range_error(
479 ExpectedRange::Usize,
480 &"bigger number".spanned(member.span),
481 "inserting into a list",
482 )
483 })?;
484
485 insert_data_at_index(array, int.tagged(member.span), new_value)?;
486 Ok(())
487 }
488 },
489 other => match &member.unspanned {
490 UnspannedPathMember::String(_) => Err(ShellError::type_error(
491 "row",
492 other.type_name().spanned(value.span()),
493 )),
494 UnspannedPathMember::Int(_) => Err(ShellError::type_error(
495 "table",
496 other.type_name().spanned(value.span()),
497 )),
498 },
499 }
500}
501
502pub fn missing_path_members_by_column_path(value: &Value, path: &ColumnPath) -> Option<usize> {
503 let mut current = value.clone();
504
505 for (idx, p) in path.iter().enumerate() {
506 if let Ok(value) = get_data_by_member(¤t, p) {
507 current = value;
508 } else {
509 return Some(idx);
510 }
511 }
512
513 None
514}
515
516pub fn forgiving_insert_data_at_column_path(
517 value: &Value,
518 split_path: &ColumnPath,
519 new_value: Value,
520) -> Result<Value, ShellError> {
521 let mut original = value.clone();
522
523 if let Some(missed_at) = missing_path_members_by_column_path(value, split_path) {
524 let mut paths = split_path.iter().skip(missed_at + 1).collect::<Vec<_>>();
525 paths.reverse();
526
527 let mut candidate = new_value;
528
529 for member in &paths {
530 match &member.unspanned {
531 UnspannedPathMember::String(column_name) => {
532 candidate =
533 UntaggedValue::row(indexmap! { column_name.into() => candidate.clone()})
534 .into_value(&candidate.tag)
535 }
536 UnspannedPathMember::Int(int) => {
537 let mut rows = vec![];
538 let size = int.to_usize().unwrap_or(0);
539
540 for _ in 0..=size {
541 rows.push(
542 UntaggedValue::Primitive(Primitive::Nothing).into_value(&candidate.tag),
543 );
544 }
545 rows.push(candidate.clone());
546 candidate = UntaggedValue::Table(rows).into_value(&candidate.tag);
547 }
548 }
549 }
550
551 let cp = ColumnPath::new(
552 split_path
553 .iter()
554 .cloned()
555 .take(split_path.members().len() - missed_at + 1)
556 .collect::<Vec<_>>(),
557 );
558
559 if missed_at == 0 {
560 let current: &mut Value = &mut original;
561 insert_data_at_member(current, &cp.members()[0], candidate)?;
562 return Ok(original);
563 }
564
565 if value
566 .get_data_by_column_path(&cp, Box::new(move |_, _, err| err))
567 .is_ok()
568 {
569 return insert_data_at_column_path(value, &cp, candidate);
570 } else if let Some((last, front)) = cp.split_last() {
571 let mut current: &mut Value = &mut original;
572
573 for member in front {
574 let type_name = current.spanned_type_name();
575
576 current = get_mut_data_by_member(current, member).ok_or_else(|| {
577 ShellError::missing_property(
578 member.plain_string(std::usize::MAX).spanned(member.span),
579 type_name,
580 )
581 })?
582 }
583
584 insert_data_at_member(current, last, candidate)?;
585
586 return Ok(original);
587 } else {
588 return Err(ShellError::untagged_runtime_error(
589 "Internal error: could not split column path correctly",
590 ));
591 }
592 }
593
594 insert_data_at_column_path(value, split_path, new_value)
595}
596
597pub fn insert_data_at_column_path(
598 value: &Value,
599 split_path: &ColumnPath,
600 new_value: Value,
601) -> Result<Value, ShellError> {
602 if let Some((last, front)) = split_path.split_last() {
603 let mut original = value.clone();
604
605 let mut current: &mut Value = &mut original;
606
607 for member in front {
608 let type_name = current.spanned_type_name();
609
610 current = get_mut_data_by_member(current, member).ok_or_else(|| {
611 ShellError::missing_property(
612 member.plain_string(std::usize::MAX).spanned(member.span),
613 type_name,
614 )
615 })?
616 }
617
618 insert_data_at_member(current, last, new_value)?;
619
620 Ok(original)
621 } else {
622 Err(ShellError::untagged_runtime_error(
623 "Internal error: could not split column path correctly",
624 ))
625 }
626}
627
628pub fn replace_data_at_column_path(
629 value: &Value,
630 split_path: &ColumnPath,
631 replaced_value: Value,
632) -> Option<Value> {
633 let mut new_obj: Value = value.clone();
634 let mut current = &mut new_obj;
635 let split_path = split_path.members();
636
637 for idx in 0..split_path.len() {
638 match get_mut_data_by_member(current, &split_path[idx]) {
639 Some(next) => {
640 if idx == (split_path.len() - 1) {
641 *next = replaced_value.value.into_value(&value.tag);
642 return Some(new_obj);
643 } else {
644 current = next;
645 }
646 }
647 None => {
648 return None;
649 }
650 }
651 }
652
653 None
654}
655
656pub fn as_column_path(value: &Value) -> Result<Tagged<ColumnPath>, ShellError> {
657 match &value.value {
658 UntaggedValue::Primitive(Primitive::String(s)) => {
659 let s = s.to_string().spanned(value.tag.span);
660
661 Ok(ColumnPath::build(&s).tagged(&value.tag))
662 }
663
664 UntaggedValue::Primitive(Primitive::ColumnPath(path)) => {
665 Ok(path.clone().tagged(value.tag.clone()))
666 }
667
668 other => Err(ShellError::type_error(
669 "column path",
670 other.type_name().spanned(value.span()),
671 )),
672 }
673}
674
675pub fn as_path_member(value: &Value) -> Result<PathMember, ShellError> {
676 match &value.value {
677 UntaggedValue::Primitive(primitive) => match primitive {
678 Primitive::Int(int) => Ok(PathMember::int(*int, value.tag.span)),
679 Primitive::String(string) => Ok(PathMember::string(string, value.tag.span)),
680 other => Err(ShellError::type_error(
681 "path member",
682 other.type_name().spanned(value.span()),
683 )),
684 },
685 other => Err(ShellError::type_error(
686 "path member",
687 other.type_name().spanned(value.span()),
688 )),
689 }
690}
691
692pub fn as_string(value: &Value) -> Result<String, ShellError> {
693 match &value.value {
694 UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()),
695 UntaggedValue::Primitive(Primitive::Date(dt)) => Ok(dt.format("%Y-%m-%d").to_string()),
696 UntaggedValue::Primitive(Primitive::Boolean(x)) => Ok(x.to_string()),
697 UntaggedValue::Primitive(Primitive::Decimal(x)) => Ok(x.to_string()),
698 UntaggedValue::Primitive(Primitive::Int(x)) => Ok(x.to_string()),
699 UntaggedValue::Primitive(Primitive::Filesize(x)) => Ok(x.to_string()),
700 UntaggedValue::Primitive(Primitive::FilePath(x)) => Ok(x.display().to_string()),
701 UntaggedValue::Primitive(Primitive::BigInt(x)) => Ok(x.to_string()),
702 UntaggedValue::Primitive(Primitive::ColumnPath(path)) => Ok(path
703 .iter()
704 .map(|member| match &member.unspanned {
705 UnspannedPathMember::String(name) => name.to_string(),
706 UnspannedPathMember::Int(n) => n.to_string(),
707 })
708 .join(".")),
709
710 other => Err(ShellError::labeled_error(
712 "Expected string",
713 other.type_name(),
714 &value.tag,
715 )),
716 }
717}
718
719fn insert_data_at_index(
720 list: &mut Vec<Value>,
721 index: Tagged<usize>,
722 new_value: Value,
723) -> Result<(), ShellError> {
724 if index.item >= list.len() {
725 if index.item == list.len() {
726 list.push(new_value);
727 return Ok(());
728 }
729
730 let mut idx = list.len();
731
732 loop {
733 list.push(UntaggedValue::Primitive(Primitive::Nothing).into_value(&new_value.tag));
734
735 idx += 1;
736
737 if idx == index.item {
738 list.push(new_value);
739 return Ok(());
740 }
741 }
742 } else {
743 list[index.item] = new_value;
744 Ok(())
745 }
746}
747
748pub fn get_data<'value>(value: &'value Value, desc: &str) -> MaybeOwned<'value, Value> {
749 match &value.value {
750 UntaggedValue::Primitive(_) => MaybeOwned::Borrowed(value),
751 UntaggedValue::Row(o) => o.get_data(desc),
752 UntaggedValue::Block(_) | UntaggedValue::Table(_) | UntaggedValue::Error(_) => {
753 MaybeOwned::Owned(UntaggedValue::nothing().into_untagged_value())
754 }
755 #[cfg(feature = "dataframe")]
756 UntaggedValue::DataFrame(_) | UntaggedValue::FrameStruct(_) => {
757 MaybeOwned::Owned(UntaggedValue::nothing().into_untagged_value())
758 }
759 }
760}
761
762pub(crate) fn get_data_by_index(value: &Value, idx: Spanned<usize>) -> Option<Value> {
763 match &value.value {
764 UntaggedValue::Table(value_set) => {
765 let value = value_set.get(idx.item)?;
766 Some(
767 value
768 .value
769 .clone()
770 .into_value(Tag::new(value.anchor(), idx.span)),
771 )
772 }
773 _ => None,
774 }
775}
776
777pub fn get_data_by_key(value: &Value, name: Spanned<&str>) -> Option<Value> {
778 match &value.value {
779 UntaggedValue::Row(o) => o.get_data_by_key(name),
780 UntaggedValue::Table(l) => {
781 let mut out = vec![];
782 for item in l {
783 match item {
784 Value {
785 value: UntaggedValue::Row(o),
786 ..
787 } => match o.get_data_by_key(name) {
788 Some(v) => out.push(v),
789 None => out.push(UntaggedValue::nothing().into_untagged_value()),
790 },
791 _ => out.push(UntaggedValue::nothing().into_untagged_value()),
792 }
793 }
794
795 if !out.is_empty() {
796 Some(UntaggedValue::Table(out).into_value(name.span))
797 } else {
798 None
799 }
800 }
801 _ => None,
802 }
803}
804
805pub(crate) fn get_mut_data_by_member<'value>(
806 value: &'value mut Value,
807 name: &PathMember,
808) -> Option<&'value mut Value> {
809 match &mut value.value {
810 UntaggedValue::Row(o) => match &name.unspanned {
811 UnspannedPathMember::String(string) => o.get_mut_data_by_key(string),
812 UnspannedPathMember::Int(_) => None,
813 },
814 UntaggedValue::Table(l) => match &name.unspanned {
815 UnspannedPathMember::String(string) => {
816 for item in l {
817 if let Value {
818 value: UntaggedValue::Row(o),
819 ..
820 } = item
821 {
822 if let Some(v) = o.get_mut_data_by_key(string) {
823 return Some(v);
824 }
825 }
826 }
827 None
828 }
829 UnspannedPathMember::Int(int) => {
830 let index = int.to_usize()?;
831 l.get_mut(index)
832 }
833 },
834 _ => None,
835 }
836}