<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(unused_parens))]

extern crate num_traits;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde-json")]
extern crate serde_json;
extern crate toml;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};

mod error;
mod escaping;

pub use error::{Error, Result};
pub use escaping::MarkupDisplay;

use std::collections::BTreeMap;

pub mod filters;

#[derive(Debug)]
pub struct Config<'a> {
    pub dirs: Vec<PathBuf>,
    pub syntaxes: BTreeMap<String, Syntax<'a>>,
    pub default_syntax: &'a str,
}

#[derive(Debug)]
pub struct Syntax<'a> {
    pub block_start: &'a str,
    pub block_end: &'a str,
    pub expr_start: &'a str,
    pub expr_end: &'a str,
    pub comment_start: &'a str,
    pub comment_end: &'a str,
}

impl<'a> Default for Syntax<'a> {
    fn default() -> Self {
        Self {
            block_start: "{%",
            block_end: "%}",
            expr_start: "{{",
            expr_end: "}}",
            comment_start: "{#",
            comment_end: "#}",
        }
    }
}

impl<'a> From<RawSyntax<'a>> for Syntax<'a> {
    fn from(raw: RawSyntax<'a>) -> Self {
        let syntax = Self::default();
        Self {
            block_start: raw.block_start.unwrap_or(syntax.block_start),
            block_end: raw.block_end.unwrap_or(syntax.block_end),
            expr_start: raw.expr_start.unwrap_or(syntax.expr_start),
            expr_end: raw.expr_end.unwrap_or(syntax.expr_end),
            comment_start: raw.comment_start.unwrap_or(syntax.comment_start),
            comment_end: raw.comment_end.unwrap_or(syntax.comment_end),
        }
    }
}

pub fn read_config_file() -> String {
    let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let filename = root.join(CONFIG_FILE_NAME);
    if filename.exists() {
        fs::read_to_string(&filename)
            .expect(&format!("unable to read {}", filename.to_str().unwrap()))
    } else {
        "".to_string()
    }
}

impl<'a> Config<'a> {
    pub fn new(s: &str) -> Config {
        let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let default = vec![root.join("templates")];

        let mut syntaxes: BTreeMap<String, Syntax> = BTreeMap::new();
        syntaxes.insert(DEFAULT_SYNTAX_NAME.to_string(), Syntax::default());

        let raw: RawConfig =
            toml::from_str(&s).expect(&format!("invalid TOML in {}", CONFIG_FILE_NAME));

        let dirs = match raw.general {
            Some(General { dirs: Some(dirs) }) => {
                dirs.into_iter().map(|dir| root.join(dir)).collect()
            }
            Some(General { dirs: None }) | None => default,
        };

        if let Some(raw_syntaxes) = raw.syntax {
            for raw_s in raw_syntaxes {
                let name = raw_s.name;

                if let Some(_) = syntaxes.insert(name.to_string(), Syntax::from(raw_s)) {
                    panic!("named syntax \"{}\" already exist", name)
                }
            }
        }

        let default_syntax = if let Some(default_syntax) = raw.default_syntax {
            if syntaxes.contains_key(default_syntax) {
                default_syntax
            } else {
                panic!("default syntax {} not exist", default_syntax)
            }
        } else {
            DEFAULT_SYNTAX_NAME
        };

        Config {
            dirs,
            syntaxes,
            default_syntax,
        }
    }

    pub fn find_template(&self, path: &str, start_at: Option<&Path>) -> PathBuf {
        if let Some(root) = start_at {
            let relative = root.with_file_name(path);
            if relative.exists() {
                return relative.to_owned();
            }
        }

        for dir in &self.dirs {
            let rooted = dir.join(path);
            if rooted.exists() {
                return rooted;
            }
        }

        panic!(
            "template {:?} not found in directories {:?}",
            path, self.dirs
        )
    }
}

#[derive(Deserialize)]
struct RawConfig<'d> {
    general: Option<General>,
    syntax: Option<Vec<RawSyntax<'d>>>,
    default_syntax: Option<&'d str>,
}

#[derive(Deserialize)]
struct General {
    dirs: Option<Vec<String>>,
}

#[derive(Deserialize)]
struct RawSyntax<'a> {
    name: &'a str,
    block_start: Option<&'a str>,
    block_end: Option<&'a str>,
    expr_start: Option<&'a str>,
    expr_end: Option<&'a str>,
    comment_start: Option<&'a str>,
    comment_end: Option<&'a str>,
}

static CONFIG_FILE_NAME: &str = "askama.toml";
static DEFAULT_SYNTAX_NAME: &str = "default";

#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::path::{Path, PathBuf};

    #[test]
    fn test_default_config() {
        let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        root.push("templates");
        let config = Config::new("");
        assert_eq!(config.dirs, vec![root]);
    }

    #[test]
    fn test_config_dirs() {
        let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        root.push("tpl");
        let config = Config::new("[general]\ndirs = [\"tpl\"]");
        assert_eq!(config.dirs, vec![root]);
    }

    fn assert_eq_rooted(actual: &Path, expected: &str) {
        let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        root.push("templates");
        let mut inner = PathBuf::new();
        inner.push(expected);
        assert_eq!(actual.strip_prefix(root).unwrap(), inner);
    }

    #[test]
    fn find_absolute() {
        let config = Config::new("");
        let root = config.find_template("a.html", None);
        let path = config.find_template("sub/b.html", Some(&root));
        assert_eq_rooted(&path, "sub/b.html");
    }

    #[test]
    #[should_panic]
    fn find_relative_nonexistent() {
        let config = Config::new("");
        let root = config.find_template("a.html", None);
        config.find_template("b.html", Some(&root));
    }

    #[test]
    fn find_relative() {
        let config = Config::new("");
        let root = config.find_template("sub/b.html", None);
        let path = config.find_template("c.html", Some(&root));
        assert_eq_rooted(&path, "sub/c.html");
    }

    #[test]
    fn find_relative_sub() {
        let config = Config::new("");
        let root = config.find_template("sub/b.html", None);
        let path = config.find_template("sub1/d.html", Some(&root));
        assert_eq_rooted(&path, "sub/sub1/d.html");
    }

    #[test]
    fn add_syntax() {
        let raw_config = r#"
        default_syntax = "foo"

        [[syntax]]
        name = "foo"
        block_start = "~<"

        [[syntax]]
        name = "bar"
        expr_start = "%%"
        "#;

        let default_syntax = Syntax::default();
        let config = Config::new(raw_config);
        assert_eq!(config.default_syntax, "foo");

        let foo = config.syntaxes.get("foo").unwrap();
        assert_eq!(foo.block_start, "~<");
        assert_eq!(foo.block_end, default_syntax.block_end);
        assert_eq!(foo.expr_start, default_syntax.expr_start);
        assert_eq!(foo.expr_end, default_syntax.expr_end);
        assert_eq!(foo.comment_start, default_syntax.comment_start);
        assert_eq!(foo.comment_end, default_syntax.comment_end);

        let bar = config.syntaxes.get("bar").unwrap();
        assert_eq!(bar.block_start, default_syntax.block_start);
        assert_eq!(bar.block_end, default_syntax.block_end);
        assert_eq!(bar.expr_start, "%%");
        assert_eq!(bar.expr_end, default_syntax.expr_end);
        assert_eq!(bar.comment_start, default_syntax.comment_start);
        assert_eq!(bar.comment_end, default_syntax.comment_end);
    }

    #[test]
    fn add_syntax_two() {
        let raw_config = r#"
        default_syntax = "foo"

        syntax = [{ name = "foo", block_start = "~<" },
                  { name = "bar", expr_start = "%%" } ]
        "#;

        let default_syntax = Syntax::default();
        let config = Config::new(raw_config);
        assert_eq!(config.default_syntax, "foo");

        let foo = config.syntaxes.get("foo").unwrap();
        assert_eq!(foo.block_start, "~<");
        assert_eq!(foo.block_end, default_syntax.block_end);
        assert_eq!(foo.expr_start, default_syntax.expr_start);
        assert_eq!(foo.expr_end, default_syntax.expr_end);
        assert_eq!(foo.comment_start, default_syntax.comment_start);
        assert_eq!(foo.comment_end, default_syntax.comment_end);

        let bar = config.syntaxes.get("bar").unwrap();
        assert_eq!(bar.block_start, default_syntax.block_start);
        assert_eq!(bar.block_end, default_syntax.block_end);
        assert_eq!(bar.expr_start, "%%");
        assert_eq!(bar.expr_end, default_syntax.expr_end);
        assert_eq!(bar.comment_start, default_syntax.comment_start);
        assert_eq!(bar.comment_end, default_syntax.comment_end);
    }

    #[should_panic]
    #[test]
    fn use_default_at_syntax_name() {
        let raw_config = r#"
        syntax = [{ name = "default" }]
        "#;

        let _config = Config::new(raw_config);
    }

    #[should_panic]
    #[test]
    fn duplicated_syntax_name_on_list() {
        let raw_config = r#"
        syntax = [{ name = "foo", block_start = "~<" },
                  { name = "foo", block_start = "%%" } ]
        "#;

        let _config = Config::new(raw_config);
    }

    #[should_panic]
    #[test]
    fn is_not_exist_default_syntax() {
        let raw_config = r#"
        default_syntax = "foo"
        "#;

        let _config = Config::new(raw_config);
    }
}
<commit_msg>Reorder code for better readability<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(unused_parens))]

