nu_protocol/value/custom_value.rs
1use crate::ast::PathMember;
2use crate::shell_error::generic::GenericError;
3use crate::value::CellPathMutation;
4use crate::{ShellError, Span, Spanned, Type, Value, ast::Operator, casing::Casing};
5use std::any::Any;
6use std::{cmp::Ordering, fmt, path::Path};
7
8/// Trait definition for a custom [`Value`](crate::Value) type
9#[typetag::serde(tag = "type")]
10pub trait CustomValue: fmt::Debug + Send + Sync + Any {
11 /// Custom `Clone` implementation
12 ///
13 /// This can reemit a `Value::Custom(Self, span)` or materialize another representation
14 /// if necessary.
15 fn clone_value(&self, span: Span) -> Value;
16
17 //fn category(&self) -> Category;
18
19 /// The friendly type name to show for the custom value, e.g. in `describe` and in error
20 /// messages. This does not have to be the same as the name of the struct or enum, but
21 /// conventionally often is.
22 fn type_name(&self) -> String;
23
24 /// Converts the custom value to a base nushell value.
25 ///
26 /// This imposes the requirement that you can represent the custom value in some form using the
27 /// Value representations that already exist in nushell
28 fn to_base_value(&self, span: Span) -> Result<Value, ShellError>;
29
30 /// Any representation used to downcast object to its original type
31 fn as_any(&self) -> &dyn std::any::Any;
32
33 /// Any representation used to downcast object to its original type (mutable reference)
34 fn as_mut_any(&mut self) -> &mut dyn std::any::Any;
35
36 /// Follow cell path by numeric index (e.g. rows).
37 ///
38 /// Let `$val` be the custom value then these are the fields passed to this method:
39 /// ```text
40 /// ╭── index [path_span]
41 /// ┴
42 /// $val.0?
43 /// ──┬─ ┬
44 /// │ ╰── optional, `true` if present
45 /// ╰── self [self_span]
46 /// ```
47 fn follow_path_int(
48 &self,
49 self_span: Span,
50 index: usize,
51 path_span: Span,
52 optional: bool,
53 ) -> Result<Value, ShellError> {
54 let _ = (self_span, index, optional);
55 Err(ShellError::IncompatiblePathAccess {
56 type_name: self.type_name(),
57 span: path_span,
58 })
59 }
60
61 /// Follow cell path by string key (e.g. columns).
62 ///
63 /// Let `$val` be the custom value then these are the fields passed to this method:
64 /// ```text
65 /// ╭── column_name [path_span]
66 /// │ ╭── casing, `Casing::Insensitive` if present
67 /// ───┴── ┴
68 /// $val.column?!
69 /// ──┬─ ┬
70 /// │ ╰── optional, `true` if present
71 /// ╰── self [self_span]
72 /// ```
73 fn follow_path_string(
74 &self,
75 self_span: Span,
76 column_name: String,
77 path_span: Span,
78 optional: bool,
79 casing: Casing,
80 ) -> Result<Value, ShellError> {
81 let _ = (self_span, column_name, optional, casing);
82 Err(ShellError::IncompatiblePathAccess {
83 type_name: self.type_name(),
84 span: path_span,
85 })
86 }
87
88 /// Update a value at the given cell path, returning a new `Value`.
89 ///
90 /// The default implementation converts to a base value, performs the mutation,
91 /// and returns the base value (losing the custom value wrapper). Override this
92 /// to preserve the custom value type through mutations.
93 fn update_data_at_cell_path(
94 &self,
95 cell_path: &[PathMember],
96 new_val: Value,
97 action: &CellPathMutation,
98 head: Span,
99 ) -> Result<Value, ShellError> {
100 let mut base = self.to_base_value(head)?;
101 base.mutate_data_at_cell_path(cell_path, new_val, action)?;
102 Ok(base)
103 }
104
105 /// ordering with other value (see [`std::cmp::PartialOrd`])
106 fn partial_cmp(&self, _other: &Value) -> Option<Ordering> {
107 None
108 }
109
110 /// Definition of an operation between the object that implements the trait
111 /// and another Value.
112 ///
113 /// The Operator enum is used to indicate the expected operation.
114 ///
115 /// Default impl raises [`ShellError::OperatorUnsupportedType`].
116 fn operation(
117 &self,
118 lhs_span: Span,
119 operator: Operator,
120 op: Span,
121 right: &Value,
122 ) -> Result<Value, ShellError> {
123 let _ = (lhs_span, right);
124 Err(ShellError::OperatorUnsupportedType {
125 op: operator,
126 unsupported: Type::Custom(self.type_name().into()),
127 op_span: op,
128 unsupported_span: lhs_span,
129 help: None,
130 })
131 }
132
133 /// Save custom value to disk.
134 ///
135 /// This method is used in `save` to save a custom value to disk.
136 /// This is done before opening any file, so saving can be handled differently.
137 ///
138 /// The default impl just returns an error.
139 fn save(
140 &self,
141 path: Spanned<&Path>,
142 value_span: Span,
143 save_span: Span,
144 ) -> Result<(), ShellError> {
145 let _ = path;
146 Err(ShellError::Generic(
147 GenericError::new(
148 "Cannot save custom value",
149 format!("Saving custom value {} failed", self.type_name()),
150 save_span,
151 )
152 .with_inner([ShellError::Generic(
153 GenericError::new(
154 "Custom value does not implement `save`",
155 format!("{} doesn't implement saving to disk", self.type_name()),
156 value_span,
157 )
158 .with_help("Check the plugin's documentation for this value type. It might use a different way to save."),
159 )]),
160 ))
161 }
162
163 /// For custom values in plugins: return `true` here if you would like to be notified when all
164 /// copies of this custom value are dropped in the engine.
165 ///
166 /// The notification will take place via `custom_value_dropped()` on the plugin type.
167 ///
168 /// The default is `false`.
169 fn notify_plugin_on_drop(&self) -> bool {
170 false
171 }
172
173 /// Returns an estimate of the memory size used by this CustomValue in bytes
174 ///
175 /// The default implementation returns the size of the trait object.
176 fn memory_size(&self) -> usize {
177 std::mem::size_of_val(self)
178 }
179
180 /// Returns `true` if this custom value should be iterable (like a list) when used with
181 /// commands like `each`, `where`, etc.
182 ///
183 /// When this returns `true`, the engine will call `to_base_value()` to convert the custom
184 /// value to a list before iteration. This is useful for lazy data structures like database
185 /// query builders that should behave like lists when iterated.
186 ///
187 /// The default is `false`.
188 #[deprecated(
189 since = "0.111.1",
190 note = "will be replaced by a new custom-value iterator system next release; \
191 avoid new uses unless you need current behavior"
192 )]
193 fn is_iterable(&self) -> bool {
194 false
195 }
196}