nu_command/formats/from/
msgpackz.rs

1use std::io::Cursor;
2
3use nu_engine::command_prelude::*;
4
5use super::msgpack::{Opts, read_msgpack};
6
7const BUFFER_SIZE: usize = 65536;
8
9#[derive(Clone)]
10pub struct FromMsgpackz;
11
12impl Command for FromMsgpackz {
13    fn name(&self) -> &str {
14        "from msgpackz"
15    }
16
17    fn signature(&self) -> Signature {
18        Signature::build(self.name())
19            .input_output_type(Type::Binary, Type::Any)
20            .switch("objects", "Read multiple objects from input", None)
21            .category(Category::Formats)
22    }
23
24    fn description(&self) -> &str {
25        "Convert brotli-compressed MessagePack data into Nu values."
26    }
27
28    fn extra_description(&self) -> &str {
29        "This is the format used by the plugin registry file ($nu.plugin-path)."
30    }
31
32    fn run(
33        &self,
34        engine_state: &EngineState,
35        stack: &mut Stack,
36        call: &Call,
37        input: PipelineData,
38    ) -> Result<PipelineData, ShellError> {
39        let span = input.span().unwrap_or(call.head);
40        let objects = call.has_flag(engine_state, stack, "objects")?;
41        let opts = Opts {
42            span,
43            objects,
44            signals: engine_state.signals().clone(),
45        };
46        let metadata = input.metadata().map(|md| md.with_content_type(None));
47        let out = match input {
48            // Deserialize from a byte buffer
49            PipelineData::Value(Value::Binary { val: bytes, .. }, _) => {
50                let reader = brotli::Decompressor::new(Cursor::new(bytes), BUFFER_SIZE);
51                read_msgpack(reader, opts)
52            }
53            // Deserialize from a raw stream directly without having to collect it
54            PipelineData::ByteStream(stream, ..) => {
55                let span = stream.span();
56                if let Some(reader) = stream.reader() {
57                    let reader = brotli::Decompressor::new(reader, BUFFER_SIZE);
58                    read_msgpack(reader, opts)
59                } else {
60                    Err(ShellError::PipelineMismatch {
61                        exp_input_type: "binary or byte stream".into(),
62                        dst_span: call.head,
63                        src_span: span,
64                    })
65                }
66            }
67            _ => Err(ShellError::PipelineMismatch {
68                exp_input_type: "binary or byte stream".into(),
69                dst_span: call.head,
70                src_span: span,
71            }),
72        };
73        out.map(|pd| pd.set_metadata(metadata))
74    }
75}