extern crate num_traits;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde-json")]
extern crate serde_json;
extern crate toml;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};

mod error;
mod escaping;

pub use error::{Error, Result};
pub use escaping::MarkupDisplay;

use std::collections::BTreeMap;

pub mod filters;

#[derive(Debug)]
pub struct Config<'a> {
    pub dirs: Vec<PathBuf>,
    pub syntaxes: BTreeMap<String, Syntax<'a>>,
    pub default_syntax: &'a str,
}

impl<'a> Config<'a> {
    pub fn new(s: &str) -> Config {
        let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let default = vec![root.join("templates")];

        let mut syntaxes: BTreeMap<String, Syntax> = BTreeMap::new();
        syntaxes.insert(DEFAULT_SYNTAX_NAME.to_string(), Syntax::default());

        let raw: RawConfig =
            toml::from_str(&s).expect(&format!("invalid TOML in {}", CONFIG_FILE_NAME));

        let dirs = match raw.general {
            Some(General { dirs: Some(dirs) }) => {
                dirs.into_iter().map(|dir| root.join(dir)).collect()
            }
            Some(General { dirs: None }) | None => default,
        };

        if let Some(raw_syntaxes) = raw.syntax {
            for raw_s in raw_syntaxes {
                let name = raw_s.name;

                if let Some(_) = syntaxes.insert(name.to_string(), Syntax::from(raw_s)) {
                    panic!("named syntax \"{}\" already exist", name)
                }
            }
        }

        let default_syntax = if let Some(default_syntax) = raw.default_syntax {
            if syntaxes.contains_key(default_syntax) {
                default_syntax
            } else {
                panic!("default syntax {} not exist", default_syntax)
            }
        } else {
            DEFAULT_SYNTAX_NAME
        };

        Config {
            dirs,
            syntaxes,
            default_syntax,
        }
    }

    pub fn find_template(&self, path: &str, start_at: Option<&Path>) -> PathBuf {
        if let Some(root) = start_at {
            let relative = root.with_file_name(path);
            if relative.exists() {
                return relative.to_owned();
            }
        }

        for dir in &self.dirs {
            let rooted = dir.join(path);
            if rooted.exists() {
                return rooted;
            }
        }

        panic!(
            "template {:?} not found in directories {:?}",
            path, self.dirs
        )
    }
}

#[derive(Debug)]
pub struct Syntax<'a> {
    pub block_start: &'a str,
    pub block_end: &'a str,
    pub expr_start: &'a str,
    pub expr_end: &'a str,
    pub comment_start: &'a str,
    pub comment_end: &'a str,
}

impl<'a> Default for Syntax<'a> {
    fn default() -> Self {
        Self {
            block_start: "{%",
            block_end: "%}",
            expr_start: "{{",
            expr_end: "}}",
            comment_start: "{#",
            comment_end: "#}",
        }
    }
}

impl<'a> From<RawSyntax<'a>> for Syntax<'a> {
    fn from(raw: RawSyntax<'a>) -> Self {
        let syntax = Self::default();
        Self {
            block_start: raw.block_start.unwrap_or(syntax.block_start),
            block_end: raw.block_end.unwrap_or(syntax.block_end),
            expr_start: raw.expr_start.unwrap_or(syntax.expr_start),
            expr_end: raw.expr_end.unwrap_or(syntax.expr_end),
            comment_start: raw.comment_start.unwrap_or(syntax.comment_start),
            comment_end: raw.comment_end.unwrap_or(syntax.comment_end),
        }
    }
}

#[derive(Deserialize)]
struct RawConfig<'d> {
    general: Option<General>,
    syntax: Option<Vec<RawSyntax<'d>>>,
    default_syntax: Option<&'d str>,
}

#[derive(Deserialize)]
struct General {
    dirs: Option<Vec<String>>,
}

#[derive(Deserialize)]
struct RawSyntax<'a> {
    name: &'a str,
    block_start: Option<&'a str>,
    block_end: Option<&'a str>,
    expr_start: Option<&'a str>,
    expr_end: Option<&'a str>,
    comment_start: Option<&'a str>,
    comment_end: Option<&'a str>,
}

pub fn read_config_file() -> String {
    let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let filename = root.join(CONFIG_FILE_NAME);
    if filename.exists() {
        fs::read_to_string(&filename)
            .expect(&format!("unable to read {}", filename.to_str().unwrap()))
    } else {
        "".to_string()
    }
}

static CONFIG_FILE_NAME: &str = "askama.toml";
static DEFAULT_SYNTAX_NAME: &str = "default";

