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}