Snap for 7272808 from db6c0dddd5e828f9e30fd4dbe84872c0190faf64 to sc-v2-release

Change-Id: Ibbf55166e93acedbda22aa6d9bda3c93c3a82e83
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 97e8581..12cd342 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "3833799e58db60b87ebfe5a1e2dbe4fc0729621a"
+    "sha1": "522605e72e04dbd6ededa29743a485d2fad29dd4"
   }
 }
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100755
index 0000000..287bc4e
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,47 @@
+on: [push, pull_request]

+

+name: Continuous integration

+

+jobs:

+  ci:

+    runs-on: ubuntu-latest

+    strategy:

+      matrix:

+        rust:

+          - stable

+          - beta

+          - nightly

+          - 1.36.0  # MSRV

+

+    steps:

+      - uses: actions/checkout@v2

+

+      - uses: actions/cache@v2

+        with:

+          path: |

+            ~/.cargo/registry

+            ~/.cargo/git

+            target

+          key: ${{ runner.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }}

+

+      - uses: actions-rs/toolchain@v1

+        with:

+          profile: minimal

+          toolchain: ${{ matrix.rust }}

+          override: true

+          components: rustfmt, clippy

+

+      - run: cargo test

+

+      - if: ${{ matrix.rust == 'stable' }}

+        run: cargo fmt --all -- --check

+        

+      - if: ${{ matrix.rust == 'stable' }}

+        run: cargo clippy --all -- -D warnings

+

+      # Delete things that shouldn't be cached

+      - run: find ./target/debug -maxdepth 1 -type f -delete

+      - run: rm -rf ./target/debug/deps/tinytemplate*

+      - run: rm -rf ./target/debug/.fingerprint/tinytemplate*

+      - run: rm -f  ./target/.rustc_info.json

+      - run: rm -rf ~/.cargo/registry/index/

diff --git a/.travis.yml b/.travis.yml
deleted file mode 100755
index acd6984..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-sudo: true
-
-language: rust
-
-cache: cargo
-
-dist: xenial
-
-rust:
-  - stable
-
-os:
-  - linux
-
-matrix:
-  include:
-    - os: linux
-    - os: linux
-      rust: 1.36.0
-    - os: linux
-      env: RUSTFMT=yes
-    - os: linux
-      env: CLIPPY=yes
-
-install:
-  - bash ci/install.sh
-
-script:
-  - bash ci/script.sh
-
-branches:
-  only: master
-
-notifications:
-  email:
-    on_success: never
diff --git a/Android.bp b/Android.bp
index 69240e3..290f0b5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -52,5 +52,5 @@
 // dependent_library ["feature_list"]
 //   itoa-0.4.7 "default,std"
 //   ryu-1.0.5
-//   serde-1.0.124 "default,std"
+//   serde-1.0.125 "default,std"
 //   serde_json-1.0.64 "default,std"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b02a229..2c757ac 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,16 @@
 
 ## [Unreleased]
 
+## [1.2.1] - 2021-03-03
+### Fixed
+- Fixed a compile error on some nightly compiler versions.
+
+## [1.2.0] - 2020-01-03
+### Fixed
+ - Fixed numeric values being truthy when zero, rather than when non-zero. (For real this time)
+### Added
+ - Allow numeric indexes to be used in paths, to index into JSON arrays.
+
 ## [1.1.0] - 2020-05-31
   - Added `TinyTemplate::set_default_formatter` which, for example, allows to dissable HTML-scaping
 
@@ -31,9 +41,11 @@
 ### Added
 - Initial release on Crates.io.
 