#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::path::{Path, PathBuf};

    #[test]
    fn test_default_config() {
        let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        root.push("templates");
        let config = Config::new("");
        assert_eq!(config.dirs, vec![root]);
    }

    #[test]
    fn test_config_dirs() {
        let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        root.push("tpl");
        let config = Config::new("[general]\ndirs = [\"tpl\"]");
        assert_eq!(config.dirs, vec![root]);
    }

    fn assert_eq_rooted(actual: &Path, expected: &str) {
        let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        root.push("templates");
        let mut inner = PathBuf::new();
        inner.push(expected);
        assert_eq!(actual.strip_prefix(root).unwrap(), inner);
    }

    #[test]
    fn find_absolute() {
        let config = Config::new("");
        let root = config.find_template("a.html", None);
        let path = config.find_template("sub/b.html", Some(&root));
        assert_eq_rooted(&path, "sub/b.html");
    }

    #[test]
    #[should_panic]
    fn find_relative_nonexistent() {
        let config = Config::new("");
        let root = config.find_template("a.html", None);
        config.find_template("b.html", Some(&root));
    }

    #[test]
    fn find_relative() {
        let config = Config::new("");
        let root = config.find_template("sub/b.html", None);
        let path = config.find_template("c.html", Some(&root));
        assert_eq_rooted(&path, "sub/c.html");
    }

    #[test]
    fn find_relative_sub() {
        let config = Config::new("");
        let root = config.find_template("sub/b.html", None);
        let path = config.find_template("sub1/d.html", Some(&root));
        assert_eq_rooted(&path, "sub/sub1/d.html");
    }

    #[test]
    fn add_syntax() {
        let raw_config = r#"
        default_syntax = "foo"

        [[syntax]]
        name = "foo"
        block_start = "~<"

        [[syntax]]
        name = "bar"
        expr_start = "%%"
        "#;

        let default_syntax = Syntax::default();
        let config = Config::new(raw_config);
        assert_eq!(config.default_syntax, "foo");

        let foo = config.syntaxes.get("foo").unwrap();
        assert_eq!(foo.block_start, "~<");
        assert_eq!(foo.block_end, default_syntax.block_end);
        assert_eq!(foo.expr_start, default_syntax.expr_start);
        assert_eq!(foo.expr_end, default_syntax.expr_end);
        assert_eq!(foo.comment_start, default_syntax.comment_start);
        assert_eq!(foo.comment_end, default_syntax.comment_end);

        let bar = config.syntaxes.get("bar").unwrap();
        assert_eq!(bar.block_start, default_syntax.block_start);
        assert_eq!(bar.block_end, default_syntax.block_end);
        assert_eq!(bar.expr_start, "%%");
        assert_eq!(bar.expr_end, default_syntax.expr_end);
        assert_eq!(bar.comment_start, default_syntax.comment_start);
        assert_eq!(bar.comment_end, default_syntax.comment_end);
    }

    #[test]
    fn add_syntax_two() {
        let raw_config = r#"
        default_syntax = "foo"

        syntax = [{ name = "foo", block_start = "~<" },
                  { name = "bar", expr_start = "%%" } ]
        "#;

        let default_syntax = Syntax::default();
        let config = Config::new(raw_config);
        assert_eq!(config.default_syntax, "foo");

        let foo = config.syntaxes.get("foo").unwrap();
        assert_eq!(foo.block_start, "~<");
        assert_eq!(foo.block_end, default_syntax.block_end);
        assert_eq!(foo.expr_start, default_syntax.expr_start);
        assert_eq!(foo.expr_end, default_syntax.expr_end);
        assert_eq!(foo.comment_start, default_syntax.comment_start);
        assert_eq!(foo.comment_end, default_syntax.comment_end);

        let bar = config.syntaxes.get("bar").unwrap();
        assert_eq!(bar.block_start, default_syntax.block_start);
        assert_eq!(bar.block_end, default_syntax.block_end);
        assert_eq!(bar.expr_start, "%%");
        assert_eq!(bar.expr_end, default_syntax.expr_end);
        assert_eq!(bar.comment_start, default_syntax.comment_start);
        assert_eq!(bar.comment_end, default_syntax.comment_end);
    }

    #[should_panic]
    #[test]
    fn use_default_at_syntax_name() {
        let raw_config = r#"
        syntax = [{ name = "default" }]
        "#;

        let _config = Config::new(raw_config);
    }

    #[should_panic]
    #[test]
    fn duplicated_syntax_name_on_list() {
        let raw_config = r#"
        syntax = [{ name = "foo", block_start = "~<" },
                  { name = "foo", block_start = "%%" } ]
        "#;

        let _config = Config::new(raw_config);
    }

    #[should_panic]
    #[test]
    fn is_not_exist_default_syntax() {
        let raw_config = r#"
        default_syntax = "foo"
        "#;

        let _config = Config::new(raw_config);
    }
}
<|endoftext|>


<commit_before>// spell-checker:ignore memmem
//! Implementations of digest functions, like md5 and sha1.
//!
//! The [`Digest`] trait represents the interface for providing inputs
//! to these digest functions and accessing the resulting hash. The
//! [`DigestWriter`] struct provides a wrapper around [`Digest`] that
//! implements the [`Write`] trait, for use in situations where calling
//! [`write`] would be useful.
extern crate digest;
extern crate md5;
extern crate sha1;
extern crate sha2;
extern crate sha3;

use std::io::Write;

use hex::encode;
#[cfg(windows)]
use memchr::memmem;

pub trait Digest {
    fn new() -> Self
    where
        Self: Sized;
    fn input(&mut self, input: &[u8]);
    fn result(&mut self, out: &mut [u8]);
    fn reset(&mut self);
    fn output_bits(&self) -> usize;
    fn output_bytes(&self) -> usize {
        (self.output_bits() + 7) / 8
    }
    fn result_str(&mut self) -> String {
        let mut buf: Vec<u8> = vec![0; self.output_bytes()];
        self.result(&mut buf);
        encode(buf)
    }
}

impl Digest for blake2b_simd::State {
    fn new() -> Self {
        Self::new()
    }

    fn input(&mut self, input: &[u8]) {
        self.update(input);
    }

    fn result(&mut self, out: &mut [u8]) {
        let hash_result = &self.finalize();
        out.copy_from_slice(hash_result.as_bytes());
    }

    fn reset(&mut self) {
        *self = Self::new();
    }

    fn output_bits(&self) -> usize {
        512
    }
}

impl Digest for blake3::Hasher {
    fn new() -> Self {
        Self::new()
    }

    fn input(&mut self, input: &[u8]) {
        self.update(input);
    }

    fn result(&mut self, out: &mut [u8]) {
        let hash_result = &self.finalize();
        out.copy_from_slice(hash_result.as_bytes());
    }

    fn reset(&mut self) {
        *self = Self::new();
    }

    fn output_bits(&self) -> usize {
        256
    }
}

// Implements the Digest trait for sha2 / sha3 algorithms with fixed output
macro_rules! impl_digest_sha {
    ($type: ty, $size: expr) => {
        impl Digest for $type {
            fn new() -> Self {
                Self::default()
            }

            fn input(&mut self, input: &[u8]) {
                digest::Digest::update(self, input);
            }

            fn result(&mut self, out: &mut [u8]) {
                digest::Digest::finalize_into_reset(self, out.into());
            }

            fn reset(&mut self) {
                *self = Self::new();
            }

            fn output_bits(&self) -> usize {
                $size
            }
        }
    };
}

// Implements the Digest trait for sha2 / sha3 algorithms with variable output
macro_rules! impl_digest_shake {
    ($type: ty) => {
        impl Digest for $type {
            fn new() -> Self {
                Self::default()
            }

            fn input(&mut self, input: &[u8]) {
                digest::Update::update(self, input);
            }

            fn result(&mut self, out: &mut [u8]) {
                digest::ExtendableOutputReset::finalize_xof_reset_into(self, out);
            }

            fn reset(&mut self) {
                *self = Self::new();
            }

            fn output_bits(&self) -> usize {
                0
            }
        }
    };
}

impl_digest_sha!(md5::Md5, 128);
impl_digest_sha!(sha1::Sha1, 160);
impl_digest_sha!(sha2::Sha224, 224);
impl_digest_sha!(sha2::Sha256, 256);
impl_digest_sha!(sha2::Sha384, 384);
impl_digest_sha!(sha2::Sha512, 512);

impl_digest_sha!(sha3::Sha3_224, 224);
impl_digest_sha!(sha3::Sha3_256, 256);
impl_digest_sha!(sha3::Sha3_384, 384);
impl_digest_sha!(sha3::Sha3_512, 512);
impl_digest_shake!(sha3::Shake128);
impl_digest_shake!(sha3::Shake256);

/// A struct that writes to a digest.
///
/// This struct wraps a [`Digest`] and provides a [`Write`]
/// implementation that passes input bytes directly to the
/// [`Digest::input`].
///
/// On Windows, if `binary` is `false`, then the [`write`]
/// implementation replaces instances of "\r\n" with "\n" before passing
/// the input bytes to the [`digest`].
pub struct DigestWriter<'a> {
    digest: &'a mut Box<dyn Digest>,

    /// Whether to write to the digest in binary mode or text mode on Windows.
    ///
    /// If this is `false`, then instances of "\r\n" are replaced with
    /// "\n" before passing input bytes to the [`digest`].
    #[allow(dead_code)]
    binary: bool,

    /// Whether the previous
    #[allow(dead_code)]
    was_last_character_carriage_return: bool,
    // TODO These are dead code only on non-Windows operating systems.
    // It might be better to use a `#[cfg(windows)]` guard here.
}

impl<'a> DigestWriter<'a> {
    pub fn new(digest: &'a mut Box<dyn Digest>, binary: bool) -> DigestWriter {
        let was_last_character_carriage_return = false;
        DigestWriter {
            digest,
            binary,
            was_last_character_carriage_return,
        }
    }

    pub fn finalize(&mut self) -> bool {
        if self.was_last_character_carriage_return {
            self.digest.input(&[b'\r']);
            true
        } else {
            false
        }
    }
}

