1use nu_errors::ShellError;
2use nu_protocol::{SpannedTypeName, TaggedDictBuilder, UntaggedValue, Value};
3use nu_source::Tag;
4
5use crate::utils::group;
6
7#[allow(clippy::type_complexity)]
8pub fn split(
9 value: &Value,
10 splitter: &Option<Box<dyn Fn(usize, &Value) -> Result<String, ShellError> + Send>>,
11 tag: impl Into<Tag>,
12) -> Result<Value, ShellError> {
13 let tag = tag.into();
14
15 let mut splits = indexmap::IndexMap::new();
16 let mut out = TaggedDictBuilder::new(&tag);
17
18 if splitter.is_none() {
19 out.insert_untagged("table", value.clone());
20 return Ok(out.into_value());
21 }
22
23 for (column, value) in value.row_entries() {
24 if !&value.is_table() {
25 return Err(ShellError::type_error(
26 "a table value",
27 value.spanned_type_name(),
28 ));
29 }
30
31 match group(value, splitter, &tag) {
32 Ok(grouped) => {
33 for (split_label, subset) in grouped.row_entries() {
34 let s = splits
35 .entry(split_label.clone())
36 .or_insert(indexmap::IndexMap::new());
37
38 if !&subset.is_table() {
39 return Err(ShellError::type_error(
40 "a table value",
41 subset.spanned_type_name(),
42 ));
43 }
44
45 s.insert(column.clone(), subset.clone());
46 }
47 }
48 Err(err) => return Err(err),
49 }
50 }
51
52 let mut out = TaggedDictBuilder::new(&tag);
53
54 for (k, v) in splits {
55 out.insert_untagged(k, UntaggedValue::row(v));
56 }
57
58 Ok(out.into_value())
59}