Skip to main content

nu_protocol/engine/
closure.rs

1use std::{
2    borrow::Cow,
3    fmt::{self, Debug},
4};
5
6use crate::{BlockId, ShellError, Span, Value, VarId, engine::EngineState};
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Clone, Serialize, Deserialize)]
11pub struct Closure {
12    pub block_id: BlockId,
13    pub captures: Vec<(VarId, Value)>,
14}
15
16impl Debug for Closure {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("Closure")
19            .field("block_id", &self.block_id)
20            .field(
21                "captures",
22                &fmt::from_fn(|f| {
23                    f.debug_map()
24                        .entries(self.captures.iter().map(|(k, v)| (k, v)))
25                        .finish()
26                }),
27            )
28            .finish()
29    }
30}
31
32impl Closure {
33    pub fn coerce_into_string<'a>(
34        &self,
35        engine_state: &'a EngineState,
36        span: Span,
37    ) -> Result<Cow<'a, str>, ShellError> {
38        let block = engine_state.get_block(self.block_id);
39        if let Some(span) = block.span {
40            let contents_bytes = engine_state.get_span_contents(span);
41            Ok(String::from_utf8_lossy(contents_bytes))
42        } else {
43            Err(ShellError::CantConvert {
44                to_type: "string".into(),
45                from_type: "closure".into(),
46                span,
47                help: Some(format!(
48                    "unable to retrieve block contents for closure with id {}",
49                    self.block_id.get()
50                )),
51            })
52        }
53    }
54
55    /// Returns an estimate of the memory size used by this Closure in bytes
56    pub fn memory_size(&self) -> usize {
57        std::mem::size_of::<Self>()
58            + self
59                .captures
60                .iter()
61                .map(|(_, v)| v.memory_size())
62                .sum::<usize>()
63    }
64
65    pub(crate) fn compact_debug(&self) -> impl Debug {
66        fmt::from_fn(|f| {
67            write!(f, "{:?}: ", self.block_id)?;
68            f.debug_map()
69                .entries(self.captures.iter().map(|(k, v)| (k, v)))
70                .finish()
71        })
72    }
73}