impl<'a> Write for DigestWriter<'a> {
    #[cfg(not(windows))]
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.digest.input(buf);
        Ok(buf.len())
    }

    #[cfg(windows)]
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        if self.binary {
            self.digest.input(buf);
            return Ok(buf.len());
        }

        // The remaining code handles Windows text mode, where we must
        // replace each occurrence of "\r\n" with "\n".
        //
        // First, if the last character written was "\r" and the first
        // character in the current buffer to write is not "\n", then we
        // need to write the "\r" that we buffered from the previous
        // call to `write()`.
        let n = buf.len();
        if self.was_last_character_carriage_return && n > 0 && buf[0] != b'\n' {
            self.digest.input(&[b'\r']);
        }

        // Next, find all occurrences of "\r\n", inputting the slice
        // just before the "\n" in the previous instance of "\r\n" and
        // the beginning of this "\r\n".
        let mut i_prev = 0;
        for i in memmem::find_iter(buf, b"\r\n") {
            self.digest.input(&buf[i_prev..i]);
            i_prev = i + 1;
        }

        // Finally, check whether the last character is "\r". If so,
        // buffer it until we know that the next character is not "\n",
        // which can only be known on the next call to `write()`.
        //
        // This all assumes that `write()` will be called on adjacent
        // blocks of the input.
        if n > 0 && buf[n - 1] == b'\r' {
            self.was_last_character_carriage_return = true;
            self.digest.input(&buf[i_prev..n - 1]);
        } else {
            self.was_last_character_carriage_return = false;
            self.digest.input(&buf[i_prev..n]);
        }

        // Even though we dropped a "\r" for each "\r\n" we found, we
        // still report the number of bytes written as `n`. This is
        // because the meaning of the returned number is supposed to be
        // the number of bytes consumed by the writer, so that if the
        // calling code were calling `write()` in a loop, it would know
        // where the next contiguous slice of the buffer starts.
        Ok(n)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    /// Test for replacing a "\r\n" sequence with "\n" when the "\r" is
    /// at the end of one block and the "\n" is at the beginning of the
    /// next block, when reading in blocks.
    #[cfg(windows)]
    #[test]
    fn test_crlf_across_blocks() {
        use std::io::Write;

        use crate::digest::Digest;
        use crate::digest::DigestWriter;

        // Writing "\r" in one call to `write()`, and then "\n" in another.
        let mut digest = Box::new(md5::Context::new()) as Box<dyn Digest>;
        let mut writer_crlf = DigestWriter::new(&mut digest, false);
        writer_crlf.write_all(&[b'\r']).unwrap();
        writer_crlf.write_all(&[b'\n']).unwrap();
        writer_crlf.finalize();
        let result_crlf = digest.result_str();

        // We expect "\r\n" to be replaced with "\n" in text mode on Windows.
        let mut digest = Box::new(md5::Context::new()) as Box<dyn Digest>;
        let mut writer_lf = DigestWriter::new(&mut digest, false);
        writer_lf.write_all(&[b'\n']).unwrap();
        writer_lf.finalize();
        let result_lf = digest.result_str();

        assert_eq!(result_crlf, result_lf);
    }
}
<commit_msg>hashsum: refactor macro name<commit_after>// spell-checker:ignore memmem
//! Implementations of digest functions, like md5 and sha1.
//!
//! The [`Digest`] trait represents the interface for providing inputs
//! to these digest functions and accessing the resulting hash. The
//! [`DigestWriter`] struct provides a wrapper around [`Digest`] that
//! implements the [`Write`] trait, for use in situations where calling
//! [`write`] would be useful.
extern crate digest;
extern crate md5;
extern crate sha1;
extern crate sha2;
extern crate sha3;

use std::io::Write;

use hex::encode;
#[cfg(windows)]
use memchr::memmem;

pub trait Digest {
    fn new() -> Self
    where
        Self: Sized;
    fn input(&mut self, input: &[u8]);
    fn result(&mut self, out: &mut [u8]);
    fn reset(&mut self);
    fn output_bits(&self) -> usize;
    fn output_bytes(&self) -> usize {
        (self.output_bits() + 7) / 8
    }
    fn result_str(&mut self) -> String {
        let mut buf: Vec<u8> = vec![0; self.output_bytes()];
        self.result(&mut buf);
        encode(buf)
    }
}

impl Digest for blake2b_simd::State {
    fn new() -> Self {
        Self::new()
    }

    fn input(&mut self, input: &[u8]) {
        self.update(input);
    }

    fn result(&mut self, out: &mut [u8]) {
        let hash_result = &self.finalize();
        out.copy_from_slice(hash_result.as_bytes());
    }

    fn reset(&mut self) {
        *self = Self::new();
    }

    fn output_bits(&self) -> usize {
        512
    }
}

impl Digest for blake3::Hasher {
    fn new() -> Self {
        Self::new()
    }

    fn input(&mut self, input: &[u8]) {
        self.update(input);
    }

    fn result(&mut self, out: &mut [u8]) {
        let hash_result = &self.finalize();
        out.copy_from_slice(hash_result.as_bytes());
    }

    fn reset(&mut self) {
        *self = Self::new();
    }

    fn output_bits(&self) -> usize {
        256
    }
}

// Implements the Digest trait for sha2 / sha3 algorithms with fixed output
macro_rules! impl_digest_rustcryptocommon {
    ($type: ty, $size: expr) => {
        impl Digest for $type {
            fn new() -> Self {
                Self::default()
            }

            fn input(&mut self, input: &[u8]) {
                digest::Digest::update(self, input);
            }

            fn result(&mut self, out: &mut [u8]) {
                digest::Digest::finalize_into_reset(self, out.into());
            }

            fn reset(&mut self) {
                *self = Self::new();
            }

            fn output_bits(&self) -> usize {
                $size
            }
        }
    };
}

// Implements the Digest trait for sha2 / sha3 algorithms with variable output
macro_rules! impl_digest_shake {
    ($type: ty) => {
        impl Digest for $type {
            fn new() -> Self {
                Self::default()
            }

            fn input(&mut self, input: &[u8]) {
                digest::Update::update(self, input);
            }

            fn result(&mut self, out: &mut [u8]) {
                digest::ExtendableOutputReset::finalize_xof_reset_into(self, out);
            }

            fn reset(&mut self) {
                *self = Self::new();
            }

            fn output_bits(&self) -> usize {
                0
            }
        }
    };
}

impl_digest_rustcryptocommon!(md5::Md5, 128);
impl_digest_rustcryptocommon!(sha1::Sha1, 160);
impl_digest_rustcryptocommon!(sha2::Sha224, 224);
impl_digest_rustcryptocommon!(sha2::Sha256, 256);
impl_digest_rustcryptocommon!(sha2::Sha384, 384);
impl_digest_rustcryptocommon!(sha2::Sha512, 512);

impl_digest_rustcryptocommon!(sha3::Sha3_224, 224);
impl_digest_rustcryptocommon!(sha3::Sha3_256, 256);
impl_digest_rustcryptocommon!(sha3::Sha3_384, 384);
impl_digest_rustcryptocommon!(sha3::Sha3_512, 512);
impl_digest_shake!(sha3::Shake128);
impl_digest_shake!(sha3::Shake256);

/// A struct that writes to a digest.
///
/// This struct wraps a [`Digest`] and provides a [`Write`]
/// implementation that passes input bytes directly to the
/// [`Digest::input`].
///
/// On Windows, if `binary` is `false`, then the [`write`]
/// implementation replaces instances of "\r\n" with "\n" before passing
/// the input bytes to the [`digest`].
pub struct DigestWriter<'a> {
    digest: &'a mut Box<dyn Digest>,

    /// Whether to write to the digest in binary mode or text mode on Windows.
    ///
    /// If this is `false`, then instances of "\r\n" are replaced with
    /// "\n" before passing input bytes to the [`digest`].
    #[allow(dead_code)]
    binary: bool,

    /// Whether the previous
    #[allow(dead_code)]
    was_last_character_carriage_return: bool,
    // TODO These are dead code only on non-Windows operating systems.
    // It might be better to use a `#[cfg(windows)]` guard here.
}

