nu_plugin_protocol/plugin_custom_value/
mod.rs1use std::cmp::Ordering;
2
3use nu_protocol::{CustomValue, ShellError, Span, Value, ast::Operator};
4use nu_utils::SharedCow;
5
6use serde::{Deserialize, Serialize};
7
8#[cfg(test)]
9mod tests;
10
11#[derive(Clone, Debug, Serialize, Deserialize)]
27pub struct PluginCustomValue(SharedCow<SharedContent>);
28
29#[derive(Clone, Debug, Serialize, Deserialize)]
31struct SharedContent {
32 name: String,
34 data: Vec<u8>,
36 #[serde(default, skip_serializing_if = "is_false")]
40 notify_on_drop: bool,
41}
42
43fn is_false(b: &bool) -> bool {
44 !b
45}
46
47#[typetag::serde]
48impl CustomValue for PluginCustomValue {
49 fn clone_value(&self, span: Span) -> Value {
50 self.clone().into_value(span)
51 }
52
53 fn type_name(&self) -> String {
54 self.name().to_owned()
55 }
56
57 fn to_base_value(&self, _span: Span) -> Result<Value, ShellError> {
58 panic!("to_base_value() not available on plugin custom value without source");
59 }
60
61 fn follow_path_int(
62 &self,
63 _self_span: Span,
64 _index: usize,
65 _path_span: Span,
66 ) -> Result<Value, ShellError> {
67 panic!("follow_path_int() not available on plugin custom value without source");
68 }
69
70 fn follow_path_string(
71 &self,
72 _self_span: Span,
73 _column_name: String,
74 _path_span: Span,
75 ) -> Result<Value, ShellError> {
76 panic!("follow_path_string() not available on plugin custom value without source");
77 }
78
79 fn partial_cmp(&self, _other: &Value) -> Option<Ordering> {
80 panic!("partial_cmp() not available on plugin custom value without source");
81 }
82
83 fn operation(
84 &self,
85 _lhs_span: Span,
86 _operator: Operator,
87 _op_span: Span,
88 _right: &Value,
89 ) -> Result<Value, ShellError> {
90 panic!("operation() not available on plugin custom value without source");
91 }
92
93 fn as_any(&self) -> &dyn std::any::Any {
94 self
95 }
96
97 fn as_mut_any(&mut self) -> &mut dyn std::any::Any {
98 self
99 }
100}
101
102impl PluginCustomValue {
103 pub fn new(name: String, data: Vec<u8>, notify_on_drop: bool) -> PluginCustomValue {
105 PluginCustomValue(SharedCow::new(SharedContent {
106 name,
107 data,
108 notify_on_drop,
109 }))
110 }
111
112 pub fn into_value(self, span: Span) -> Value {
114 Value::custom(Box::new(self), span)
115 }
116
117 pub fn name(&self) -> &str {
119 &self.0.name
120 }
121
122 pub fn data(&self) -> &[u8] {
124 &self.0.data
125 }
126
127 pub fn notify_on_drop(&self) -> bool {
129 self.0.notify_on_drop
130 }
131
132 pub fn ref_count(&self) -> usize {
134 SharedCow::ref_count(&self.0)
135 }
136
137 pub fn serialize_from_custom_value(
140 custom_value: &dyn CustomValue,
141 span: Span,
142 ) -> Result<PluginCustomValue, ShellError> {
143 let name = custom_value.type_name();
144 let notify_on_drop = custom_value.notify_plugin_on_drop();
145 rmp_serde::to_vec(custom_value)
146 .map(|data| PluginCustomValue::new(name, data, notify_on_drop))
147 .map_err(|err| ShellError::CustomValueFailedToEncode {
148 msg: err.to_string(),
149 span,
150 })
151 }
152
153 pub fn deserialize_to_custom_value(
156 &self,
157 span: Span,
158 ) -> Result<Box<dyn CustomValue>, ShellError> {
159 rmp_serde::from_slice::<Box<dyn CustomValue>>(self.data()).map_err(|err| {
160 ShellError::CustomValueFailedToDecode {
161 msg: err.to_string(),
162 span,
163 }
164 })
165 }
166 pub fn serialize_custom_values_in(value: &mut Value) -> Result<(), ShellError> {
169 value.recurse_mut(&mut |value| {
170 let span = value.span();
171 match value {
172 Value::Custom { val, .. } => {
173 if val.as_any().downcast_ref::<PluginCustomValue>().is_some() {
174 Ok(())
176 } else {
177 let serialized = Self::serialize_from_custom_value(&**val, span)?;
178 *value = Value::custom(Box::new(serialized), span);
179 Ok(())
180 }
181 }
182 _ => Ok(()),
183 }
184 })
185 }
186
187 pub fn deserialize_custom_values_in(value: &mut Value) -> Result<(), ShellError> {
190 value.recurse_mut(&mut |value| {
191 let span = value.span();
192 match value {
193 Value::Custom { val, .. } => {
194 if let Some(val) = val.as_any().downcast_ref::<PluginCustomValue>() {
195 let deserialized = val.deserialize_to_custom_value(span)?;
196 *value = Value::custom(deserialized, span);
197 Ok(())
198 } else {
199 Ok(())
201 }
202 }
203 _ => Ok(()),
204 }
205 })
206 }
207
208 pub fn render_to_base_value_in(value: &mut Value) -> Result<(), ShellError> {
210 value.recurse_mut(&mut |value| {
211 let span = value.span();
212 match value {
213 Value::Custom { val, .. } => {
214 *value = val.to_base_value(span)?;
215 Ok(())
216 }
217 _ => Ok(()),
218 }
219 })
220 }
221}