-[Unreleased]: https://github.com/bheisler/TinyTemplate/compare/1.0.3...HEAD
+[Unreleased]: https://github.com/bheisler/TinyTemplate/compare/1.2.0...HEAD
 [1.0.1]: https://github.com/bheisler/TinyTemplate/compare/1.0.0...1.0.1
 [1.0.2]: https://github.com/bheisler/TinyTemplate/compare/1.0.1...1.0.2
 [1.0.3]: https://github.com/bheisler/TinyTemplate/compare/1.0.2...1.0.3
 [1.0.4]: https://github.com/bheisler/TinyTemplate/compare/1.0.3...1.0.4
 [1.1.0]: https://github.com/bheisler/TinyTemplate/compare/1.0.4...1.1.0
+[1.2.0]: https://github.com/bheisler/TinyTemplate/compare/1.1.0...1.2.0
+[1.2.1]: https://github.com/bheisler/TinyTemplate/compare/1.2.0...1.2.1
diff --git a/Cargo.toml b/Cargo.toml
index 22f2454..7995565 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
 
 [package]
 name = "tinytemplate"
-version = "1.1.0"
+version = "1.2.1"
 authors = ["Brook Heisler <brookheisler@gmail.com>"]
 description = "Simple, lightweight template engine"
 readme = "README.md"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 2c48a14..d69a280 100755
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "tinytemplate"
-version = "1.1.0"
+version = "1.2.1"
 authors = ["Brook Heisler <brookheisler@gmail.com>"]
 
 description = "Simple, lightweight template engine"
diff --git a/METADATA b/METADATA
index caa4164..c4c386e 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/tinytemplate/tinytemplate-1.1.0.crate"
+    value: "https://static.crates.io/crates/tinytemplate/tinytemplate-1.2.1.crate"
   }
-  version: "1.1.0"
+  version: "1.2.1"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2020
-    month: 12
-    day: 21
+    year: 2021
+    month: 4
+    day: 2
   }
 }
diff --git a/README.md b/README.md
index 186c5b5..c5c793f 100755
--- a/README.md
+++ b/README.md
@@ -9,12 +9,11 @@
 </div>

 

 <div align="center">

-	<a href="https://travis-ci.org/bheisler/TinyTemplate">

-        <img src="https://travis-ci.org/bheisler/TinyTemplate.svg?branch=master" alt="Travis-CI">

+    <a href="https://github.com/bheisler/TinyTemplate/actions">

+        <img src="https://github.com/bheisler/TinyTemplate/workflows/Continuous%20integration/badge.svg" alt="Continuous integration">

     </a>

-    |

     <a href="https://crates.io/crates/tinytemplate">

-        <img src="https://img.shields.io/crates/v/tinytemplate.svg" alt=Crates.io">

+        <img src="https://img.shields.io/crates/v/tinytemplate.svg" alt="Crates.io">

     </a>

 </div>

 