impl<'a> DigestWriter<'a> {
    pub fn new(digest: &'a mut Box<dyn Digest>, binary: bool) -> DigestWriter {
        let was_last_character_carriage_return = false;
        DigestWriter {
            digest,
            binary,
            was_last_character_carriage_return,
        }
    }

    pub fn finalize(&mut self) -> bool {
        if self.was_last_character_carriage_return {
            self.digest.input(&[b'\r']);
            true
        } else {
            false
        }
    }
}

impl<'a> Write for DigestWriter<'a> {
    #[cfg(not(windows))]
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.digest.input(buf);
        Ok(buf.len())
    }

    #[cfg(windows)]
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        if self.binary {
            self.digest.input(buf);
            return Ok(buf.len());
        }

        // The remaining code handles Windows text mode, where we must
        // replace each occurrence of "\r\n" with "\n".
        //
        // First, if the last character written was "\r" and the first
        // character in the current buffer to write is not "\n", then we
        // need to write the "\r" that we buffered from the previous
        // call to `write()`.
        let n = buf.len();
        if self.was_last_character_carriage_return && n > 0 && buf[0] != b'\n' {
            self.digest.input(&[b'\r']);
        }

        // Next, find all occurrences of "\r\n", inputting the slice
        // just before the "\n" in the previous instance of "\r\n" and
        // the beginning of this "\r\n".
        let mut i_prev = 0;
        for i in memmem::find_iter(buf, b"\r\n") {
            self.digest.input(&buf[i_prev..i]);
            i_prev = i + 1;
        }

        // Finally, check whether the last character is "\r". If so,
        // buffer it until we know that the next character is not "\n",
        // which can only be known on the next call to `write()`.
        //
        // This all assumes that `write()` will be called on adjacent
        // blocks of the input.
        if n > 0 && buf[n - 1] == b'\r' {
            self.was_last_character_carriage_return = true;
            self.digest.input(&buf[i_prev..n - 1]);
        } else {
            self.was_last_character_carriage_return = false;
            self.digest.input(&buf[i_prev..n]);
        }

        // Even though we dropped a "\r" for each "\r\n" we found, we
        // still report the number of bytes written as `n`. This is
        // because the meaning of the returned number is supposed to be
        // the number of bytes consumed by the writer, so that if the
        // calling code were calling `write()` in a loop, it would know
        // where the next contiguous slice of the buffer starts.
        Ok(n)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    /// Test for replacing a "\r\n" sequence with "\n" when the "\r" is
    /// at the end of one block and the "\n" is at the beginning of the
    /// next block, when reading in blocks.
    #[cfg(windows)]
    #[test]
    fn test_crlf_across_blocks() {
        use std::io::Write;

        use crate::digest::Digest;
        use crate::digest::DigestWriter;

        // Writing "\r" in one call to `write()`, and then "\n" in another.
        let mut digest = Box::new(md5::Context::new()) as Box<dyn Digest>;
        let mut writer_crlf = DigestWriter::new(&mut digest, false);
        writer_crlf.write_all(&[b'\r']).unwrap();
        writer_crlf.write_all(&[b'\n']).unwrap();
        writer_crlf.finalize();
        let result_crlf = digest.result_str();

        // We expect "\r\n" to be replaced with "\n" in text mode on Windows.
        let mut digest = Box::new(md5::Context::new()) as Box<dyn Digest>;
        let mut writer_lf = DigestWriter::new(&mut digest, false);
        writer_lf.write_all(&[b'\n']).unwrap();
        writer_lf.finalize();
        let result_lf = digest.result_str();

        assert_eq!(result_crlf, result_lf);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[deny(missing_docs)]

extern crate gfx_core as core;
extern crate gfx_device_gl as device_gl;
extern crate glutin;

use core::{format, handle, texture};
use core::memory::Typed;
use device_gl::Resources as R;

/// Initialize with a window builder.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example
///
/// ```no_run
/// extern crate gfx_core;
/// extern crate gfx_device_gl;
/// extern crate gfx_window_glutin;
/// extern crate glutin;
///
/// use gfx_core::format::{DepthStencil, Rgba8};
///
/// fn main() {
///     let builder = glutin::WindowBuilder::new().with_title("Example".to_string());
///     let (window, device, factory, rtv, stv) =
///         gfx_window_glutin::init::<Rgba8, DepthStencil>(builder);
///
///     // your code
/// }
/// ```
pub fn init<Cf, Df>(builder: glutin::WindowBuilder) ->
            (glutin::Window, device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (window, device, factory, color_view, ds_view) = init_raw(builder, Cf::get_format(), Df::get_format());
    (window, device, factory, Typed::new(color_view), Typed::new(ds_view))
}

/// Initialize with an existing Glutin window.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example (using Piston to create the window)
///
/// let settings = piston::window::WindowSettings::new("Example", [800, 600]);
/// let mut glutin_window = glutin_window::GlutinWindow::new(&settings).unwrap();
///
/// let (mut device, mut factory, main_color, main_depth) =
///     gfx_window_glutin::init_existing::<ColorFormat, DepthFormat>(&glutin_window.window);
///
/// let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
pub fn init_existing<Cf, Df>(window: &glutin::Window) ->
            (device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (device, factory, color_view, ds_view) = init_existing_raw(window, Cf::get_format(), Df::get_format());
    (device, factory, Typed::new(color_view), Typed::new(ds_view))
}

fn get_window_dimensions(window: &glutin::Window) -> texture::Dimensions {
    let (width, height) = window.get_inner_size().unwrap();
    let aa = window.get_pixel_format().multisampling
                   .unwrap_or(0) as texture::NumSamples;
    ((width as f32 * window.hidpi_factor()) as texture::Size, (height as f32 * window.hidpi_factor()) as texture::Size, 1, aa.into())
}

/// Initialize with a window builder. Raw version.
pub fn init_raw(builder: glutin::WindowBuilder,
                color_format: format::Format, ds_format: format::Format) ->
                (glutin::Window, device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    let window = {
        let color_total_bits = color_format.0.get_total_bits();
        let alpha_bits = color_format.0.get_alpha_stencil_bits();
        let depth_total_bits = ds_format.0.get_total_bits();
        let stencil_bits = ds_format.0.get_alpha_stencil_bits();
        builder
            .with_depth_buffer(depth_total_bits - stencil_bits)
            .with_stencil_buffer(stencil_bits)
            .with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
            .with_srgb(Some(color_format.1 == format::ChannelType::Srgb))
            .build()
    }.unwrap();

    let (device, factory, color_view, ds_view) = init_existing_raw(&window, color_format, ds_format);

    (window, device, factory, color_view, ds_view)
}

/// Initialize with an existing Glutin window. Raw version.
pub fn init_existing_raw(window: &glutin::Window,
                color_format: format::Format, ds_format: format::Format) ->
                (device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    unsafe { window.make_current().unwrap() };
    let (device, factory) = device_gl::create(|s|
        window.get_proc_address(s) as *const std::os::raw::c_void);

    // create the main color/depth targets
    let dim = get_window_dimensions(window);
    let (color_view, ds_view) = device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0);

    // done
    (device, factory, color_view, ds_view)
}

/// Update the internal dimensions of the main framebuffer targets. Generic version over the format.
pub fn update_views<Cf, Df>(window: &glutin::Window, color_view: &mut handle::RenderTargetView<R, Cf>,
                    ds_view: &mut handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let dim = color_view.get_dimensions();
    assert_eq!(dim, ds_view.get_dimensions());
    if let Some((cv, dv)) = update_views_raw(window, dim, Cf::get_format(), Df::get_format()) {
        *color_view = Typed::new(cv);
        *ds_view = Typed::new(dv);
    }
}

