nu_protocol/value/
custom_value.rs

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