@@ -63,16 +62,14 @@
 

 ```toml

 [dependencies]

-tinytemplate = "1.0"

-serde_derive = "1.0"

+tinytemplate = "1.1"

+serde = { version = "1.0", features = ["derive"] }

 ```

 

 Then add this code to "src.rs":

 

 ```rust

-#[macro_use]

-extern crate serde_derive;

-extern crate tinytemplate;

+use serde::Serialize;

 

 use tinytemplate::TinyTemplate;

 use std::error::Error;

diff --git a/ci/install.sh b/ci/install.sh
deleted file mode 100755
index 56bb887..0000000
--- a/ci/install.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-set -ex
-
-if [ "$RUSTFMT" = "yes" ]; then
-    rustup component add rustfmt-preview
-fi
-
-if [ "$CLIPPY" = "yes" ]; then
-    rustup component add clippy-preview
-fi
\ No newline at end of file
diff --git a/ci/script.sh b/ci/script.sh
deleted file mode 100755
index 996013c..0000000
--- a/ci/script.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-set -ex
-
-if [ "$RUSTFMT" = "yes" ]; then
-    cargo fmt --all -- --check
-elif [ "$CLIPPY" = "yes" ]; then
-      cargo clippy --all -- -D warnings
-else
-    cargo test
-fi
\ No newline at end of file
diff --git a/src/compiler.rs b/src/compiler.rs
index 5b7e721..df37947 100755
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -6,7 +6,7 @@
 /// template strings and generating the appropriate bytecode instructions.

 use error::Error::*;

 use error::{get_offset, Error, Result};

-use instruction::{Instruction, Path};

+use instruction::{Instruction, Path, PathStep};

 

 /// The end point of a branch or goto instruction is not known.

 const UNKNOWN: usize = ::std::usize::MAX;

@@ -185,9 +185,15 @@
     /// context.

     fn parse_path(&self, text: &'template str) -> Result<Path<'template>> {

         if !text.starts_with('@') {

-            Ok(text.split('.').collect::<Vec<_>>())

+            Ok(text

+                .split('.')

+                .map(|s| match s.parse::<usize>() {

+                    Ok(n) => PathStep::Index(s, n),

+                    Err(_) => PathStep::Name(s),

+                })

+                .collect::<Vec<_>>())

         } else if KNOWN_KEYWORDS.iter().any(|k| *k == text) {

-            Ok(vec![text])

+            Ok(vec![PathStep::Name(text)])

         } else {

             Err(self.parse_error(text, format!("Invalid keyword name '{}'", text)))

         }

@@ -432,7 +438,7 @@
         let text = "{ foobar }";

         let instructions = compile(text).unwrap();

         assert_eq!(1, instructions.len());

-        assert_eq!(&Value(vec!["foobar"]), &instructions[0]);

+        assert_eq!(&Value(vec![PathStep::Name("foobar")]), &instructions[0]);

     }

 

     #[test]

@@ -441,7 +447,7 @@
         let instructions = compile(text).unwrap();

         assert_eq!(1, instructions.len());

         assert_eq!(

-            &FormattedValue(vec!["foobar"], "my_formatter"),

+            &FormattedValue(vec![PathStep::Name("foobar")], "my_formatter"),

             &instructions[0]

         );

     }

@@ -451,7 +457,25 @@
         let text = "{ foo.bar }";

         let instructions = compile(text).unwrap();

         assert_eq!(1, instructions.len());

-        assert_eq!(&Value(vec!["foo", "bar"]), &instructions[0]);

+        assert_eq!(

+            &Value(vec![PathStep::Name("foo"), PathStep::Name("bar")]),

+            &instructions[0]

+        );

+    }

+

+    #[test]

+    fn test_indexed_path() {

+        let text = "{ foo.0.bar }";

+        let instructions = compile(text).unwrap();

+        assert_eq!(1, instructions.len());

+        assert_eq!(

+            &Value(vec![

+                PathStep::Name("foo"),

+                PathStep::Index("0", 0),

+                PathStep::Name("bar")

+            ]),

+            &instructions[0]

+        );

     }

 

     #[test]

@@ -460,7 +484,7 @@
         let instructions = compile(text).unwrap();

         assert_eq!(3, instructions.len());

         assert_eq!(&Literal("Hello "), &instructions[0]);

-        assert_eq!(&Value(vec!["name"]), &instructions[1]);

+        assert_eq!(&Value(vec![PathStep::Name("name")]), &instructions[1]);

         assert_eq!(&Literal(", how are you?"), &instructions[2]);

     }

 

@@ -469,7 +493,10 @@
         let text = "{{ if foo }}Hello!{{ endif }}";

         let instructions = compile(text).unwrap();

         assert_eq!(2, instructions.len());

-        assert_eq!(&Branch(vec!["foo"], true, 2), &instructions[0]);

+        assert_eq!(

+            &Branch(vec![PathStep::Name("foo")], true, 2),

+            &instructions[0]

+        );

         assert_eq!(&Literal("Hello!"), &instructions[1]);

     }

 

@@ -478,7 +505,10 @@
         let text = "{{ if not foo }}Hello!{{ endif }}";

         let instructions = compile(text).unwrap();

         assert_eq!(2, instructions.len());

-        assert_eq!(&Branch(vec!["foo"], false, 2), &instructions[0]);

+        assert_eq!(

+            &Branch(vec![PathStep::Name("foo")], false, 2),

+            &instructions[0]

+        );

         assert_eq!(&Literal("Hello!"), &instructions[1]);

     }

 

@@ -487,7 +517,10 @@
         let text = "{{ if foo }}Hello!{{ else }}Goodbye!{{ endif }}";

         let instructions = compile(text).unwrap();

         assert_eq!(4, instructions.len());

-        assert_eq!(&Branch(vec!["foo"], true, 3), &instructions[0]);

+        assert_eq!(

+            &Branch(vec![PathStep::Name("foo")], true, 3),

+            &instructions[0]

+        );

         assert_eq!(&Literal("Hello!"), &instructions[1]);

         assert_eq!(&Goto(4), &instructions[2]);

         assert_eq!(&Literal("Goodbye!"), &instructions[3]);

@@ -498,7 +531,10 @@
         let text = "{{ with foo as bar }}Hello!{{ endwith }}";

         let instructions = compile(text).unwrap();

         assert_eq!(3, instructions.len());

-        assert_eq!(&PushNamedContext(vec!["foo"], "bar"), &instructions[0]);

+        assert_eq!(

+            &PushNamedContext(vec![PathStep::Name("foo")], "bar"),

+            &instructions[0]

+        );

         assert_eq!(&Literal("Hello!"), &instructions[1]);

         assert_eq!(&PopContext, &instructions[2]);

     }

@@ -509,11 +545,11 @@
         let instructions = compile(text).unwrap();

         assert_eq!(5, instructions.len());

         assert_eq!(

-            &PushIterationContext(vec!["bar", "baz"], "foo"),

+            &PushIterationContext(vec![PathStep::Name("bar"), PathStep::Name("baz")], "foo"),

             &instructions[0]

         );

         assert_eq!(&Iterate(4), &instructions[1]);

-        assert_eq!(&Value(vec!["foo"]), &instructions[2]);

+        assert_eq!(&Value(vec![PathStep::Name("foo")]), &instructions[2]);

         assert_eq!(&Goto(1), &instructions[3]);

         assert_eq!(&PopContext, &instructions[4]);

     }

@@ -524,7 +560,7 @@
         let instructions = compile(text).unwrap();

         assert_eq!(3, instructions.len());

         assert_eq!(&Literal("Hello,"), &instructions[0]);

-        assert_eq!(&Value(vec!["name"]), &instructions[1]);

+        assert_eq!(&Value(vec![PathStep::Name("name")]), &instructions[1]);

         assert_eq!(&Literal(", how are you?"), &instructions[2]);

     }

 

@@ -534,9 +570,12 @@
         let instructions = compile(text).unwrap();

         assert_eq!(6, instructions.len());

         assert_eq!(&Literal("Hello,"), &instructions[0]);

-        assert_eq!(&Branch(vec!["name"], true, 5), &instructions[1]);

+        assert_eq!(

+            &Branch(vec![PathStep::Name("name")], true, 5),

+            &instructions[1]

+        );

         assert_eq!(&Literal(""), &instructions[2]);

-        assert_eq!(&Value(vec!["name"]), &instructions[3]);

+        assert_eq!(&Value(vec![PathStep::Name("name")]), &instructions[3]);

         assert_eq!(&Literal(""), &instructions[4]);

         assert_eq!(&Literal(", how are you?"), &instructions[5]);

     }

@@ -564,8 +603,8 @@
         let text = "{value -}{value} Hello";

         let instructions = compile(text).unwrap();

         assert_eq!(3, instructions.len());

-        assert_eq!(&Value(vec!["value"]), &instructions[0]);

-        assert_eq!(&Value(vec!["value"]), &instructions[1]);

+        assert_eq!(&Value(vec![PathStep::Name("value")]), &instructions[0]);

+        assert_eq!(&Value(vec![PathStep::Name("value")]), &instructions[1]);

         assert_eq!(&Literal(" Hello"), &instructions[2]);

     }

 

@@ -574,7 +613,13 @@
         let text = "{{ call my_macro with foo.bar }}";

         let instructions = compile(text).unwrap();

         assert_eq!(1, instructions.len());

-        assert_eq!(&Call("my_macro", vec!["foo", "bar"]), &instructions[0]);

+        assert_eq!(

+            &Call(

+                "my_macro",

+                vec![PathStep::Name("foo"), PathStep::Name("bar")]

+            ),

+            &instructions[0]

+        );

     }

 

     #[test]

@@ -584,7 +629,7 @@
         assert_eq!(4, instructions.len());

         assert_eq!(&Literal("body "), &instructions[0]);

         assert_eq!(&Literal("{ \nfont-size: "), &instructions[1]);

-        assert_eq!(&Value(vec!["fontsize"]), &instructions[2]);

+        assert_eq!(&Value(vec![PathStep::Name("fontsize")]), &instructions[2]);

         assert_eq!(&Literal(" \n}"), &instructions[3]);

     }

 

diff --git a/src/error.rs b/src/error.rs
index 92f4890..730c648 100755
--- a/src/error.rs
+++ b/src/error.rs
@@ -41,7 +41,7 @@
         column: usize,

     },

 

-    #[doc(Hidden)]

+    #[doc(hidden)]

     __NonExhaustive,

 }

 impl From<SerdeJsonError> for Error {

@@ -57,24 +57,50 @@
 impl fmt::Display for Error {

     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

         match self {

-            Error::ParseError { msg, line, column } => write!(f, "Failed to parse the template (line {}, column {}). Reason: {}", line, column, msg),

+            Error::ParseError { msg, line, column } => write!(

+                f,

+                "Failed to parse the template (line {}, column {}). Reason: {}",

+                line, column, msg

+            ),

             Error::RenderError { msg, line, column } => {

-                write!(f, "Encountered rendering error on line {}, column {}. Reason: {}", line, column, msg)

+                write!(

+                    f,

+                    "Encountered rendering error on line {}, column {}. Reason: {}",

+                    line, column, msg

+                )

             }

-            Error::SerdeError{ err } => {

+            Error::SerdeError { err } => {

                 write!(f, "Unexpected serde error while converting the context to a serde_json::Value. Error: {}", err)

             }

             Error::GenericError { msg } => {

                 write!(f, "{}", msg)

             }

-            Error::StdFormatError{ err } => {

-                write!(f, "Unexpected formatting error: {}", err )

+            Error::StdFormatError { err } => {

+                write!(f, "Unexpected formatting error: {}", err)

             }

-            Error::CalledTemplateError{ name, err, line, column } => {

-                write!(f, "Call to sub-template \"{}\" on line {}, column {} failed. Reason: {}", name, line, column, err)

+            Error::CalledTemplateError {

+                name,

+                err,

+                line,

+                column,

+            } => {

+                write!(

+                    f,

+                    "Call to sub-template \"{}\" on line {}, column {} failed. Reason: {}",

+                    name, line, column, err

+                )

             }

-            Error::CalledFormatterError{ name, err, line, column } => {

-                write!(f, "Call to value formatter \"{}\" on line {}, column {} failed. Reason: {}", name, line, column, err)

+            Error::CalledFormatterError {

+                name,

+                err,

+                line,

+                column,

+            } => {

+                write!(

+                    f,

+                    "Call to value formatter \"{}\" on line {}, column {} failed. Reason: {}",

+                    name, line, column, err

+                )

             }

             Error::__NonExhaustive => unreachable!(),

         }

diff --git a/src/instruction.rs b/src/instruction.rs
index 9bb79e3..0e19814 100755
--- a/src/instruction.rs
+++ b/src/instruction.rs
@@ -1,3 +1,5 @@
+use std::ops::Deref;

+

 /// TinyTemplate implements a simple bytecode interpreter for its template engine. Instructions

 /// for this interpreter are represented by the Instruction enum and typically contain various

 /// parameters such as the path to context values or name strings.

@@ -7,11 +9,28 @@
 /// slices from the template text. These string slices can then be appended directly to the output

 /// string.

 

+/// Enum for a step in a path which optionally contains a parsed index.

+#[derive(Eq, PartialEq, Debug, Clone)]

+pub(crate) enum PathStep<'template> {

+    Name(&'template str),

+    Index(&'template str, usize),

+}

+impl<'template> Deref for PathStep<'template> {

+    type Target = str;

+

+    fn deref(&self) -> &Self::Target {

+        match self {

+            PathStep::Name(s) => s,

+            PathStep::Index(s, _) => s,

+        }

+    }

+}

+

 /// Sequence of named steps used for looking up values in the context

-pub(crate) type Path<'template> = Vec<&'template str>;

+pub(crate) type Path<'template> = Vec<PathStep<'template>>;

 

 /// Path, but as a slice.

-pub(crate) type PathSlice<'a, 'template> = &'a [&'template str];

+pub(crate) type PathSlice<'a, 'template> = &'a [PathStep<'template>];

 

 /// Enum representing the bytecode instructions.

 #[derive(Eq, PartialEq, Debug, Clone)]

diff --git a/src/template.rs b/src/template.rs
index acc4b81..6f0162d 100755
--- a/src/template.rs
+++ b/src/template.rs
@@ -3,7 +3,7 @@
 use compiler::TemplateCompiler;
 use error::Error::*;
 use error::*;
-use instruction::{Instruction, PathSlice};
+use instruction::{Instruction, PathSlice, PathStep};
 use serde_json::Value;
 use std::collections::HashMap;
 use std::fmt::Write;
@@ -44,12 +44,12 @@
             match stack_layer {
                 ContextElement::Object(obj) => return self.lookup_in(path, obj),
                 ContextElement::Named(name, obj) => {
-                    if *name == path[0] {
+                    if *name == &*path[0] {
                         return self.lookup_in(&path[1..], obj);
                     }
                 }
                 ContextElement::Iteration(name, obj, _, _, _) => {
-                    if *name == path[0] {
+                    if *name == &*path[0] {
                         return self.lookup_in(&path[1..], obj);
                     }
                 }
@@ -63,6 +63,15 @@
     fn lookup_in(&self, path: PathSlice, object: &'render Value) -> Result<&'render Value> {
         let mut current = object;
         for step in path.iter() {
+            if let PathStep::Index(_, n) = step {
+                if let Some(next) = current.get(n) {
+                    current = next;
+                    continue;
+                }
+            }
+
+            let step: &str = &*step;
+
             match current.get(step) {
                 Some(next) => current = next,
                 None => return Err(lookup_error(self.original_text, step, path, current)),
@@ -159,11 +168,12 @@
                     program_counter += 1;
                 }
                 Instruction::Value(path) => {
-                    let first = *path.first().unwrap();
+                    let first = path.first().unwrap();
                     if first.starts_with('@') {
                         // Currently we just hard-code the special @-keywords and have special
                         // lookup functions to use them because there are lifetime complexities with
                         // looking up values that don't live for as long as the given context object.
+                        let first: &str = &*first;
                         match first {
                             "@index" => {
                                 write!(output, "{}", render_context.lookup_index()?.0).unwrap()
@@ -202,9 +212,10 @@
                     program_counter += 1;
                 }
                 Instruction::Branch(path, negate, target) => {
-                    let first = *path.first().unwrap();
+                    let first = path.first().unwrap();
                     let mut truthy = if first.starts_with('@') {
-                        match first {
+                        let first: &str = &*first;
+                        match &*first {
                             "@index" => render_context.lookup_index()?.0 != 0,
                             "@first" => render_context.lookup_index()?.0 == 0,
                             "@last" => {
@@ -238,10 +249,10 @@
                 Instruction::PushIterationContext(path, name) => {
                     // We push a context with an invalid index and no value and then wait for the
                     // following Iterate instruction to set the index and value properly.
-                    let first = *path.first().unwrap();
+                    let first = path.first().unwrap();
                     let context_value = match first {
-                        "@root" => render_context.lookup_root()?,
-                        other if other.starts_with('@') => {
+                        PathStep::Name("@root") => render_context.lookup_root()?,
+                        PathStep::Name(other) if other.starts_with('@') => {
                             return Err(not_iterable_error(self.original_text, path))
                         }
                         _ => render_context.lookup(path)?,
@@ -314,12 +325,12 @@
         Ok(())
     }
 
-    fn value_is_truthy(&self, value: &Value, path: &[&str]) -> Result<bool> {
+    fn value_is_truthy(&self, value: &Value, path: PathSlice) -> Result<bool> {
         let truthy = match value {
             Value::Null => false,
             Value::Bool(b) => *b,
             Value::Number(n) => match n.as_f64() {
-                Some(float) => float == 0.0,
+                Some(float) => float != 0.0,
                 None => {
                     return Err(truthiness_error(self.original_text, path));
                 }
@@ -845,4 +856,89 @@
             .unwrap();
         assert_eq!("foobar", &string);
     }
+
+    #[test]
+    fn test_number_truthiness_zero() {
+        let template = compile("{{ if @root }}truthy{{else}}not truthy{{ endif }}");
+        let context = 0;
+        let context = ::serde_json::to_value(&context).unwrap();
+        let template_registry = other_templates();
+        let formatter_registry = formatters();
+        let string = template
+            .render(
+                &context,
+                &template_registry,
+                &formatter_registry,
+                &default_formatter(),
+            )
+            .unwrap();
+        assert_eq!("not truthy", &string);
+    }
+
+    #[test]
+    fn test_number_truthiness_one() {
+        let template = compile("{{ if @root }}truthy{{else}}not truthy{{ endif }}");
+        let context = 1;
+        let context = ::serde_json::to_value(&context).unwrap();
+        let template_registry = other_templates();
+        let formatter_registry = formatters();
+        let string = template
+            .render(
+                &context,
+                &template_registry,
+                &formatter_registry,
+                &default_formatter(),
+            )
+            .unwrap();
+        assert_eq!("truthy", &string);
+    }
+
+    #[test]
+    fn test_indexed_paths() {
+        #[derive(Serialize)]
+        struct Context {
+            foo: (usize, usize),
+        }
+
+        let template = compile("{ foo.1 }{ foo.0 }");
+        let context = Context { foo: (123, 456) };
+        let context = ::serde_json::to_value(&context).unwrap();
+        let template_registry = other_templates();
+        let formatter_registry = formatters();
+        let string = template
+            .render(
+                &context,
+                &template_registry,
+                &formatter_registry,
+                &default_formatter(),
+            )
+            .unwrap();
+        assert_eq!("456123", &string);
+    }
+
+    #[test]
+    fn test_indexed_paths_fall_back_to_string_lookup() {
+        #[derive(Serialize)]
+        struct Context {
+            foo: HashMap<&'static str, usize>,
+        }
+
+        let template = compile("{ foo.1 }{ foo.0 }");
+        let mut foo = HashMap::new();
+        foo.insert("0", 123);
+        foo.insert("1", 456);
+        let context = Context { foo };
+        let context = ::serde_json::to_value(&context).unwrap();
+        let template_registry = other_templates();
+        let formatter_registry = formatters();
+        let string = template
+            .render(
+                &context,
+                &template_registry,
+                &formatter_registry,
+                &default_formatter(),
+            )
+            .unwrap();
+        assert_eq!("456123", &string);
+    }
 }