/// Return new main target views if the window resolution has changed from the old dimensions.
pub fn update_views_raw(window: &glutin::Window, old_dimensions: texture::Dimensions,
                        color_format: format::Format, ds_format: format::Format)
                        -> Option<(handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)>
{
    let dim = get_window_dimensions(window);
    if dim != old_dimensions {
        Some(device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0))
    }else {
        None
    }
}
<commit_msg>Fix doc formatting and add a bit of detail<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[deny(missing_docs)]

extern crate gfx_core as core;
extern crate gfx_device_gl as device_gl;
extern crate glutin;

use core::{format, handle, texture};
use core::memory::Typed;
use device_gl::Resources as R;

/// Initialize with a window builder.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example
///
/// ```no_run
/// extern crate gfx_core;
/// extern crate gfx_device_gl;
/// extern crate gfx_window_glutin;
/// extern crate glutin;
///
/// use gfx_core::format::{DepthStencil, Rgba8};
///
/// fn main() {
///     let builder = glutin::WindowBuilder::new().with_title("Example".to_string());
///     let (window, device, factory, rtv, stv) =
///         gfx_window_glutin::init::<Rgba8, DepthStencil>(builder);
///
///     // your code
/// }
/// ```
pub fn init<Cf, Df>(builder: glutin::WindowBuilder) ->
            (glutin::Window, device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (window, device, factory, color_view, ds_view) = init_raw(builder, Cf::get_format(), Df::get_format());
    (window, device, factory, Typed::new(color_view), Typed::new(ds_view))
}

/// Initialize with an existing Glutin window.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example (using Piston to create the window)
///
/// ```no_run
/// extern crate piston;
/// extern crate glutin_window;
/// extern crate gfx_window_glutin;
///
/// // Create window with Piston
/// let settings = piston::window::WindowSettings::new("Example", [800, 600]);
/// let mut glutin_window = glutin_window::GlutinWindow::new(&settings).unwrap();
///
/// // Initialise gfx
/// let (mut device, mut factory, main_color, main_depth) =
///     gfx_window_glutin::init_existing::<ColorFormat, DepthFormat>(&glutin_window.window);
///
/// let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
/// ```
pub fn init_existing<Cf, Df>(window: &glutin::Window) ->
            (device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (device, factory, color_view, ds_view) = init_existing_raw(window, Cf::get_format(), Df::get_format());
    (device, factory, Typed::new(color_view), Typed::new(ds_view))
}

fn get_window_dimensions(window: &glutin::Window) -> texture::Dimensions {
    let (width, height) = window.get_inner_size().unwrap();
    let aa = window.get_pixel_format().multisampling
                   .unwrap_or(0) as texture::NumSamples;
    ((width as f32 * window.hidpi_factor()) as texture::Size, (height as f32 * window.hidpi_factor()) as texture::Size, 1, aa.into())
}

/// Initialize with a window builder. Raw version.
pub fn init_raw(builder: glutin::WindowBuilder,
                color_format: format::Format, ds_format: format::Format) ->
                (glutin::Window, device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    let window = {
        let color_total_bits = color_format.0.get_total_bits();
        let alpha_bits = color_format.0.get_alpha_stencil_bits();
        let depth_total_bits = ds_format.0.get_total_bits();
        let stencil_bits = ds_format.0.get_alpha_stencil_bits();
        builder
            .with_depth_buffer(depth_total_bits - stencil_bits)
            .with_stencil_buffer(stencil_bits)
            .with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
            .with_srgb(Some(color_format.1 == format::ChannelType::Srgb))
            .build()
    }.unwrap();

    let (device, factory, color_view, ds_view) = init_existing_raw(&window, color_format, ds_format);

    (window, device, factory, color_view, ds_view)
}

/// Initialize with an existing Glutin window. Raw version.
pub fn init_existing_raw(window: &glutin::Window,
                color_format: format::Format, ds_format: format::Format) ->
                (device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    unsafe { window.make_current().unwrap() };
    let (device, factory) = device_gl::create(|s|
        window.get_proc_address(s) as *const std::os::raw::c_void);

    // create the main color/depth targets
    let dim = get_window_dimensions(window);
    let (color_view, ds_view) = device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0);

    // done
    (device, factory, color_view, ds_view)
}

/// Update the internal dimensions of the main framebuffer targets. Generic version over the format.
pub fn update_views<Cf, Df>(window: &glutin::Window, color_view: &mut handle::RenderTargetView<R, Cf>,
                    ds_view: &mut handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let dim = color_view.get_dimensions();
    assert_eq!(dim, ds_view.get_dimensions());
    if let Some((cv, dv)) = update_views_raw(window, dim, Cf::get_format(), Df::get_format()) {
        *color_view = Typed::new(cv);
        *ds_view = Typed::new(dv);
    }
}

