pub enum ScopedJson<'reg: 'rc, 'rc> {
    Constant(&'reg Json),
    Derived(Json),
    Context(&'rc JsonVec<String>),
    Missing,
}
Expand description

A JSON wrapper designed for handlebars internal use case

  • Constant: the JSON value hardcoded into template
  • Context: the JSON value referenced in your provided data context
  • Derived: the owned JSON value computed during rendering process

Variants§

§

Constant(&'reg Json)

§

Derived(Json)

§

Context(&'rc JsonVec<String>)

§

Missing

Implementations§

get the JSON reference

Examples found in repository?
src/json/value.rs (line 33)
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    pub fn render(&self) -> String {
        self.as_json().render()
    }

    pub fn is_missing(&self) -> bool {
        matches!(self, ScopedJson::Missing)
    }

    pub fn into_derived(self) -> ScopedJson<'reg, 'rc> {
        let v = self.as_json();
        ScopedJson::Derived(v.clone())
    }

    pub fn context_path(&self) -> Option<&Vec<String>> {
        match self {
            ScopedJson::Context(_, ref p) => Some(p),
            _ => None,
        }
    }
}

impl<'reg: 'rc, 'rc> From<Json> for ScopedJson<'reg, 'rc> {
    fn from(v: Json) -> ScopedJson<'reg, 'rc> {
        ScopedJson::Derived(v)
    }
}

/// Json wrapper that holds the Json value and reference path information
///
#[derive(Debug)]
pub struct PathAndJson<'reg, 'rc> {
    relative_path: Option<String>,
    value: ScopedJson<'reg, 'rc>,
}

impl<'reg: 'rc, 'rc> PathAndJson<'reg, 'rc> {
    pub fn new(
        relative_path: Option<String>,
        value: ScopedJson<'reg, 'rc>,
    ) -> PathAndJson<'reg, 'rc> {
        PathAndJson {
            relative_path,
            value,
        }
    }

    /// Returns relative path when the value is referenced
    /// If the value is from a literal, the path is `None`
    pub fn relative_path(&self) -> Option<&String> {
        self.relative_path.as_ref()
    }

    /// Returns full path to this value if any
    pub fn context_path(&self) -> Option<&Vec<String>> {
        self.value.context_path()
    }

    /// Returns the value
    pub fn value(&self) -> &Json {
        self.value.as_json()
    }
More examples
Hide additional examples
src/render.rs (line 628)
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
    pub fn expand<'reg: 'rc, 'rc>(
        &'reg self,
        registry: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
    ) -> Result<PathAndJson<'reg, 'rc>, RenderError> {
        match self {
            Parameter::Name(ref name) => {
                // FIXME: raise error when expanding with name?
                Ok(PathAndJson::new(Some(name.to_owned()), ScopedJson::Missing))
            }
            Parameter::Path(ref path) => {
                if let Some(rc_context) = rc.context() {
                    let result = rc.evaluate2(rc_context.borrow(), path)?;
                    Ok(PathAndJson::new(
                        Some(path.raw().to_owned()),
                        ScopedJson::Derived(result.as_json().clone()),
                    ))
                } else {
                    let result = rc.evaluate2(ctx, path)?;
                    Ok(PathAndJson::new(Some(path.raw().to_owned()), result))
                }
            }
            Parameter::Literal(ref j) => Ok(PathAndJson::new(None, ScopedJson::Constant(j))),
            Parameter::Subexpression(ref t) => match *t.as_element() {
                Expression(ref ht) => {
                    let name = ht.name.expand_as_name(registry, ctx, rc)?;

                    let h = Helper::try_from_template(ht, registry, ctx, rc)?;
                    if let Some(ref d) = rc.get_local_helper(&name) {
                        call_helper_for_value(d.as_ref(), &h, registry, ctx, rc)
                    } else {
                        let mut helper = registry.get_or_load_helper(&name)?;

                        if helper.is_none() {
                            helper = registry.get_or_load_helper(if ht.block {
                                BLOCK_HELPER_MISSING
                            } else {
                                HELPER_MISSING
                            })?;
                        }

                        helper
                            .ok_or_else(|| {
                                RenderError::new(format!("Helper not defined: {:?}", ht.name))
                            })
                            .and_then(|d| call_helper_for_value(d.as_ref(), &h, registry, ctx, rc))
                    }
                }
                _ => unreachable!(),
            },
        }
    }
