aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2020-12-07 17:56:55 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-12-07 17:56:55 +0000
commita2deff0e9446e0560653aa286a5a3fcf166d49ad (patch)
tree30b3efa938d801f0479e5ea2c6c647c74e60afa1
parent8ecf69645e5dc06b2d864b8228d1b5b19cefaaf6 (diff)
parent850c55d12c61a71b08420cc31429f937e3474a54 (diff)
downloaduntrusted-a2deff0e9446e0560653aa286a5a3fcf166d49ad.tar.gz
untrusted crate v0.7.1 am: 10c89c5856 am: 64b7afd4a6 am: 850c55d12c
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/untrusted/+/1517419 Change-Id: I82b0938987b5fa2f56a2b21d237826cd4f4b6a57
-rw-r--r--.cargo_vcs_info.json5
-rw-r--r--.gitattributes8
-rw-r--r--.gitignore37
-rw-r--r--.travis.yml15
-rw-r--r--Cargo.toml29
l---------LICENSE1
-rw-r--r--LICENSE.txt13
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_ISC0
-rw-r--r--OWNERS1
-rw-r--r--README.md109
-rw-r--r--rustfmt.toml13
-rw-r--r--src/untrusted.rs374
-rw-r--r--tests/tests.rs98
14 files changed, 722 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..05e75c4
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+ "git": {
+ "sha1": "c3a0e38470aa35565764a68c65b75b9e2ffd732d"
+ }
+}
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..35a6201
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,8 @@
+* text=auto !eol
+*.sln eol=crlf
+*.vcxproj eol=crlf
+*.vcxproj.filters eol=crlf
+*.props eol=crlf
+*.bat eol=crlf
+*.rc eol=crlf
+*.pl linguist-language=Assembly
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..71aa63b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+build/
+ssl/test/runner/runner
+*.bk
+*.orig
+*.swp
+*.swo
+doc/*.html
+doc/doc.css
+*~
+
+# Visual Studio Junk
+.vs/
+*.opensdf
+*.psess
+*.sdf
+*.sln.docstates
+*.suo
+*.user
+*.userosscache
+*.VC.db
+*.VC.opendb
+*.vsp
+*.vspx
+*.rsproj
+*.sln
+*.vcxproj
+*.filters
+
+
+# Cargo Junk
+Cargo.lock
+target/
+
+# JetBrains Junk
+.idea
+*.iml
+CMakeLists.txt
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..9579d74
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,15 @@
+language: rust
+sudo: false
+matrix:
+ allow_failures:
+ - rust: nightly
+ include:
+ - rust: stable
+
+ - rust: beta
+
+ - rust: nightly
+
+script:
+ - cargo test -vv --release
+ - cargo test -vv
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..9da787a
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,29 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "untrusted"
+version = "0.7.1"
+authors = ["Brian Smith <brian@briansmith.org>"]
+description = "Safe, fast, zero-panic, zero-crashing, zero-allocation parsing of untrusted inputs in Rust."
+documentation = "https://briansmith.org/rustdoc/untrusted/"
+readme = "README.md"
+license = "ISC"
+repository = "https://github.com/briansmith/untrusted"
+[profile.bench]
+opt-level = 2
+lto = true
+
+[lib]
+name = "untrusted"
+path = "src/untrusted.rs"
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..85de3d4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE.txt \ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..7151db6
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,13 @@
+// Copyright 2015-2016 Brian Smith.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..60df743
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "untrusted"
+description: "Safe, fast, zero-panic, zero-crashing, zero-allocation parsing of untrusted inputs in Rust."
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/untrusted"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/untrusted/untrusted-0.7.1.crate"
+ }
+ version: "0.7.1"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2020
+ month: 11
+ day: 26
+ }
+}
diff --git a/MODULE_LICENSE_ISC b/MODULE_LICENSE_ISC
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_ISC
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..46fc303
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9cbf9df
--- /dev/null
+++ b/README.md
@@ -0,0 +1,109 @@
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+
+
+untrusted.rs
+============
+
+Safe, fast, zero-panic, zero-crashing, zero-allocation parsing of untrusted
+inputs in Rust.
+
+untrusted.rs is 100% Rust with no use of `unsafe`. It never uses the heap.
+No part of untrusted.rs's API will ever panic or cause a crash. It is
+`#![no_std]` and so it works perfectly with both libcore- and libstd- based
+projects. It does not depend on any crates other than libcore.
+
+untrusted.rs is intended to be used with the latest version of Rust Stable.
+It should usually work with the latest Rust Beta and Rust Nightly versions
+too. Using a version of untrusted.rs other than the latest release available
+on crates.io is not recommended.
+
+
+
+Documentation
+-------------
+
+See the documentation at
+https://briansmith.org/rustdoc/untrusted/.
+
+To use untrusted.rs in your project, add a dependency to your
+Cargo.toml like this:
+
+```
+[dependencies]
+untrusted = "0.2"
+```
+
+
+
+Examples
+--------
+
+[*ring*](https://github.com/briansmith/ring)'s parser for the subset of ASN.1
+DER it needs to understand,
+[`ring::der`](https://github.com/briansmith/ring/blob/master/src/der.rs), is
+built on top of untrusted.rs. *ring* also uses untrusted.rs to parse ECC public
+keys, RSA PKCS#1 1.5 padding, and everything else.
+
+All of [webpki](https://github.com/briansmith/webpki)'s parsing of X.509
+certificates (also ASN.1 DER) is done using untrusted.rs.
+
+
+
+Contributing
+------------
+
+Patches welcome!
+
+When contributing changes, state that you agree to license your contribution
+under the same terms as the existing code by putting this at the bottom of your
+commit message:
+
+```
+
+I agree to license my contributions to each file under the terms given
+at the top of each file I changed.
+```
+
+Currently, the biggest needs for this library are:
+
+* Unit tests.
+* Documentation.
+* More examples.
+* Static analysis and fuzzing.
+
+
+
+Online Automated Testing
+------------------------
+
+Travis CI is used for Android, Linux, and Mac OS X. The tests are run for the
+current release of each Rust channel (Stable, Beta, Nightly). Since
+untrusted.rs only depends on libcore and it only uses 100% cross-platform code
+without using `unsafe`, it should work anywhere as long as these platforms are
+passing.
+
+<a title="Build Status" href=https://travis-ci.org/briansmith/untrusted><img src=https://travis-ci.org/briansmith/untrusted.svg?branch=master></a>
+
+
+
+Bug Reporting
+-------------
+
+Please report bugs either as pull requests or as issues in [the issue
+tracker](https://github.com/briansmith/untrusted/issues). untrusted.rs has a
+**full disclosure** vulnerability policy. **Please do NOT attempt to report
+any security vulnerability in this code privately to anybody.**
+
+
+
+License
+-------
+
+See [LICENSE.txt](LICENSE.txt), an ISC-style (simplified MIT) license.
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..a9ae3c4
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,13 @@
+edition = "2018"
+fn_args_density = "Compressed"
+fn_single_line = true
+match_arm_blocks = false
+match_block_trailing_comma = true
+max_width = 100
+merge_imports = true
+newline_style = "Unix"
+reorder_imports = true
+trailing_comma = "Vertical"
+use_field_init_shorthand = true
+use_try_shorthand = true
+wrap_comments = true
diff --git a/src/untrusted.rs b/src/untrusted.rs
new file mode 100644
index 0000000..2f88bb4
--- /dev/null
+++ b/src/untrusted.rs
@@ -0,0 +1,374 @@
+// Copyright 2015-2016 Brian Smith.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+//! untrusted.rs: Safe, fast, zero-panic, zero-crashing, zero-allocation
+//! parsing of untrusted inputs in Rust.
+//!
+//! <code>git clone https://github.com/briansmith/untrusted</code>
+//!
+//! untrusted.rs goes beyond Rust's normal safety guarantees by also
+//! guaranteeing that parsing will be panic-free, as long as
+//! `untrusted::Input::as_slice_less_safe()` is not used. It avoids copying
+//! data and heap allocation and strives to prevent common pitfalls such as
+//! accidentally parsing input bytes multiple times. In order to meet these
+//! goals, untrusted.rs is limited in functionality such that it works best for
+//! input languages with a small fixed amount of lookahead such as ASN.1, TLS,
+//! TCP/IP, and many other networking, IPC, and related protocols. Languages
+//! that require more lookahead and/or backtracking require some significant
+//! contortions to parse using this framework. It would not be realistic to use
+//! it for parsing programming language code, for example.
+//!
+//! The overall pattern for using untrusted.rs is:
+//!
+//! 1. Write a recursive-descent-style parser for the input language, where the
+//! input data is given as a `&mut untrusted::Reader` parameter to each
+//! function. Each function should have a return type of `Result<V, E>` for
+//! some value type `V` and some error type `E`, either or both of which may
+//! be `()`. Functions for parsing the lowest-level language constructs
+//! should be defined. Those lowest-level functions will parse their inputs
+//! using `::read_byte()`, `Reader::peek()`, and similar functions.
+//! Higher-level language constructs are then parsed by calling the
+//! lower-level functions in sequence.
+//!
+//! 2. Wrap the top-most functions of your recursive-descent parser in
+//! functions that take their input data as an `untrusted::Input`. The
+//! wrapper functions should call the `Input`'s `read_all` (or a variant
+//! thereof) method. The wrapper functions are the only ones that should be
+//! exposed outside the parser's module.
+//!
+//! 3. After receiving the input data to parse, wrap it in an `untrusted::Input`
+//! using `untrusted::Input::from()` as early as possible. Pass the
+//! `untrusted::Input` to the wrapper functions when they need to be parsed.
+//!
+//! In general parsers built using `untrusted::Reader` do not need to explicitly
+//! check for end-of-input unless they are parsing optional constructs, because
+//! `Reader::read_byte()` will return `Err(EndOfInput)` on end-of-input.
+//! Similarly, parsers using `untrusted::Reader` generally don't need to check
+//! for extra junk at the end of the input as long as the parser's API uses the
+//! pattern described above, as `read_all` and its variants automatically check
+//! for trailing junk. `Reader::skip_to_end()` must be used when any remaining
+//! unread input should be ignored without triggering an error.
+//!
+//! untrusted.rs works best when all processing of the input data is done
+//! through the `untrusted::Input` and `untrusted::Reader` types. In
+//! particular, avoid trying to parse input data using functions that take
+//! byte slices. However, when you need to access a part of the input data as
+//! a slice to use a function that isn't written using untrusted.rs,
+//! `Input::as_slice_less_safe()` can be used.
+//!
+//! It is recommend to use `use untrusted;` and then `untrusted::Input`,
+//! `untrusted::Reader`, etc., instead of using `use untrusted::*`. Qualifying
+//! the names with `untrusted` helps remind the reader of the code that it is
+//! dealing with *untrusted* input.
+//!
+//! # Examples
+//!
+//! [*ring*](https://github.com/briansmith/ring)'s parser for the subset of
+//! ASN.1 DER it needs to understand,
+//! [`ring::der`](https://github.com/briansmith/ring/blob/master/src/der.rs),
+//! is built on top of untrusted.rs. *ring* also uses untrusted.rs to parse ECC
+//! public keys, RSA PKCS#1 1.5 padding, and for all other parsing it does.
+//!
+//! All of [webpki](https://github.com/briansmith/webpki)'s parsing of X.509
+//! certificates (also ASN.1 DER) is done using untrusted.rs.
+
+#![doc(html_root_url = "https://briansmith.org/rustdoc/")]
+// `#[derive(...)]` uses `#[allow(unused_qualifications)]` internally.
+#![deny(unused_qualifications)]
+#![forbid(
+ anonymous_parameters,
+ box_pointers,
+ missing_docs,
+ trivial_casts,
+ trivial_numeric_casts,
+ unsafe_code,
+ unstable_features,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_results,
+ variant_size_differences,
+ warnings
+)]
+#![no_std]
+
+/// A wrapper around `&'a [u8]` that helps in writing panic-free code.
+///
+/// No methods of `Input` will ever panic.
+#[derive(Clone, Copy, Debug, Eq)]
+pub struct Input<'a> {
+ value: no_panic::Slice<'a>,
+}
+
+impl<'a> Input<'a> {
+ /// Construct a new `Input` for the given input `bytes`.
+ pub const fn from(bytes: &'a [u8]) -> Self {
+ // This limit is important for avoiding integer overflow. In particular,
+ // `Reader` assumes that an `i + 1 > i` if `input.value.get(i)` does
+ // not return `None`. According to the Rust language reference, the
+ // maximum object size is `core::isize::MAX`, and in practice it is
+ // impossible to create an object of size `core::usize::MAX` or larger.
+ Self {
+ value: no_panic::Slice::new(bytes),
+ }
+ }
+
+ /// Returns `true` if the input is empty and false otherwise.
+ #[inline]
+ pub fn is_empty(&self) -> bool { self.value.is_empty() }
+
+ /// Returns the length of the `Input`.
+ #[inline]
+ pub fn len(&self) -> usize { self.value.len() }
+
+ /// Calls `read` with the given input as a `Reader`, ensuring that `read`
+ /// consumed the entire input. If `read` does not consume the entire input,
+ /// `incomplete_read` is returned.
+ pub fn read_all<F, R, E>(&self, incomplete_read: E, read: F) -> Result<R, E>
+ where
+ F: FnOnce(&mut Reader<'a>) -> Result<R, E>,
+ {
+ let mut input = Reader::new(*self);
+ let result = read(&mut input)?;
+ if input.at_end() {
+ Ok(result)
+ } else {
+ Err(incomplete_read)
+ }
+ }
+
+ /// Access the input as a slice so it can be processed by functions that
+ /// are not written using the Input/Reader framework.
+ #[inline]
+ pub fn as_slice_less_safe(&self) -> &'a [u8] { self.value.as_slice_less_safe() }
+}
+
+impl<'a> From<&'a [u8]> for Input<'a> {
+ #[inline]
+ fn from(value: &'a [u8]) -> Self { Self { value: no_panic::Slice::new(value)} }
+}
+
+// #[derive(PartialEq)] would result in lifetime bounds that are
+// unnecessarily restrictive; see
+// https://github.com/rust-lang/rust/issues/26925.
+impl PartialEq<Input<'_>> for Input<'_> {
+ #[inline]
+ fn eq(&self, other: &Input) -> bool {
+ self.as_slice_less_safe() == other.as_slice_less_safe()
+ }
+}
+
+impl PartialEq<[u8]> for Input<'_> {
+ #[inline]
+ fn eq(&self, other: &[u8]) -> bool { self.as_slice_less_safe() == other }
+}
+
+impl PartialEq<Input<'_>> for [u8] {
+ #[inline]
+ fn eq(&self, other: &Input) -> bool { other.as_slice_less_safe() == self }
+}
+
+/// Calls `read` with the given input as a `Reader`, ensuring that `read`
+/// consumed the entire input. When `input` is `None`, `read` will be
+/// called with `None`.
+pub fn read_all_optional<'a, F, R, E>(
+ input: Option<Input<'a>>, incomplete_read: E, read: F,
+) -> Result<R, E>
+where
+ F: FnOnce(Option<&mut Reader<'a>>) -> Result<R, E>,
+{
+ match input {
+ Some(input) => {
+ let mut input = Reader::new(input);
+ let result = read(Some(&mut input))?;
+ if input.at_end() {
+ Ok(result)
+ } else {
+ Err(incomplete_read)
+ }
+ },
+ None => read(None),
+ }
+}
+
+/// A read-only, forward-only* cursor into the data in an `Input`.
+///
+/// Using `Reader` to parse input helps to ensure that no byte of the input
+/// will be accidentally processed more than once. Using `Reader` in
+/// conjunction with `read_all` and `read_all_optional` helps ensure that no
+/// byte of the input is accidentally left unprocessed. The methods of `Reader`
+/// never panic, so `Reader` also assists the writing of panic-free code.
+///
+/// \* `Reader` is not strictly forward-only because of the method
+/// `get_input_between_marks`, which is provided mainly to support calculating
+/// digests over parsed data.
+#[derive(Debug)]
+pub struct Reader<'a> {
+ input: no_panic::Slice<'a>,
+ i: usize,
+}
+
+/// An index into the already-parsed input of a `Reader`.
+pub struct Mark {
+ i: usize,
+}
+
+impl<'a> Reader<'a> {
+ /// Construct a new Reader for the given input. Use `read_all` or
+ /// `read_all_optional` instead of `Reader::new` whenever possible.
+ #[inline]
+ pub fn new(input: Input<'a>) -> Self {
+ Self {
+ input: input.value,
+ i: 0,
+ }
+ }
+
+ /// Returns `true` if the reader is at the end of the input, and `false`
+ /// otherwise.
+ #[inline]
+ pub fn at_end(&self) -> bool { self.i == self.input.len() }
+
+ /// Returns an `Input` for already-parsed input that has had its boundaries
+ /// marked using `mark`.
+ #[inline]
+ pub fn get_input_between_marks(
+ &self, mark1: Mark, mark2: Mark,
+ ) -> Result<Input<'a>, EndOfInput> {
+ self.input
+ .subslice(mark1.i..mark2.i)
+ .map(|subslice| Input { value: subslice })
+ .ok_or(EndOfInput)
+ }
+
+ /// Return the current position of the `Reader` for future use in a call
+ /// to `get_input_between_marks`.
+ #[inline]
+ pub fn mark(&self) -> Mark { Mark { i: self.i } }
+
+ /// Returns `true` if there is at least one more byte in the input and that
+ /// byte is equal to `b`, and false otherwise.
+ #[inline]
+ pub fn peek(&self, b: u8) -> bool {
+ match self.input.get(self.i) {
+ Some(actual_b) => b == *actual_b,
+ None => false,
+ }
+ }
+
+ /// Reads the next input byte.
+ ///
+ /// Returns `Ok(b)` where `b` is the next input byte, or `Err(EndOfInput)`
+ /// if the `Reader` is at the end of the input.
+ #[inline]
+ pub fn read_byte(&mut self) -> Result<u8, EndOfInput> {
+ match self.input.get(self.i) {
+ Some(b) => {
+ self.i += 1; // safe from overflow; see Input::from().
+ Ok(*b)
+ },
+ None => Err(EndOfInput),
+ }
+ }
+
+ /// Skips `num_bytes` of the input, returning the skipped input as an
+ /// `Input`.
+ ///
+ /// Returns `Ok(i)` if there are at least `num_bytes` of input remaining,
+ /// and `Err(EndOfInput)` otherwise.
+ #[inline]
+ pub fn read_bytes(&mut self, num_bytes: usize) -> Result<Input<'a>, EndOfInput> {
+ let new_i = self.i.checked_add(num_bytes).ok_or(EndOfInput)?;
+ let ret = self
+ .input
+ .subslice(self.i..new_i)
+ .map(|subslice| Input { value: subslice })
+ .ok_or(EndOfInput)?;
+ self.i = new_i;
+ Ok(ret)
+ }
+
+ /// Skips the reader to the end of the input, returning the skipped input
+ /// as an `Input`.
+ #[inline]
+ pub fn read_bytes_to_end(&mut self) -> Input<'a> {
+ let to_skip = self.input.len() - self.i;
+ self.read_bytes(to_skip).unwrap()
+ }
+
+ /// Calls `read()` with the given input as a `Reader`. On success, returns a
+ /// pair `(bytes_read, r)` where `bytes_read` is what `read()` consumed and
+ /// `r` is `read()`'s return value.
+ pub fn read_partial<F, R, E>(&mut self, read: F) -> Result<(Input<'a>, R), E>
+ where
+ F: FnOnce(&mut Reader<'a>) -> Result<R, E>,
+ {
+ let start = self.i;
+ let r = read(self)?;
+ let bytes_read = Input {
+ value: self.input.subslice(start..self.i).unwrap()
+ };
+ Ok((bytes_read, r))
+ }
+
+ /// Skips `num_bytes` of the input.
+ ///
+ /// Returns `Ok(i)` if there are at least `num_bytes` of input remaining,
+ /// and `Err(EndOfInput)` otherwise.
+ #[inline]
+ pub fn skip(&mut self, num_bytes: usize) -> Result<(), EndOfInput> {
+ self.read_bytes(num_bytes).map(|_| ())
+ }
+
+ /// Skips the reader to the end of the input.
+ #[inline]
+ pub fn skip_to_end(&mut self) -> () { let _ = self.read_bytes_to_end(); }
+}
+
+/// The error type used to indicate the end of the input was reached before the
+/// operation could be completed.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub struct EndOfInput;
+
+mod no_panic {
+ use core;
+
+ /// A wrapper around a slice that exposes no functions that can panic.
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct Slice<'a> {
+ bytes: &'a [u8],
+ }
+
+ impl<'a> Slice<'a> {
+ #[inline]
+ pub const fn new(bytes: &'a [u8]) -> Self { Self { bytes } }
+
+ #[inline]
+ pub fn get(&self, i: usize) -> Option<&u8> { self.bytes.get(i) }
+
+ #[inline]
+ pub fn subslice(&self, r: core::ops::Range<usize>) -> Option<Self> {
+ self.bytes.get(r).map(|bytes| Self { bytes })
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool { self.bytes.is_empty() }
+
+ #[inline]
+ pub fn len(&self) -> usize { self.bytes.len() }
+
+ #[inline]
+ pub fn as_slice_less_safe(&self) -> &'a [u8] { self.bytes }
+ }
+
+} // mod no_panic
diff --git a/tests/tests.rs b/tests/tests.rs
new file mode 100644
index 0000000..087e963
--- /dev/null
+++ b/tests/tests.rs
@@ -0,0 +1,98 @@
+// Copyright 2015-2019 Brian Smith.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+#[test]
+fn test_input_from() { let _ = untrusted::Input::from(b"foo"); }
+
+#[test]
+fn test_input_is_empty() {
+ let input = untrusted::Input::from(b"");
+ assert!(input.is_empty());
+ let input = untrusted::Input::from(b"foo");
+ assert!(!input.is_empty());
+}
+
+#[test]
+fn test_input_len() {
+ let input = untrusted::Input::from(b"foo");
+ assert_eq!(input.len(), 3);
+}
+
+#[test]
+fn test_input_read_all() {
+ let input = untrusted::Input::from(b"foo");
+ let result = input.read_all(untrusted::EndOfInput, |input| {
+ assert_eq!(b'f', input.read_byte()?);
+ assert_eq!(b'o', input.read_byte()?);
+ assert_eq!(b'o', input.read_byte()?);
+ assert!(input.at_end());
+ Ok(())
+ });
+ assert_eq!(result, Ok(()));
+}
+
+#[test]
+fn test_input_read_all_unconsume() {
+ let input = untrusted::Input::from(b"foo");
+ let result = input.read_all(untrusted::EndOfInput, |input| {
+ assert_eq!(b'f', input.read_byte()?);
+ assert!(!input.at_end());
+ Ok(())
+ });
+ assert_eq!(result, Err(untrusted::EndOfInput));
+}
+
+#[test]
+fn test_input_as_slice_less_safe() {
+ let slice = b"foo";
+ let input = untrusted::Input::from(slice);
+ assert_eq!(input.as_slice_less_safe(), slice);
+}
+
+#[test]
+fn using_reader_after_skip_and_get_error_returns_error_must_not_panic() {
+ let input = untrusted::Input::from(&[]);
+ let r = input.read_all(untrusted::EndOfInput, |input| {
+ let r = input.read_bytes(1);
+ assert_eq!(r, Err(untrusted::EndOfInput));
+ Ok(input.read_bytes_to_end())
+ });
+ let _ = r; // "Use" r. The value of `r` is undefined here.
+}
+
+#[test]
+fn size_assumptions() {
+ // Assume that a pointer can address any point in the address space, and
+ // infer that this implies that a byte slice will never be
+ // `core::usize::MAX` bytes long.
+ assert_eq!(core::mem::size_of::<*const u8>(), core::mem::size_of::<usize>());
+}
+
+#[test]
+fn const_fn() {
+ const _INPUT: untrusted::Input<'static> = untrusted::Input::from(&[]);
+}
+
+#[test]
+fn test_vec_into() {
+ extern crate std;
+ let vec = vec![0u8; 0];
+ let _x: untrusted::Input = (&vec[..]).into();
+}
+
+#[test]
+fn test_from_slice() {
+ let slice: &[u8] = &[0u8];
+ let _x: untrusted::Input = slice.into();
+} \ No newline at end of file