/// Return new main target views if the window resolution has changed from the old dimensions.
pub fn update_views_raw(window: &glutin::Window, old_dimensions: texture::Dimensions,
                        color_format: format::Format, ds_format: format::Format)
                        -> Option<(handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)>
{
    let dim = get_window_dimensions(window);
    if dim != old_dimensions {
        Some(device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0))
    }else {
        None
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Add example of invalidating<commit_after>fn main() {
    let mut s = String::from("hello there!");

    // append to string

    s.push_str(" Nice to meet you!");

    println!("{}", s);

    let s2 = s;
    // s is no longer valid here!
    println!("{}", s);
}
<|endoftext|>


<commit_before>#![crate_type="lib"]

pub trait Remote {
    fn foo(&self) { }
}

pub trait Remote1<T> {
    fn foo(&self, t: T) { }
}

pub trait Remote2<T, U> {
    fn foo(&self, t: T, u: U) { }
}

pub struct Pair<T,U>(T,U);
<commit_msg>Fix some unused variable warnings<commit_after>#![crate_type="lib"]

pub trait Remote {
    fn foo(&self) { }
}

pub trait Remote1<T> {
    fn foo(&self, _t: T) { }
}

pub trait Remote2<T, U> {
    fn foo(&self, _t: T, _u: U) { }
}

pub struct Pair<T,U>(T,U);
<|endoftext|>


<commit_before>use std::{cmp, io::{self, Write, Read}, iter::repeat, ptr};

#[derive(Debug,PartialEq,Clone)]
pub struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub fn with_capacity(capacity: usize) -> Buffer {
    let mut v = Vec::with_capacity(capacity);
    v.extend(repeat(0).take(capacity));
    Buffer {
      memory:   v,
      capacity,
      position: 0,
      end:      0
    }
  }

  pub fn grow(&mut self, new_size: usize) -> bool {
    if self.capacity >= new_size {
      return false;
    }

    self.memory.resize(new_size, 0);
    self.capacity = new_size;
    true
  }

  pub fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    if self.position > self.capacity / 2 {
      self.shift();
    }
    cnt
  }

  pub fn fill(&mut self, count: usize) -> usize {
    if self.available_space() < self.position {
      self.shift();
    }
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    cnt
  }

  pub fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub fn space(&mut self) -> &mut [u8] {
    &mut self.memory[self.end..self.capacity]
  }

  fn shift(&mut self) {
    let length = self.end - self.position;
    unsafe {
      ptr::copy((&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
    }
    self.position = 0;
    self.end      = length;
  }
}

impl Write for Buffer {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.space().write(buf).map(|size| {
      self.fill(size);
      size
    })
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

impl Read for Buffer {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = cmp::min(self.available_data(), buf.len());
    buf.copy_from_slice(&self.memory[self.position..len]);
    self.position += len;
    Ok(len)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::io::Write;

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.write(&b"abcd"[..]);
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }
}
<commit_msg>async: faster vec initialization<commit_after>use std::{cmp, io::{self, Write, Read}, ptr};

#[derive(Debug,PartialEq,Clone)]
pub struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub fn with_capacity(capacity: usize) -> Buffer {
    Buffer {
      memory:   vec![0; capacity],
      capacity,
      position: 0,
      end:      0
    }
  }

  pub fn grow(&mut self, new_size: usize) -> bool {
    if self.capacity >= new_size {
      return false;
    }

    self.memory.resize(new_size, 0);
    self.capacity = new_size;
    true
  }

  pub fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    if self.position > self.capacity / 2 {
      self.shift();
    }
    cnt
  }

  pub fn fill(&mut self, count: usize) -> usize {
    if self.available_space() < self.position {
      self.shift();
    }
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    cnt
  }

  pub fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub fn space(&mut self) -> &mut [u8] {
    &mut self.memory[self.end..self.capacity]
  }

  fn shift(&mut self) {
    let length = self.end - self.position;
    unsafe {
      ptr::copy((&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
    }
    self.position = 0;
    self.end      = length;
  }
}

impl Write for Buffer {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.space().write(buf).map(|size| {
      self.fill(size);
      size
    })
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

impl Read for Buffer {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = cmp::min(self.available_data(), buf.len());
    buf.copy_from_slice(&self.memory[self.position..len]);
    self.position += len;
    Ok(len)
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::io::Write;

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.write(&b"abcd"[..]);
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }
}
<|endoftext|>


<commit_before>extern crate gluon_base as base;
extern crate pretty;
#[macro_use]
extern crate pretty_assertions;

use std::ops::Deref;

use pretty::{Arena, DocAllocator};

use base::kind::Kind;
use base::types::*;
use base::source::Source;

fn type_con<I, T>(s: I, args: Vec<T>) -> Type<I, T>
where
    I: Deref<Target = str>,
    T: From<Type<I, T>>,
{
    assert!(s.len() != 0);
    match s.parse() {
        Ok(b) => Type::Builtin(b),
        Err(()) if s.starts_with(char::is_lowercase) => Type::Generic(Generic::new(s, Kind::typ())),
        Err(()) => Type::App(Type::ident(s), args.into_iter().collect()),
    }
}

macro_rules! assert_eq_display {
    ($l: expr, $r: expr) => {
        assert_eq!($l.to_string(), $r.to_string());
    }
}

#[test]
fn show_function() {
    let int: ArcType<&str> = Type::int();
    let int_int = Type::function(vec![int.clone()], int.clone());
    assert_eq_display!(format!("{}", int_int), "Int -> Int");

    assert_eq_display!(
        format!("{}", Type::function(vec![int_int.clone()], int.clone())),
        "(Int -> Int) -> Int"
    );

    assert_eq_display!(
        format!("{}", Type::function(vec![int.clone()], int_int.clone())),
        "Int -> Int -> Int"
    );
}

#[test]
fn show_forall() {
    let arg = |id| Generic::new(id, Kind::typ());
    let typ: ArcType<&str> = Type::forall(vec![arg("a"), arg("b")], Type::unit());

    assert_eq_display!(format!("{}", typ), "forall a b . ()");
}

#[test]
fn show_record_empty() {
    let record: ArcType<&str> = Type::record(vec![], vec![]);
    assert_eq_display!(format!("{}", record), "{}");
}

#[test]
fn show_record_singleton() {
    let typ: ArcType<&str> = Type::record(vec![], vec![Field::new("x", Type::int())]);
    assert_eq_display!(format!("{}", typ), "{ x : Int }");
}

#[test]
fn show_record_singleton_polymorphic() {
    let data = |s, a| ArcType::from(type_con(s, a));
    let fun = Type::function(vec![data("a", vec![])], Type::string());
    let typ = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![],
    );
    assert_eq_display!(format!("{}", typ), "{ Test = forall a . a -> String }");
}

#[test]
fn show_record_multifield() {
    let data = |s, a| ArcType::from(type_con(s, a));
    let fun = Type::function(vec![data("a", vec![])], Type::string());
    let typ = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![Field::new("x", Type::int())],
    );
    assert_eq_display!(
        format!("{}", typ),
        "{ Test = forall a . a -> String, x : Int }"
    );
}
#[test]
fn show_record_multiline() {
    let data = |s, a| ArcType::from(type_con(s, a));
    let fun = Type::function(vec![data("a", vec![])], Type::string());
    let test = data("Test", vec![data("a", vec![])]);
    let record = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![
            Field::new("x", Type::int()),
            Field::new("test", test.clone()),
            Field::new(
                "+",
                Type::function(vec![Type::int(), Type::int()], Type::int()),
            ),
        ],
    );

    assert_eq_display!(
        format!("{}", record),
        r#"{
    Test = forall a . a -> String,
    x : Int,
    test : Test a,
    (+) : Int -> Int -> Int
}"#
    );
}

#[test]
fn show_record_multi_line_nested() {
    let data = |s, a| ArcType::from(type_con(s, a));
    let fun = Type::function(vec![data("a", vec![])], Type::string());
    let test = data("Test", vec![data("a", vec![])]);
    let inner_record = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![
            Field::new("x", Type::int()),
            Field::new("test", test.clone()),
            Field::new(
                "+",
                Type::function(vec![Type::int(), Type::int()], Type::int()),
            ),
        ],
    );
    let record = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![
            Field::new("x", Type::int()),
            Field::new(
                "test",
                Type::function(
                    vec![
                        data("Test", vec![Type::int(), fun.clone()]),
                        Type::float(),
                        fun.clone(),
                        fun.clone(),
                    ],
                    fun.clone(),
                ),
            ),
            Field::new(
                "record_looooooooooooooooooooooooooooooooooong",
                inner_record,
            ),
            Field::new("looooooooooooooooooooooooooooooooooong_field", test.clone()),
        ],
    );
    let expected = r#"{
    Test = forall a . a -> String,
    x : Int,
    test : Test Int (a -> String)
            -> Float
            -> (a -> String)
            -> (a -> String)
            -> a
            -> String,
    record_looooooooooooooooooooooooooooooooooong : {
        Test = forall a . a -> String,
        x : Int,
        test : Test a,
        (+) : Int -> Int -> Int
    },
    looooooooooooooooooooooooooooooooooong_field : Test a
}"#;

    assert_eq_display!(format!("{}", record), expected);
}

#[test]
fn show_variant() {
    let typ: ArcType<&str> = Type::variant(vec![
        Field::new("A", Type::function(vec![Type::int()], Type::ident("A"))),
        Field::new("B", Type::ident("A")),
    ]);
    assert_eq_display!(format!("{}", typ), "| A Int | B");
}

#[test]
fn show_kind() {
    let two_args = Kind::function(Kind::typ(), Kind::function(Kind::typ(), Kind::typ()));
    assert_eq_display!(format!("{}", two_args), "Type -> Type -> Type");
    let function_arg = Kind::function(Kind::function(Kind::typ(), Kind::typ()), Kind::typ());
    assert_eq_display!(format!("{}", function_arg), "(Type -> Type) -> Type");
}

#[test]
fn show_polymorphic_record() {
    let fields = vec![Field::new("x", Type::string())];
    let typ: ArcType<&str> = Type::poly_record(vec![], fields, Type::ident("r"));
    assert_eq_display!(format!("{}", typ), "{ x : String | r }");
}

#[test]
fn show_polymorphic_record_associated_type() {
    let type_fields = vec![
        Field::new(
            "Test",
            Alias::new(
                "Test",
                Type::forall(vec![Generic::new("a", Kind::typ())], Type::ident("a")),
            ),
        ),
    ];
    let typ: ArcType<&str> = Type::poly_record(type_fields, vec![], Type::ident("r"));
    assert_eq_display!(format!("{}", typ), "{ Test = forall a . a | r }");
}

#[test]
fn break_record() {
    let data = |s, a| ArcType::from(type_con(s, a));

    let test = data("Test", vec![data("a", vec![])]);
    let typ: ArcType<&str> = Type::record(
        vec![],
        vec![
            Field::new("x", Type::int()),
            Field::new("test", test.clone()),
            Field::new(
                "+",
                Type::function(vec![Type::int(), Type::int()], Type::int()),
            ),
        ],
    );
    let arena = Arena::new();
    let source = Source::new("");
    let printer = pretty_print::Printer::new(&arena, &source);
    let typ = arena
        .text("aaaaaaaaabbbbbbbbbbcccccccccc ")
        .append(pretty_print(&printer, &typ))
        .append(arena.newline());
    assert_eq_display!(
        format!("{}", typ.1.pretty(80)),
        r#"aaaaaaaaabbbbbbbbbbcccccccccc {
    x : Int,
    test : Test a,
    (+) : Int -> Int -> Int
}
"#
    );
}
<commit_msg>Fix bad rebase in the show_record_empty test<commit_after>extern crate gluon_base as base;
extern crate pretty;
#[macro_use]
extern crate pretty_assertions;

