Skip to main content

nu_protocol/value/
custom_value.rs

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