Skip to main content

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}