use std::ops::Deref;

use pretty::{Arena, DocAllocator};

use base::kind::Kind;
use base::types::*;
use base::source::Source;

fn type_con<I, T>(s: I, args: Vec<T>) -> Type<I, T>
where
    I: Deref<Target = str>,
    T: From<Type<I, T>>,
{
    assert!(s.len() != 0);
    match s.parse() {
        Ok(b) => Type::Builtin(b),
        Err(()) if s.starts_with(char::is_lowercase) => Type::Generic(Generic::new(s, Kind::typ())),
        Err(()) => Type::App(Type::ident(s), args.into_iter().collect()),
    }
}

macro_rules! assert_eq_display {
    ($l: expr, $r: expr) => {
        assert_eq!($l.to_string(), $r.to_string());
    }
}

#[test]
fn show_function() {
    let int: ArcType<&str> = Type::int();
    let int_int = Type::function(vec![int.clone()], int.clone());
    assert_eq_display!(format!("{}", int_int), "Int -> Int");

    assert_eq_display!(
        format!("{}", Type::function(vec![int_int.clone()], int.clone())),
        "(Int -> Int) -> Int"
    );

    assert_eq_display!(
        format!("{}", Type::function(vec![int.clone()], int_int.clone())),
        "Int -> Int -> Int"
    );
}

#[test]
fn show_forall() {
    let arg = |id| Generic::new(id, Kind::typ());
    let typ: ArcType<&str> = Type::forall(vec![arg("a"), arg("b")], Type::unit());

    assert_eq_display!(format!("{}", typ), "forall a b . ()");
}

#[test]
fn show_record_empty() {
    let record: ArcType<&str> = Type::record(vec![], vec![]);
    assert_eq_display!(format!("{}", record), "()");
}

#[test]
fn show_record_singleton() {
    let typ: ArcType<&str> = Type::record(vec![], vec![Field::new("x", Type::int())]);
    assert_eq_display!(format!("{}", typ), "{ x : Int }");
}

#[test]
fn show_record_singleton_polymorphic() {
    let data = |s, a| ArcType::from(type_con(s, a));
    let fun = Type::function(vec![data("a", vec![])], Type::string());
    let typ = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![],
    );
    assert_eq_display!(format!("{}", typ), "{ Test = forall a . a -> String }");
}

#[test]
fn show_record_multifield() {
    let data = |s, a| ArcType::from(type_con(s, a));
    let fun = Type::function(vec![data("a", vec![])], Type::string());
    let typ = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![Field::new("x", Type::int())],
    );
    assert_eq_display!(
        format!("{}", typ),
        "{ Test = forall a . a -> String, x : Int }"
    );
}
#[test]
fn show_record_multiline() {
    let data = |s, a| ArcType::from(type_con(s, a));
    let fun = Type::function(vec![data("a", vec![])], Type::string());
    let test = data("Test", vec![data("a", vec![])]);
    let record = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![
            Field::new("x", Type::int()),
            Field::new("test", test.clone()),
            Field::new(
                "+",
                Type::function(vec![Type::int(), Type::int()], Type::int()),
            ),
        ],
    );

    assert_eq_display!(
        format!("{}", record),
        r#"{
    Test = forall a . a -> String,
    x : Int,
    test : Test a,
    (+) : Int -> Int -> Int
}"#
    );
}

#[test]
fn show_record_multi_line_nested() {
    let data = |s, a| ArcType::from(type_con(s, a));
    let fun = Type::function(vec![data("a", vec![])], Type::string());
    let test = data("Test", vec![data("a", vec![])]);
    let inner_record = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![
            Field::new("x", Type::int()),
            Field::new("test", test.clone()),
            Field::new(
                "+",
                Type::function(vec![Type::int(), Type::int()], Type::int()),
            ),
        ],
    );
    let record = Type::record(
        vec![
            Field::new(
                "Test",
                Alias::new(
                    "Test",
                    Type::forall(vec![Generic::new("a", Kind::typ())], fun.clone()),
                ),
            ),
        ],
        vec![
            Field::new("x", Type::int()),
            Field::new(
                "test",
                Type::function(
                    vec![
                        data("Test", vec![Type::int(), fun.clone()]),
                        Type::float(),
                        fun.clone(),
                        fun.clone(),
                    ],
                    fun.clone(),
                ),
            ),
            Field::new(
                "record_looooooooooooooooooooooooooooooooooong",
                inner_record,
            ),
            Field::new("looooooooooooooooooooooooooooooooooong_field", test.clone()),
        ],
    );
    let expected = r#"{
    Test = forall a . a -> String,
    x : Int,
    test : Test Int (a -> String)
            -> Float
            -> (a -> String)
            -> (a -> String)
            -> a
            -> String,
    record_looooooooooooooooooooooooooooooooooong : {
        Test = forall a . a -> String,
        x : Int,
        test : Test a,
        (+) : Int -> Int -> Int
    },
    looooooooooooooooooooooooooooooooooong_field : Test a
}"#;

    assert_eq_display!(format!("{}", record), expected);
}

#[test]
fn show_variant() {
    let typ: ArcType<&str> = Type::variant(vec![
        Field::new("A", Type::function(vec![Type::int()], Type::ident("A"))),
        Field::new("B", Type::ident("A")),
    ]);
    assert_eq_display!(format!("{}", typ), "| A Int | B");
}

#[test]
fn show_kind() {
    let two_args = Kind::function(Kind::typ(), Kind::function(Kind::typ(), Kind::typ()));
    assert_eq_display!(format!("{}", two_args), "Type -> Type -> Type");
    let function_arg = Kind::function(Kind::function(Kind::typ(), Kind::typ()), Kind::typ());
    assert_eq_display!(format!("{}", function_arg), "(Type -> Type) -> Type");
}

#[test]
fn show_polymorphic_record() {
    let fields = vec![Field::new("x", Type::string())];
    let typ: ArcType<&str> = Type::poly_record(vec![], fields, Type::ident("r"));
    assert_eq_display!(format!("{}", typ), "{ x : String | r }");
}

#[test]
fn show_polymorphic_record_associated_type() {
    let type_fields = vec![
        Field::new(
            "Test",
            Alias::new(
                "Test",
                Type::forall(vec![Generic::new("a", Kind::typ())], Type::ident("a")),
            ),
        ),
    ];
    let typ: ArcType<&str> = Type::poly_record(type_fields, vec![], Type::ident("r"));
    assert_eq_display!(format!("{}", typ), "{ Test = forall a . a | r }");
}

#[test]
fn break_record() {
    let data = |s, a| ArcType::from(type_con(s, a));

    let test = data("Test", vec![data("a", vec![])]);
    let typ: ArcType<&str> = Type::record(
        vec![],
        vec![
            Field::new("x", Type::int()),
            Field::new("test", test.clone()),
            Field::new(
                "+",
                Type::function(vec![Type::int(), Type::int()], Type::int()),
            ),
        ],
    );
    let arena = Arena::new();
    let source = Source::new("");
    let printer = pretty_print::Printer::new(&arena, &source);
    let typ = arena
        .text("aaaaaaaaabbbbbbbbbbcccccccccc ")
        .append(pretty_print(&printer, &typ))
        .append(arena.newline());
    assert_eq_display!(
        format!("{}", typ.1.pretty(80)),
        r#"aaaaaaaaabbbbbbbbbbcccccccccc {
    x : Int,
    test : Test a,
    (+) : Int -> Int -> Int
}
"#
    );
}
<|endoftext|>