Support for all custom value operations on plugin custom values (#12088)

# Description

Adds support for the following operations on plugin custom values, in
addition to `to_base_value` which was already present:

- `follow_path_int()`
- `follow_path_string()`
- `partial_cmp()`
- `operation()`
- `Drop` (notification, if opted into with
`CustomValue::notify_plugin_on_drop`)

There are additionally customizable methods within the `Plugin` and
`StreamingPlugin` traits for implementing these functions in a way that
requires access to the plugin state, as a registered handle model such
as might be used in a dataframes plugin would.

`Value::append` was also changed to handle custom values correctly.

# User-Facing Changes

- Signature of `CustomValue::follow_path_string` and
`CustomValue::follow_path_int` changed to give access to the span of the
custom value itself, useful for some errors.
- Plugins using custom values have to be recompiled because the engine
will try to do custom value operations that aren't supported
- Plugins can do more things 🎉 

# Tests + Formatting
Tests were added for all of the new custom values functionality.

- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting
- [ ] Document protocol reference `CustomValueOp` variants:
  - [ ] `FollowPathInt`
  - [ ] `FollowPathString`
  - [ ] `PartialCmp`
  - [ ] `Operation`
  - [ ] `Dropped`
- [ ] Document `notify_on_drop` optional field in `PluginCustomValue`
This commit is contained in:
Devyn Cairns
2024-03-12 02:37:08 -07:00
committed by GitHub
parent 8a250d2e08
commit 73f3c0b60b
19 changed files with 1065 additions and 156 deletions

View File

@ -19,7 +19,7 @@ fn serialize_deserialize() -> Result<(), ShellError> {
let original_value = TestCustomValue(32);
let span = Span::test_data();
let serialized = PluginCustomValue::serialize_from_custom_value(&original_value, span)?;
assert_eq!(original_value.value_string(), serialized.name);
assert_eq!(original_value.value_string(), serialized.name());
assert!(serialized.source.is_none());
let deserialized = serialized.deserialize_to_custom_value(span)?;
let downcasted = deserialized
@ -36,8 +36,8 @@ fn expected_serialize_output() -> Result<(), ShellError> {
let span = Span::test_data();
let serialized = PluginCustomValue::serialize_from_custom_value(&original_value, span)?;
assert_eq!(
test_plugin_custom_value().data,
serialized.data,
test_plugin_custom_value().data(),
serialized.data(),
"The bincode configuration is probably different from what we expected. \
Fix test_plugin_custom_value() to match it"
);
@ -417,8 +417,11 @@ fn serialize_in_root() -> Result<(), ShellError> {
let custom_value = val.as_custom_value()?;
if let Some(plugin_custom_value) = custom_value.as_any().downcast_ref::<PluginCustomValue>() {
assert_eq!("TestCustomValue", plugin_custom_value.name);
assert_eq!(test_plugin_custom_value().data, plugin_custom_value.data);
assert_eq!("TestCustomValue", plugin_custom_value.name());
assert_eq!(
test_plugin_custom_value().data(),
plugin_custom_value.data()
);
assert!(plugin_custom_value.source.is_none());
} else {
panic!("Failed to downcast to PluginCustomValue");
@ -443,7 +446,8 @@ fn serialize_in_range() -> Result<(), ShellError> {
.downcast_ref()
.unwrap_or_else(|| panic!("{name} not PluginCustomValue"));
assert_eq!(
"TestCustomValue", plugin_custom_value.name,
"TestCustomValue",
plugin_custom_value.name(),
"{name} name not set correctly"
);
Ok(())
@ -465,7 +469,8 @@ fn serialize_in_record() -> Result<(), ShellError> {
.downcast_ref()
.unwrap_or_else(|| panic!("'{key}' not PluginCustomValue"));
assert_eq!(
"TestCustomValue", plugin_custom_value.name,
"TestCustomValue",
plugin_custom_value.name(),
"'{key}' name not set correctly"
);
Ok(())
@ -484,7 +489,8 @@ fn serialize_in_list() -> Result<(), ShellError> {
.downcast_ref()
.unwrap_or_else(|| panic!("[{index}] not PluginCustomValue"));
assert_eq!(
"TestCustomValue", plugin_custom_value.name,
"TestCustomValue",
plugin_custom_value.name(),
"[{index}] name not set correctly"
);
Ok(())
@ -506,7 +512,8 @@ fn serialize_in_closure() -> Result<(), ShellError> {
.downcast_ref()
.unwrap_or_else(|| panic!("[{index}] not PluginCustomValue"));
assert_eq!(
"TestCustomValue", plugin_custom_value.name,
"TestCustomValue",
plugin_custom_value.name(),
"[{index}] name not set correctly"
);
Ok(())