src/partial.rs (line 118)
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
pub fn expand_partial<'reg: 'rc, 'rc>(
    d: &Decorator<'reg, 'rc>,
    r: &'reg Registry<'reg>,
    ctx: &'rc Context,
    rc: &mut RenderContext<'reg, 'rc>,
    out: &mut dyn Output,
) -> Result<(), RenderError> {
    // try eval inline partials first
    if let Some(t) = d.template() {
        t.eval(r, ctx, rc)?;
    }

    let tname = d.name();
    if rc.is_current_template(tname) {
        return Err(RenderError::new("Cannot include self in >"));
    }

    let partial = find_partial(rc, r, d, tname)?;

    if let Some(t) = partial {
        // clone to avoid lifetime issue
        // FIXME refactor this to avoid
        let mut local_rc = rc.clone();

        // if tname == PARTIAL_BLOCK
        let is_partial_block = tname == PARTIAL_BLOCK;

        // add partial block depth there are consecutive partial
        // blocks in the stack.
        if is_partial_block {
            local_rc.inc_partial_block_depth();
        } else {
            // depth cannot be lower than 0, which is guaranted in the
            // `dec_partial_block_depth` method
            local_rc.dec_partial_block_depth();
        }

        let mut block_created = false;

        // create context if param given
        if let Some(base_path) = d.param(0).and_then(|p| p.context_path()) {
            // path given, update base_path
            let mut block_inner = BlockContext::new();
            *block_inner.base_path_mut() = base_path.to_vec();

            // because block is moved here, we need another bool variable to track
            // its status for later cleanup
            block_created = true;
            // clear blocks to prevent block params from parent
            // template to be leaked into partials
            // see `test_partial_context_issue_495` for the case.
            local_rc.clear_blocks();
            local_rc.push_block(block_inner);
        }

        if !d.hash().is_empty() {
            // hash given, update base_value
            let hash_ctx = d
                .hash()
                .iter()
                .map(|(k, v)| (*k, v.value()))
                .collect::<HashMap<&str, &Json>>();

            // create block if we didn't (no param provided for partial expression)
            if !block_created {
                let block_inner = if let Some(block) = local_rc.block() {
                    // reuse current block information, including base_path and
                    // base_value if any
                    block.clone()
                } else {
                    BlockContext::new()
                };

                local_rc.clear_blocks();
                local_rc.push_block(block_inner);
            }

            // evaluate context within current block, this includes block
            // context provided by partial expression parameter
            let merged_context = merge_json(
                local_rc.evaluate2(ctx, &Path::current())?.as_json(),
                &hash_ctx,
            );

            // update the base value, there must be a block for this so it's
            // also safe to unwrap.
            if let Some(block) = local_rc.block_mut() {
                block.set_base_value(merged_context);
            }
        }

        // @partial-block
        if let Some(pb) = d.template() {
            local_rc.push_partial_block(pb);
        }

        // indent
        local_rc.set_indent_string(d.indent());

        let result = t.render(r, ctx, &mut local_rc, out);

        // cleanup
        if block_created {
            local_rc.pop_block();
        }

        if d.template().is_some() {
            local_rc.pop_partial_block();
        }

        result
    } else {
        Ok(())
    }
}
Examples found in repository?
src/json/value.rs (line 100)
99
100
101
    pub fn render(&self) -> String {
        self.value.render()
    }
More examples
Hide additional examples
src/helpers/mod.rs (line 128)
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
        out: &mut dyn Output,
    ) -> HelperResult {
        match self.call_inner(h, r, ctx, rc) {
            Ok(result) => {
                if r.strict_mode() && result.is_missing() {
                    Err(RenderError::strict_error(None))
                } else {
                    // auto escape according to settings
                    let output = do_escape(r, rc, result.render());
                    out.write(output.as_ref())?;
                    Ok(())
                }
            }
            Err(e) => {
                if e.is_unimplemented() {
                    // default implementation, do nothing
                    Ok(())
                } else {
                    Err(e)
                }
            }
        }
    }
Examples found in repository?
src/json/value.rs (line 96)
95
96
97
    pub fn is_value_missing(&self) -> bool {
        self.value.is_missing()
    }
More examples
Hide additional examples
src/helpers/mod.rs (line 124)
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry<'reg>,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg, 'rc>,
        out: &mut dyn Output,
    ) -> HelperResult {
        match self.call_inner(h, r, ctx, rc) {
            Ok(result) => {
                if r.strict_mode() && result.is_missing() {
                    Err(RenderError::strict_error(None))
                } else {
                    // auto escape according to settings
                    let output = do_escape(r, rc, result.render());
                    out.write(output.as_ref())?;
                    Ok(())
                }
            }
            Err(e) => {
                if e.is_unimplemented() {
                    // default implementation, do nothing
                    Ok(())
                } else {
                    Err(e)
                }
            }
        }
    }
Examples found in repository?
src/json/value.rs (line 86)
85
86
87
    pub fn context_path(&self) -> Option<&Vec<String>> {
        self.value.context_path()
    }

Trait Implementations§

Formats the value using the given formatter. Read more
Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Should always be Self
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.