use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand}; use nu_protocol::{Category, Example, LabeledError, PipelineData, Signature, Span, Type, Value}; use crate::ExamplePlugin; /// ` | example sum` pub struct Sum; impl PluginCommand for Sum { type Plugin = ExamplePlugin; fn name(&self) -> &str { "example sum" } fn description(&self) -> &str { "Example stream consumer for a list of values" } fn signature(&self) -> Signature { Signature::build(self.name()) .input_output_types(vec![ (Type::List(Type::Int.into()), Type::Int), (Type::List(Type::Float.into()), Type::Float), ]) .category(Category::Experimental) } fn search_terms(&self) -> Vec<&str> { vec!["example"] } fn examples(&self) -> Vec { vec![Example { example: "example seq 1 5 | example sum", description: "sum values from 1 to 5", result: Some(Value::test_int(15)), }] } fn run( &self, _plugin: &ExamplePlugin, _engine: &EngineInterface, call: &EvaluatedCall, input: PipelineData, ) -> Result { let mut acc = IntOrFloat::Int(0); for value in input { if let Ok(n) = value.as_int() { acc.add_i64(n); } else if let Ok(n) = value.as_float() { acc.add_f64(n); } else { return Err(LabeledError::new("Sum only accepts ints and floats") .with_label(format!("found {} in input", value.get_type()), value.span()) .with_label("can't be used here", call.head)); } } Ok(PipelineData::Value(acc.to_value(call.head), None)) } } /// Accumulates numbers into either an int or a float. Changes type to float on the first /// float received. #[derive(Clone, Copy)] enum IntOrFloat { Int(i64), Float(f64), } impl IntOrFloat { pub(crate) fn add_i64(&mut self, n: i64) { match self { IntOrFloat::Int(ref mut v) => { *v += n; } IntOrFloat::Float(ref mut v) => { *v += n as f64; } } } pub(crate) fn add_f64(&mut self, n: f64) { match self { IntOrFloat::Int(v) => { *self = IntOrFloat::Float(*v as f64 + n); } IntOrFloat::Float(ref mut v) => { *v += n; } } } pub(crate) fn to_value(self, span: Span) -> Value { match self { IntOrFloat::Int(v) => Value::int(v, span), IntOrFloat::Float(v) => Value::float(v, span), } } } #[test] fn test_examples() -> Result<(), nu_protocol::ShellError> { use nu_plugin_test_support::PluginTest; PluginTest::new("example", ExamplePlugin.into())?.test_command_examples(&Sum) }