<commit_before>use std::mem::transmute;
use std::ptr::{read, write, swap, copy};
use std::slice::{from_raw_parts, from_raw_parts_mut};
use util::PointerExt;

pub trait Vector {
    type Item;

    #[inline]
    fn new() -> Self where Self: Sized {
        Self::with_capacity(0)
    }

    fn with_capacity(cap: usize) -> Self where Self: Sized;

    fn capacity(&self) -> usize;
    fn reserve(&mut self, additional: usize);
    fn reserve_exact(&mut self, additional: usize);
    fn shrink_to_fit(&mut self);
    fn into_boxed_slice(self) -> Box<[Self::Item]>;

    fn truncate(&mut self, len: usize) {
        let s_len = self.len();
        assert!(len <= s_len);
        let ptr = self.as_mut_ptr();

        unsafe {
            self.set_len(len);
            for i in len..s_len {
                read(ptr.uoffset(i));
            }
        }
    }

    unsafe fn set_len(&mut self, len: usize);

    fn swap_remove(&mut self, index: usize) -> Self::Item {
        let len = self.len();
        assert!(index < len);
        unsafe {
            let ptr = self.as_mut_ptr();
            let v = read(ptr.uoffset(index));
            if index != len - 1 {
                swap(ptr.uoffset(len - 1), ptr.uoffset(index));
            }
            self.set_len(len - 1);
            v
        }
    }

    fn insert(&mut self, index: usize, element: Self::Item) {
        self.reserve(1);
        unsafe {
            let len = self.len();
            let ptr = self.as_mut_ptr().uoffset(index);
            copy(ptr, ptr.uoffset(1), len - index);
            write(ptr, element);
            self.set_len(len + 1);
        }
    }

    fn remove(&mut self, index: usize) -> Self::Item {
        let len = self.len();
        assert!(index < len);
        unsafe {
            let ptr = self.as_mut_ptr().uoffset(index);
            self.set_len(len - 1);
            let v = read(ptr);
            copy(ptr.uoffset(1), ptr, len - index - 1);
            v
        }
    }

    fn retain<F: FnMut(&Self::Item) -> bool>(&mut self, mut f: F) where Self: Sized {
        let len = self.len();
        let mut del = 0;
        unsafe {
            let v = self.as_mut_ptr();

            for i in 0..len {
                if !f(transmute(v.uoffset(i) as *const _)) {
                    del += 1;
                } else if del > 0 {
                    swap(v.uoffset(i - del), v.uoffset(i));
                }
            }
        }
        if del > 0 {
            self.truncate(len - del);
        }
    }

    fn push(&mut self, value: Self::Item) {
        self.reserve(1);
        let len = self.len();
        unsafe {
            write(self.as_mut_ptr().uoffset(len), value);
            self.set_len(len + 1);
        }
    }

    fn pop(&mut self) -> Option<Self::Item> {
        let len = self.len();
        if len == 0 {
            None
        } else {
            Some(self.swap_remove(len - 1))
        }
    }

    #[inline]
    fn clear(&mut self) { self.truncate(0) }

    fn len(&self) -> usize;

    #[inline]
    fn is_empty(&self) -> bool { self.len() == 0 }

    fn push_cap(&mut self, value: Self::Item) -> Result<(), Self::Item> {
        if self.len() < self.capacity() {
            self.push(value);
            Ok(())
        } else {
            Err(value)
        }
    }

    fn insert_cap(&mut self, index: usize, element: Self::Item) -> Option<Self::Item> {
        let cap = self.capacity();

        if index >= cap {
            return Some(element);
        }

        let ret = if self.len() < cap {
            None
        } else {
            self.pop()
        };
        self.insert(index, element);
        ret
    }

    fn as_ptr(&self) -> *const Self::Item;
    fn as_mut_ptr(&mut self) -> *mut Self::Item;

    #[inline]
    fn as_slice(&self) -> &[Self::Item] {
        unsafe { from_raw_parts(self.as_ptr(), self.len()) }
    }

    #[inline]
    fn as_mut_slice(&mut self) -> &mut [Self::Item] {
        unsafe { from_raw_parts_mut(self.as_mut_ptr(), self.len()) }
    }

    unsafe fn uninitialized_resize(&mut self, new_len: usize) {
        let len = self.len();
        if new_len > len {
            self.reserve_exact(new_len - len);
        }
        self.set_len(new_len);
    }
}

impl<T> Vector for Vec<T> {
    type Item = T;

    #[inline] fn new() -> Self { Vec::new() }
    #[inline] fn with_capacity(cap: usize) -> Self { Vec::with_capacity(cap) }
    #[inline] fn capacity(&self) -> usize { Vec::capacity(self) }
    #[inline] fn reserve(&mut self, additional: usize) { Vec::reserve(self, additional) }
    #[inline] fn reserve_exact(&mut self, additional: usize) { Vec::reserve_exact(self, additional) }
    #[inline] fn shrink_to_fit(&mut self) { Vec::shrink_to_fit(self) }
    #[inline] fn into_boxed_slice(self) -> Box<[T]> { Vec::into_boxed_slice(self) }
    #[inline] fn truncate(&mut self, len: usize) { Vec::truncate(self, len) }
    #[inline] unsafe fn set_len(&mut self, len: usize) { Vec::set_len(self, len) }
    #[inline] fn swap_remove(&mut self, index: usize) -> T { Vec::swap_remove(self, index) }
    #[inline] fn insert(&mut self, index: usize, element: T) { Vec::insert(self, index, element) }
    #[inline] fn remove(&mut self, index: usize) -> T { Vec::remove(self, index) }
    #[inline] fn retain<F: FnMut(&T) -> bool>(&mut self, f: F) { Vec::retain(self, f) }
    #[inline] fn push(&mut self, value: T) { Vec::push(self, value) }
    #[inline] fn pop(&mut self) -> Option<T> { Vec::pop(self) }
    #[inline] fn clear(&mut self) { Vec::clear(self) }
    #[inline] fn len(&self) -> usize { Vec::len(self) }
    #[inline] fn is_empty(&self) -> bool { Vec::is_empty(self) }
    #[inline] fn as_ptr(&self) -> *const T { self[..].as_ptr() }
    #[inline] fn as_mut_ptr(&mut self) -> *mut T { self[..].as_mut_ptr() }
    #[inline] fn as_slice(&self) -> &[T] { &self[..] }
    #[inline] fn as_mut_slice(&mut self) -> &mut [T] { &mut self[..] }
}
<commit_msg>Add bounds check to Vector::insert<commit_after>use std::mem::transmute;
use std::ptr::{read, write, swap, copy};
use std::slice::{from_raw_parts, from_raw_parts_mut};
use util::PointerExt;

pub trait Vector {
    type Item;

    #[inline]
    fn new() -> Self where Self: Sized {
        Self::with_capacity(0)
    }

    fn with_capacity(cap: usize) -> Self where Self: Sized;

    fn capacity(&self) -> usize;
    fn reserve(&mut self, additional: usize);
    fn reserve_exact(&mut self, additional: usize);
    fn shrink_to_fit(&mut self);
    fn into_boxed_slice(self) -> Box<[Self::Item]>;

    fn truncate(&mut self, len: usize) {
        let s_len = self.len();
        assert!(len <= s_len);
        let ptr = self.as_mut_ptr();

        unsafe {
            self.set_len(len);
            for i in len..s_len {
                read(ptr.uoffset(i));
            }
        }
    }

    unsafe fn set_len(&mut self, len: usize);

    fn swap_remove(&mut self, index: usize) -> Self::Item {
        let len = self.len();
        assert!(index < len);
        unsafe {
            let ptr = self.as_mut_ptr();
            let v = read(ptr.uoffset(index));
            if index != len - 1 {
                swap(ptr.uoffset(len - 1), ptr.uoffset(index));
            }
            self.set_len(len - 1);
            v
        }
    }

    fn insert(&mut self, index: usize, element: Self::Item) {
        let len = self.len();
        assert!(index <= len);
        self.reserve(1);
        unsafe {
            let ptr = self.as_mut_ptr().uoffset(index);
            copy(ptr, ptr.uoffset(1), len - index);
            write(ptr, element);
            self.set_len(len + 1);
        }
    }

    fn remove(&mut self, index: usize) -> Self::Item {
        let len = self.len();
        assert!(index < len);
        unsafe {
            let ptr = self.as_mut_ptr().uoffset(index);
            self.set_len(len - 1);
            let v = read(ptr);
            copy(ptr.uoffset(1), ptr, len - index - 1);
            v
        }
    }

    fn retain<F: FnMut(&Self::Item) -> bool>(&mut self, mut f: F) where Self: Sized {
        let len = self.len();
        let mut del = 0;
        unsafe {
            let v = self.as_mut_ptr();

            for i in 0..len {
                if !f(transmute(v.uoffset(i) as *const _)) {
                    del += 1;
                } else if del > 0 {
                    swap(v.uoffset(i - del), v.uoffset(i));
                }
            }
        }
        if del > 0 {
            self.truncate(len - del);
        }
    }

    fn push(&mut self, value: Self::Item) {
        self.reserve(1);
        let len = self.len();
        unsafe {
            write(self.as_mut_ptr().uoffset(len), value);
            self.set_len(len + 1);
        }
    }

    fn pop(&mut self) -> Option<Self::Item> {
        let len = self.len();
        if len == 0 {
            None
        } else {
            Some(self.swap_remove(len - 1))
        }
    }

    #[inline]
    fn clear(&mut self) { self.truncate(0) }

    fn len(&self) -> usize;

    #[inline]
    fn is_empty(&self) -> bool { self.len() == 0 }

    fn push_cap(&mut self, value: Self::Item) -> Result<(), Self::Item> {
        if self.len() < self.capacity() {
            self.push(value);
            Ok(())
        } else {
            Err(value)
        }
    }

    fn insert_cap(&mut self, index: usize, element: Self::Item) -> Option<Self::Item> {
        let cap = self.capacity();

        if index >= cap {
            return Some(element);
        }

        let ret = if self.len() < cap {
            None
        } else {
            self.pop()
        };
        self.insert(index, element);
        ret
    }

    fn as_ptr(&self) -> *const Self::Item;
    fn as_mut_ptr(&mut self) -> *mut Self::Item;

    #[inline]
    fn as_slice(&self) -> &[Self::Item] {
        unsafe { from_raw_parts(self.as_ptr(), self.len()) }
    }

    #[inline]
    fn as_mut_slice(&mut self) -> &mut [Self::Item] {
        unsafe { from_raw_parts_mut(self.as_mut_ptr(), self.len()) }
    }

    unsafe fn uninitialized_resize(&mut self, new_len: usize) {
        let len = self.len();
        if new_len > len {
            self.reserve_exact(new_len - len);
        }
        self.set_len(new_len);
    }
}

impl<T> Vector for Vec<T> {
    type Item = T;

    #[inline] fn new() -> Self { Vec::new() }
    #[inline] fn with_capacity(cap: usize) -> Self { Vec::with_capacity(cap) }
    #[inline] fn capacity(&self) -> usize { Vec::capacity(self) }
    #[inline] fn reserve(&mut self, additional: usize) { Vec::reserve(self, additional) }
    #[inline] fn reserve_exact(&mut self, additional: usize) { Vec::reserve_exact(self, additional) }
    #[inline] fn shrink_to_fit(&mut self) { Vec::shrink_to_fit(self) }
    #[inline] fn into_boxed_slice(self) -> Box<[T]> { Vec::into_boxed_slice(self) }
    #[inline] fn truncate(&mut self, len: usize) { Vec::truncate(self, len) }
    #[inline] unsafe fn set_len(&mut self, len: usize) { Vec::set_len(self, len) }
    #[inline] fn swap_remove(&mut self, index: usize) -> T { Vec::swap_remove(self, index) }
    #[inline] fn insert(&mut self, index: usize, element: T) { Vec::insert(self, index, element) }
    #[inline] fn remove(&mut self, index: usize) -> T { Vec::remove(self, index) }
    #[inline] fn retain<F: FnMut(&T) -> bool>(&mut self, f: F) { Vec::retain(self, f) }
    #[inline] fn push(&mut self, value: T) { Vec::push(self, value) }
    #[inline] fn pop(&mut self) -> Option<T> { Vec::pop(self) }
    #[inline] fn clear(&mut self) { Vec::clear(self) }
    #[inline] fn len(&self) -> usize { Vec::len(self) }
    #[inline] fn is_empty(&self) -> bool { Vec::is_empty(self) }
    #[inline] fn as_ptr(&self) -> *const T { self[..].as_ptr() }
    #[inline] fn as_mut_ptr(&mut self) -> *mut T { self[..].as_mut_ptr() }
    #[inline] fn as_slice(&self) -> &[T] { &self[..] }
    #[inline] fn as_mut_slice(&mut self) -> &mut [T] { &mut self[..] }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Evcxr Authors.
//
// 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
//
//     https://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.

use crate::{code_block::CodeBlock, eval_context::ContextState};
use crate::{
    errors::{bail, CompilationError, Error},
    eval_context::Config,
};
use once_cell::sync::OnceCell;
use regex::Regex;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn shared_object_name_from_crate_name(crate_name: &str) -> String {
    if cfg!(target_os = "macos") {
        format!("lib{}.dylib", crate_name)
    } else if cfg!(target_os = "windows") {
        format!("{}.dll", crate_name)
    } else {
        format!("lib{}.so", crate_name)
    }
}

fn create_dir(dir: &Path) -> Result<(), Error> {
    if let Err(err) = fs::create_dir_all(dir) {
        bail!("Error creating directory '{:?}': {}", dir, err);
    }
    Ok(())
}

fn write_file(dir: &Path, basename: &str, contents: &str) -> Result<(), Error> {
    create_dir(dir)?;
    let filename = dir.join(basename);
    if let Err(err) = fs::write(&filename, contents) {
        bail!("Error writing '{:?}': {}", filename, err);
    }
    Ok(())
}

/// On Mac, if we copy the dylib, we get intermittent failures where we end up
/// with the previous version of the file when we shouldn't. On windows, if
/// rename the file, we get errors subsequently when something (perhaps the
/// Windows linker) tries to delete the file that it expects to still be there.
/// On Linux either renaming or copying works, but renaming should be more
/// efficient, so we do that.
#[cfg(windows)]
fn rename_or_copy_so_file(src: &Path, dest: &Path) -> Result<(), Error> {
    // Copy file by reading and writing instead of using std::fs::copy. The src
    // is a hard-linked file and we want to make extra sure that we end up with
    // a completely independent copy.
    fn alt_copy(src: &Path, dest: &Path) -> Result<(), std::io::Error> {
        use std::fs::File;
        std::io::copy(&mut File::open(src)?, &mut File::create(dest)?)?;
        Ok(())
    }
    if let Err(err) = alt_copy(src, dest) {
        bail!("Error copying '{:?}' to '{:?}': {}", src, dest, err);
    }
    Ok(())
}

#[cfg(not(windows))]
fn rename_or_copy_so_file(src: &Path, dest: &Path) -> Result<(), Error> {
    if let Err(err) = fs::rename(src, dest) {
        bail!("Error renaming '{:?}' to '{:?}': {}", src, dest, err);
    }
    Ok(())
}

pub(crate) struct Module {
    pub(crate) tmpdir: PathBuf,
    build_num: i32,
    target: String,
}

const CRATE_NAME: &str = "ctx";

impl Module {
    pub(crate) fn new(tmpdir: PathBuf) -> Result<Module, Error> {
        let module = Module {
            tmpdir,
            build_num: 0,
            target: get_host_target()?,
        };
        Ok(module)
    }

    pub(crate) fn deps_dir(&self) -> PathBuf {
        self.target_dir().join("debug").join("deps")
    }

    fn target_dir(&self) -> PathBuf {
        self.tmpdir.join("target").join(&self.target)
    }

    fn so_path(&self) -> PathBuf {
        self.deps_dir()
            .join(shared_object_name_from_crate_name(CRATE_NAME))
    }

    fn src_dir(&self) -> PathBuf {
        self.tmpdir.join("src")
    }

    pub(crate) fn crate_dir(&self) -> &Path {
        &self.tmpdir
    }

    pub fn last_source(&self) -> Result<String, std::io::Error> {
        std::fs::read_to_string(self.src_dir().join("lib.rs"))
    }

    // Writes Cargo.toml. Should be called before compile.
    pub(crate) fn write_cargo_toml(&self, state: &ContextState) -> Result<(), Error> {
        write_file(
            self.crate_dir(),
            "Cargo.toml",
            &self.get_cargo_toml_contents(state),
        )
    }

    pub(crate) fn check(
        &mut self,
        code_block: &CodeBlock,
        config: &Config,
    ) -> Result<Vec<CompilationError>, Error> {
        self.write_code(code_block)?;
        let output = config
            .cargo_command("check")
            .arg("--message-format=json")
            .output();

        let cargo_output = match output {
            Ok(out) => out,
            Err(err) => bail!("Error running 'cargo check': {}", err),
        };
        let (errors, _non_json_error) = errors_from_cargo_output(&cargo_output, code_block);
        Ok(errors)
    }

    pub(crate) fn compile(
        &mut self,
        code_block: &CodeBlock,
        config: &Config,
    ) -> Result<SoFile, Error> {
        let mut command = config.cargo_command("rustc");
        if config.time_passes && config.toolchain != "nightly" {
            bail!("time_passes option requires nightly compiler");
        }

        command
            .arg("--target")
            .arg(&self.target)
            .arg("--message-format=json")
            .arg("--")
            .arg("-C")
            .arg("prefer-dynamic")
            .env("CARGO_TARGET_DIR", "target");
        if config.linker == "lld" {
            command
                .arg("-C")
                .arg(format!("link-arg=-fuse-ld={}", config.linker));
        }
        if let Some(sccache) = &config.sccache {
            command.env("RUSTC_WRAPPER", sccache);
        }
        if config.time_passes {
            command.arg("-Ztime-passes");
        }
        self.write_code(code_block)?;
        let cargo_output = run_cargo(command, code_block)?;
        if config.time_passes {
            let stdout = String::from_utf8_lossy(&cargo_output.stdout);
            eprintln!("{}", stdout);
        }
        self.build_num += 1;
        let copied_so_file = self
            .deps_dir()
            .join(shared_object_name_from_crate_name(&format!(
                "code_{}",
                self.build_num
            )));
        // Every time we compile, the output file is the same. We need to
        // renamed it so that we have a unique filename, otherwise we wouldn't
        // be able to load the result of the next compilation. Also, on Windows,
        // a loaded dll gets locked, so we couldn't even compile a second time
        // if we didn't load a different file.
        rename_or_copy_so_file(&self.so_path(), &copied_so_file)?;
        Ok(SoFile {
            path: copied_so_file,
        })
    }

    fn write_code(&self, code_block: &CodeBlock) -> Result<(), Error> {
        write_file(&self.src_dir(), "lib.rs", &code_block.code_string())?;
        self.maybe_bump_lib_mtime();
        Ok(())
    }

    #[cfg(not(target_os = "macos"))]
    fn maybe_bump_lib_mtime(&self) {}

    #[cfg(target_os = "macos")]
    fn maybe_bump_lib_mtime(&self) {
        // Some Macs use a filesystem that only has 1 second precision on file modification
        // timestamps. Cargo uses these timestamps to see if it needs to recompile things, otherwise
        // it just reuses the previous output. We set the modification timestamp on our source file
        // to be 10 seconds in the future. That way it's guaranteed to be newer than any outputs
        // produced by previous runs. In the event that setting the mtime fails, we just ignore it,
        // as this mostly affects tests and we don't want inability to set mtime to break things for
        // users.
        let _ = filetime::set_file_mtime(
            self.src_dir().join("lib.rs"),
            filetime::FileTime::from_unix_time(filetime::FileTime::now().unix_seconds() + 10, 0),
        );
    }

    fn get_cargo_toml_contents(&self, state: &ContextState) -> String {
        let crate_imports = state.format_cargo_deps();
        format!(
            r#"
[package]
name = "{}"
version = "1.0.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]
path = "src/lib.rs"

[profile.dev]
opt-level = {}
debug = false
rpath = true
lto = false
debug-assertions = true
codegen-units = 16
panic = 'unwind'
incremental = true
overflow-checks = true

[dependencies]
{}
"#,
            CRATE_NAME,
            state.opt_level(),
            crate_imports
        )
    }
}

fn run_cargo(
    mut command: std::process::Command,
    code_block: &CodeBlock,
) -> Result<std::process::Output, Error> {
    let cargo_output = match command.output() {
        Ok(out) => out,
        Err(err) => bail!("Error running 'cargo rustc': {}", err),
    };
    if cargo_output.status.success() {
        Ok(cargo_output)
    } else {
        let (errors, non_json_error) = errors_from_cargo_output(&cargo_output, code_block);
        if errors.is_empty() {
            if let Some(error) = non_json_error {
                bail!(Error::Message(error));
            } else {
                bail!(Error::Message(format!(
                    "Compilation failed, but no parsable errors were found. STDERR:\n\
                     {}\nSTDOUT:{}\n",
                    String::from_utf8_lossy(&cargo_output.stderr),
                    String::from_utf8_lossy(&cargo_output.stdout)
                )));
            }
        } else {
            bail!(Error::CompilationErrors(errors));
        }
    }
}

fn errors_from_cargo_output(
    cargo_output: &std::process::Output,
    code_block: &CodeBlock,
) -> (Vec<CompilationError>, Option<String>) {
    // Our compiler errors should all be in JSON format, but for errors from
    // Cargo errors, we need to add explicit matching for those errors that we
    // expect we might see.
    static KNOWN_NON_JSON_ERRORS: OnceCell<Regex> = OnceCell::new();
    let known_non_json_errors = KNOWN_NON_JSON_ERRORS
        .get_or_init(|| Regex::new("(error: no matching package named)").unwrap());

    let stderr = String::from_utf8_lossy(&cargo_output.stderr);
    let stdout = String::from_utf8_lossy(&cargo_output.stdout);
    let mut non_json_error = None;
    let errors = stderr
        .lines()
        .chain(stdout.lines())
        .filter_map(|line| {
            json::parse(line)
                .ok()
                .and_then(|json| CompilationError::opt_new(json, code_block))
                .or_else(|| {
                    if known_non_json_errors.is_match(line) {
                        non_json_error = Some(line.to_owned());
                    }
                    None
                })
        })
        .collect();
    (errors, non_json_error)
}

pub(crate) struct SoFile {
    pub(crate) path: PathBuf,
}

fn get_host_target() -> Result<String, Error> {
    let output = match Command::new("rustc").arg("-Vv").output() {
        Ok(o) => o,
        Err(error) => bail!("Failed to run rustc: {}", error),
    };
    let stdout = std::str::from_utf8(&output.stdout)?;
    let stderr = std::str::from_utf8(&output.stderr)?;
    for line in stdout.lines() {
        if let Some(host) = line.strip_prefix("host: ") {
            return Ok(host.to_owned());
        }
    }
    bail!(
        "rustc -Vv didn't output a host line.\n{}\n{}",
        stdout,
        stderr
    );
}
<commit_msg>Fix :time_passes command<commit_after>// Copyright 2020 The Evcxr Authors.
//
// 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
//
//     https://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.

use crate::{code_block::CodeBlock, eval_context::ContextState};
use crate::{
    errors::{bail, CompilationError, Error},
    eval_context::Config,
};
use once_cell::sync::OnceCell;
use regex::Regex;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

fn shared_object_name_from_crate_name(crate_name: &str) -> String {
    if cfg!(target_os = "macos") {
        format!("lib{}.dylib", crate_name)
    } else if cfg!(target_os = "windows") {
        format!("{}.dll", crate_name)
    } else {
        format!("lib{}.so", crate_name)
    }
}

fn create_dir(dir: &Path) -> Result<(), Error> {
    if let Err(err) = fs::create_dir_all(dir) {
        bail!("Error creating directory '{:?}': {}", dir, err);
    }
    Ok(())
}

fn write_file(dir: &Path, basename: &str, contents: &str) -> Result<(), Error> {
    create_dir(dir)?;
    let filename = dir.join(basename);
    if let Err(err) = fs::write(&filename, contents) {
        bail!("Error writing '{:?}': {}", filename, err);
    }
    Ok(())
}

/// On Mac, if we copy the dylib, we get intermittent failures where we end up
/// with the previous version of the file when we shouldn't. On windows, if
/// rename the file, we get errors subsequently when something (perhaps the
/// Windows linker) tries to delete the file that it expects to still be there.
/// On Linux either renaming or copying works, but renaming should be more
/// efficient, so we do that.
#[cfg(windows)]
fn rename_or_copy_so_file(src: &Path, dest: &Path) -> Result<(), Error> {
    // Copy file by reading and writing instead of using std::fs::copy. The src
    // is a hard-linked file and we want to make extra sure that we end up with
    // a completely independent copy.
    fn alt_copy(src: &Path, dest: &Path) -> Result<(), std::io::Error> {
        use std::fs::File;
        std::io::copy(&mut File::open(src)?, &mut File::create(dest)?)?;
        Ok(())
    }
    if let Err(err) = alt_copy(src, dest) {
        bail!("Error copying '{:?}' to '{:?}': {}", src, dest, err);
    }
    Ok(())
}

#[cfg(not(windows))]
fn rename_or_copy_so_file(src: &Path, dest: &Path) -> Result<(), Error> {
    if let Err(err) = fs::rename(src, dest) {
        bail!("Error renaming '{:?}' to '{:?}': {}", src, dest, err);
    }
    Ok(())
}

pub(crate) struct Module {
    pub(crate) tmpdir: PathBuf,
    build_num: i32,
    target: String,
}

const CRATE_NAME: &str = "ctx";

impl Module {
    pub(crate) fn new(tmpdir: PathBuf) -> Result<Module, Error> {
        let module = Module {
            tmpdir,
            build_num: 0,
            target: get_host_target()?,
        };
        Ok(module)
    }

    pub(crate) fn deps_dir(&self) -> PathBuf {
        self.target_dir().join("debug").join("deps")
    }

    fn target_dir(&self) -> PathBuf {
        self.tmpdir.join("target").join(&self.target)
    }

    fn so_path(&self) -> PathBuf {
        self.deps_dir()
            .join(shared_object_name_from_crate_name(CRATE_NAME))
    }

    fn src_dir(&self) -> PathBuf {
        self.tmpdir.join("src")
    }

    pub(crate) fn crate_dir(&self) -> &Path {
        &self.tmpdir
    }

    pub fn last_source(&self) -> Result<String, std::io::Error> {
        std::fs::read_to_string(self.src_dir().join("lib.rs"))
    }

    // Writes Cargo.toml. Should be called before compile.
    pub(crate) fn write_cargo_toml(&self, state: &ContextState) -> Result<(), Error> {
        write_file(
            self.crate_dir(),
            "Cargo.toml",
            &self.get_cargo_toml_contents(state),
        )
    }

    pub(crate) fn check(
        &mut self,
        code_block: &CodeBlock,
        config: &Config,
    ) -> Result<Vec<CompilationError>, Error> {
        self.write_code(code_block)?;
        let output = config
            .cargo_command("check")
            .arg("--message-format=json")
            .output();

        let cargo_output = match output {
            Ok(out) => out,
            Err(err) => bail!("Error running 'cargo check': {}", err),
        };
        let (errors, _non_json_error) = errors_from_cargo_output(&cargo_output, code_block);
        Ok(errors)
    }

    pub(crate) fn compile(
        &mut self,
        code_block: &CodeBlock,
        config: &Config,
    ) -> Result<SoFile, Error> {
        let mut command = config.cargo_command("rustc");
        if config.time_passes && config.toolchain != "nightly" {
            bail!("time_passes option requires nightly compiler");
        }

        command
            .arg("--target")
            .arg(&self.target)
            .arg("--message-format=json")
            .arg("--")
            .arg("-C")
            .arg("prefer-dynamic")
            .env("CARGO_TARGET_DIR", "target");
        if config.linker == "lld" {
            command
                .arg("-C")
                .arg(format!("link-arg=-fuse-ld={}", config.linker));
        }
        if let Some(sccache) = &config.sccache {
            command.env("RUSTC_WRAPPER", sccache);
        }
        if config.time_passes {
            command.arg("-Ztime-passes");
        }
        self.write_code(code_block)?;
        let cargo_output = run_cargo(command, code_block)?;
        if config.time_passes {
            let output = String::from_utf8_lossy(&cargo_output.stderr);
            eprintln!("{}", output);
        }
        self.build_num += 1;
        let copied_so_file = self
            .deps_dir()
            .join(shared_object_name_from_crate_name(&format!(
                "code_{}",
                self.build_num
            )));
        // Every time we compile, the output file is the same. We need to
        // renamed it so that we have a unique filename, otherwise we wouldn't
        // be able to load the result of the next compilation. Also, on Windows,
        // a loaded dll gets locked, so we couldn't even compile a second time
        // if we didn't load a different file.
        rename_or_copy_so_file(&self.so_path(), &copied_so_file)?;
        Ok(SoFile {
            path: copied_so_file,
        })
    }

    fn write_code(&self, code_block: &CodeBlock) -> Result<(), Error> {
        write_file(&self.src_dir(), "lib.rs", &code_block.code_string())?;
        self.maybe_bump_lib_mtime();
        Ok(())
    }

    #[cfg(not(target_os = "macos"))]
    fn maybe_bump_lib_mtime(&self) {}

    #[cfg(target_os = "macos")]
    fn maybe_bump_lib_mtime(&self) {
        // Some Macs use a filesystem that only has 1 second precision on file modification
        // timestamps. Cargo uses these timestamps to see if it needs to recompile things, otherwise
        // it just reuses the previous output. We set the modification timestamp on our source file
        // to be 10 seconds in the future. That way it's guaranteed to be newer than any outputs
        // produced by previous runs. In the event that setting the mtime fails, we just ignore it,
        // as this mostly affects tests and we don't want inability to set mtime to break things for
        // users.
        let _ = filetime::set_file_mtime(
            self.src_dir().join("lib.rs"),
            filetime::FileTime::from_unix_time(filetime::FileTime::now().unix_seconds() + 10, 0),
        );
    }

    fn get_cargo_toml_contents(&self, state: &ContextState) -> String {
        let crate_imports = state.format_cargo_deps();
        format!(
            r#"
[package]
name = "{}"
version = "1.0.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]
path = "src/lib.rs"

[profile.dev]
opt-level = {}
debug = false
rpath = true
lto = false
debug-assertions = true
codegen-units = 16
panic = 'unwind'
incremental = true
overflow-checks = true

[dependencies]
{}
"#,
            CRATE_NAME,
            state.opt_level(),
            crate_imports
        )
    }
}

fn run_cargo(
    mut command: std::process::Command,
    code_block: &CodeBlock,
) -> Result<std::process::Output, Error> {
    let cargo_output = match command.output() {
        Ok(out) => out,
        Err(err) => bail!("Error running 'cargo rustc': {}", err),
    };
    if cargo_output.status.success() {
        Ok(cargo_output)
    } else {
        let (errors, non_json_error) = errors_from_cargo_output(&cargo_output, code_block);
        if errors.is_empty() {
            if let Some(error) = non_json_error {
                bail!(Error::Message(error));
            } else {
                bail!(Error::Message(format!(
                    "Compilation failed, but no parsable errors were found. STDERR:\n\
                     {}\nSTDOUT:{}\n",
                    String::from_utf8_lossy(&cargo_output.stderr),
                    String::from_utf8_lossy(&cargo_output.stdout)
                )));
            }
        } else {
            bail!(Error::CompilationErrors(errors));
        }
    }
}

fn errors_from_cargo_output(
    cargo_output: &std::process::Output,
    code_block: &CodeBlock,
) -> (Vec<CompilationError>, Option<String>) {
    // Our compiler errors should all be in JSON format, but for errors from
    // Cargo errors, we need to add explicit matching for those errors that we
    // expect we might see.
    static KNOWN_NON_JSON_ERRORS: OnceCell<Regex> = OnceCell::new();
    let known_non_json_errors = KNOWN_NON_JSON_ERRORS
        .get_or_init(|| Regex::new("(error: no matching package named)").unwrap());

    let stderr = String::from_utf8_lossy(&cargo_output.stderr);
    let stdout = String::from_utf8_lossy(&cargo_output.stdout);
    let mut non_json_error = None;
    let errors = stderr
        .lines()
        .chain(stdout.lines())
        .filter_map(|line| {
            json::parse(line)
                .ok()
                .and_then(|json| CompilationError::opt_new(json, code_block))
                .or_else(|| {
                    if known_non_json_errors.is_match(line) {
                        non_json_error = Some(line.to_owned());
                    }
                    None
                })
        })
        .collect();
    (errors, non_json_error)
}

pub(crate) struct SoFile {
    pub(crate) path: PathBuf,
}

fn get_host_target() -> Result<String, Error> {
    let output = match Command::new("rustc").arg("-Vv").output() {
        Ok(o) => o,
        Err(error) => bail!("Failed to run rustc: {}", error),
    };
    let stdout = std::str::from_utf8(&output.stdout)?;
    let stderr = std::str::from_utf8(&output.stderr)?;
    for line in stdout.lines() {
        if let Some(host) = line.strip_prefix("host: ") {
            return Ok(host.to_owned());
        }
    }
    bail!(
        "rustc -Vv didn't output a host line.\n{}\n{}",
        stdout,
        stderr
    );
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// 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.
use std::convert::From;
use std::fmt::{self, Display};
use std::ops::Deref;
use std::sync::Mutex;

use gl;
use glutin;

/// Resize handling for Mac and maybe other platforms
///
/// This delegates to a statically referenced closure for convenience. The
/// C-style callback doesn't receive a pointer or anything, so we are forced to
/// use static storage.
///
/// This will fail horribly if more than one window is created. Don't do that :)
fn window_resize_handler(width: u32, height: u32) {
        RESIZE_CALLBACK.lock().unwrap().as_ref().map(|func| (*func)(width, height));
}

lazy_static! {
    /// The resize callback invoked by `window_resize_handler`
   static ref RESIZE_CALLBACK: Mutex<Option<Box<Fn(u32, u32) + 'static + Send>>> = Mutex::new(None);
}

/// Window errors
#[derive(Debug)]
pub enum Error {
    /// Error creating the window
    Creation(glutin::CreationError),

    /// Error manipulating the rendering context
    Context(glutin::ContextError),
}

/// Result of fallible operations concerning a Window.
type Result<T> = ::std::result::Result<T, Error>;

/// A window which can be used for displaying the terminal
///
/// Wraps the underlying windowing library to provide a stable API in Alacritty
pub struct Window {
    glutin_window: glutin::Window,
    cursor_visible: bool,
}

/// Threadsafe APIs for the window
pub struct Proxy {
    inner: glutin::WindowProxy,
}

/// Information about where the window is being displayed
///
/// Useful for subsystems like the font rasterized which depend on DPI and scale
/// factor.
pub struct DeviceProperties {
    /// Scale factor for pixels <-> points.
    ///
    /// This will be 1. on standard displays and may have a different value on
    /// hidpi displays.
    pub scale_factor: f32,
}

/// Size of the window
#[derive(Debug, Copy, Clone)]
pub struct Size<T> {
    pub width: T,
    pub height: T,
}

/// Strongly typed Pixels unit
#[derive(Debug, Copy, Clone)]
pub struct Pixels<T>(pub T);

/// Strongly typed Points unit
///
/// Points are like pixels but adjusted for DPI.
#[derive(Debug, Copy, Clone)]
pub struct Points<T>(pub T);

pub trait ToPoints {
    fn to_points(&self, scale: f32) -> Size<Points<u32>>;
}

impl ToPoints for Size<Points<u32>> {
    #[inline]
    fn to_points(&self, _scale: f32) -> Size<Points<u32>> {
        *self
    }
}

impl ToPoints for Size<Pixels<u32>> {
    fn to_points(&self, scale: f32) -> Size<Points<u32>> {
        let width_pts = (*self.width as f32 / scale) as u32;
        let height_pts = (*self.height as f32 / scale) as u32;

        Size {
            width: Points(width_pts),
            height: Points(height_pts)
        }
    }
}

impl<T: Display> Display for Size<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} × {}", self.width, self.height)
    }
}

macro_rules! deref_newtype {
    ($($src:ty),+) => {
        $(
        impl<T> Deref for $src {
            type Target = T;

            #[inline]
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        )+
    }
}

deref_newtype! { Points<T>, Pixels<T> }

impl<T: Display> Display for Pixels<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.0)
    }
}

impl<T: Display> Display for Points<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}pts", self.0)
    }
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Creation(ref err) => Some(err),
            Error::Context(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::Creation(ref _err) => "Error creating glutin Window",
            Error::Context(ref _err) => "Error operating on render context",
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Creation(ref err) => {
                write!(f, "Error creating glutin::Window; {}", err)
            },
            Error::Context(ref err) => {
                write!(f, "Error operating on render context; {}", err)
            },
        }
    }
}

impl From<glutin::CreationError> for Error {
    fn from(val: glutin::CreationError) -> Error {
        Error::Creation(val)
    }
}

impl From<glutin::ContextError> for Error {
    fn from(val: glutin::ContextError) -> Error {
        Error::Context(val)
    }
}

impl Window {
    /// Create a new window
    ///
    /// This creates a window and fully initializes a window.
    pub fn new(
        title: &str
    ) -> Result<Window> {
        /// Create a glutin::Window
        let mut window = glutin::WindowBuilder::new()
            .with_vsync()
            .with_title(title)
            .build()?;

        /// Set the glutin window resize callback for *this* window. The
        /// function pointer must be a C-style callback. This sets such a
        /// callback which simply delegates to a statically referenced Rust
        /// closure.
        window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

        /// Set OpenGL symbol loader
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

        /// Make the window's context current so OpenGL operations can run
        unsafe {
            window.make_current()?;
        }

        Ok(Window {
            glutin_window: window,
            cursor_visible: true,
        })
    }

    /// Get some properties about the device
    ///
    /// Some window properties are provided since subsystems like font
    /// rasterization depend on DPI and scale factor.
    pub fn device_properties(&self) -> DeviceProperties {
        DeviceProperties {
            scale_factor: self.glutin_window.hidpi_factor(),
        }
    }

    /// Set the window resize callback
    ///
    /// Pass a `move` closure which will be called with the new width and height
    /// when the window is resized. According to the glutin docs, this can be
    /// used to draw during resizing.
    ///
    /// This method takes self mutably to ensure there's no race condition
    /// setting the callback.
    pub fn set_resize_callback<F: Fn(u32, u32) + 'static + Send>(&mut self, func: F) {
        let mut guard = RESIZE_CALLBACK.lock().unwrap();
        *guard = Some(Box::new(func));
    }

    pub fn inner_size_pixels(&self) -> Option<Size<Pixels<u32>>> {
        self.glutin_window
            .get_inner_size_pixels()
            .map(|(w, h)| Size { width: Pixels(w), height: Pixels(h) })
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        self.glutin_window.hidpi_factor()
    }

    #[inline]
    pub fn create_window_proxy(&self) -> Proxy {
        Proxy {
            inner: self.glutin_window.create_window_proxy(),
        }
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<()> {
        self.glutin_window
            .swap_buffers()
            .map_err(From::from)
    }

    /// Poll for any available events
    #[inline]
    pub fn poll_events(&self) -> glutin::PollEventsIterator {
        self.glutin_window.poll_events()
    }

    /// Block waiting for events
    ///
    /// FIXME should return our own type
    #[inline]
    pub fn wait_events(&self) -> glutin::WaitEventsIterator {
        self.glutin_window.wait_events()
    }

    /// Set the window title
    #[inline]
    pub fn set_title(&self, title: &str) {
        self.glutin_window.set_title(title);
    }

    /// Set cursor visible
    pub fn set_cursor_visible(&mut self, visible: bool) {
        if visible != self.cursor_visible {
            self.cursor_visible = visible;
            self.glutin_window.set_cursor(if visible { glutin::MouseCursor::Default }
                                          else { glutin::MouseCursor::NoneCursor });
        }
    }
}

impl Proxy {
    /// Wakes up the event loop of the window
    ///
    /// This is useful for triggering a draw when the renderer would otherwise
    /// be waiting on user input.
    pub fn wakeup_event_loop(&self) {
        self.inner.wakeup_event_loop();
    }
}

pub trait SetInnerSize<T> {
    fn set_inner_size<S: ToPoints>(&mut self, size: S);
}

impl SetInnerSize<Pixels<u32>> for Window {
    fn set_inner_size<T: ToPoints>(&mut self, size: T) {
        let size = size.to_points(self.hidpi_factor());
        self.glutin_window.set_inner_size(*size.width as _, *size.height as _);
    }
}
<commit_msg>hide mouse cursor mac os<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// 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.
use std::convert::From;
use std::fmt::{self, Display};
use std::ops::Deref;
use std::sync::Mutex;

use gl;
use glutin;

/// Resize handling for Mac and maybe other platforms
///
/// This delegates to a statically referenced closure for convenience. The
/// C-style callback doesn't receive a pointer or anything, so we are forced to
/// use static storage.
///
/// This will fail horribly if more than one window is created. Don't do that :)
fn window_resize_handler(width: u32, height: u32) {
        RESIZE_CALLBACK.lock().unwrap().as_ref().map(|func| (*func)(width, height));
}

lazy_static! {
    /// The resize callback invoked by `window_resize_handler`
   static ref RESIZE_CALLBACK: Mutex<Option<Box<Fn(u32, u32) + 'static + Send>>> = Mutex::new(None);
}

/// Window errors
#[derive(Debug)]
pub enum Error {
    /// Error creating the window
    Creation(glutin::CreationError),

    /// Error manipulating the rendering context
    Context(glutin::ContextError),
}

/// Result of fallible operations concerning a Window.
type Result<T> = ::std::result::Result<T, Error>;

/// A window which can be used for displaying the terminal
///
/// Wraps the underlying windowing library to provide a stable API in Alacritty
pub struct Window {
    glutin_window: glutin::Window,
    cursor_visible: bool,
}

/// Threadsafe APIs for the window
pub struct Proxy {
    inner: glutin::WindowProxy,
}

/// Information about where the window is being displayed
///
/// Useful for subsystems like the font rasterized which depend on DPI and scale
/// factor.
pub struct DeviceProperties {
    /// Scale factor for pixels <-> points.
    ///
    /// This will be 1. on standard displays and may have a different value on
    /// hidpi displays.
    pub scale_factor: f32,
}

/// Size of the window
#[derive(Debug, Copy, Clone)]
pub struct Size<T> {
    pub width: T,
    pub height: T,
}

/// Strongly typed Pixels unit
#[derive(Debug, Copy, Clone)]
pub struct Pixels<T>(pub T);

/// Strongly typed Points unit
///
/// Points are like pixels but adjusted for DPI.
#[derive(Debug, Copy, Clone)]
pub struct Points<T>(pub T);

pub trait ToPoints {
    fn to_points(&self, scale: f32) -> Size<Points<u32>>;
}

impl ToPoints for Size<Points<u32>> {
    #[inline]
    fn to_points(&self, _scale: f32) -> Size<Points<u32>> {
        *self
    }
}

impl ToPoints for Size<Pixels<u32>> {
    fn to_points(&self, scale: f32) -> Size<Points<u32>> {
        let width_pts = (*self.width as f32 / scale) as u32;
        let height_pts = (*self.height as f32 / scale) as u32;

        Size {
            width: Points(width_pts),
            height: Points(height_pts)
        }
    }
}

impl<T: Display> Display for Size<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} × {}", self.width, self.height)
    }
}

macro_rules! deref_newtype {
    ($($src:ty),+) => {
        $(
        impl<T> Deref for $src {
            type Target = T;

            #[inline]
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
        )+
    }
}

deref_newtype! { Points<T>, Pixels<T> }

impl<T: Display> Display for Pixels<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}px", self.0)
    }
}

impl<T: Display> Display for Points<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}pts", self.0)
    }
}

impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&::std::error::Error> {
        match *self {
            Error::Creation(ref err) => Some(err),
            Error::Context(ref err) => Some(err),
        }
    }

    fn description(&self) -> &str {
        match *self {
            Error::Creation(ref _err) => "Error creating glutin Window",
            Error::Context(ref _err) => "Error operating on render context",
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Error::Creation(ref err) => {
                write!(f, "Error creating glutin::Window; {}", err)
            },
            Error::Context(ref err) => {
                write!(f, "Error operating on render context; {}", err)
            },
        }
    }
}

impl From<glutin::CreationError> for Error {
    fn from(val: glutin::CreationError) -> Error {
        Error::Creation(val)
    }
}

impl From<glutin::ContextError> for Error {
    fn from(val: glutin::ContextError) -> Error {
        Error::Context(val)
    }
}

impl Window {
    /// Create a new window
    ///
    /// This creates a window and fully initializes a window.
    pub fn new(
        title: &str
    ) -> Result<Window> {
        /// Create a glutin::Window
        let mut window = glutin::WindowBuilder::new()
            .with_vsync()
            .with_title(title)
            .build()?;

        /// Set the glutin window resize callback for *this* window. The
        /// function pointer must be a C-style callback. This sets such a
        /// callback which simply delegates to a statically referenced Rust
        /// closure.
        window.set_window_resize_callback(Some(window_resize_handler as fn(u32, u32)));

        /// Set OpenGL symbol loader
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

        /// Make the window's context current so OpenGL operations can run
        unsafe {
            window.make_current()?;
        }

        Ok(Window {
            glutin_window: window,
            cursor_visible: true,
        })
    }

    /// Get some properties about the device
    ///
    /// Some window properties are provided since subsystems like font
    /// rasterization depend on DPI and scale factor.
    pub fn device_properties(&self) -> DeviceProperties {
        DeviceProperties {
            scale_factor: self.glutin_window.hidpi_factor(),
        }
    }

    /// Set the window resize callback
    ///
    /// Pass a `move` closure which will be called with the new width and height
    /// when the window is resized. According to the glutin docs, this can be
    /// used to draw during resizing.
    ///
    /// This method takes self mutably to ensure there's no race condition
    /// setting the callback.
    pub fn set_resize_callback<F: Fn(u32, u32) + 'static + Send>(&mut self, func: F) {
        let mut guard = RESIZE_CALLBACK.lock().unwrap();
        *guard = Some(Box::new(func));
    }

    pub fn inner_size_pixels(&self) -> Option<Size<Pixels<u32>>> {
        self.glutin_window
            .get_inner_size_pixels()
            .map(|(w, h)| Size { width: Pixels(w), height: Pixels(h) })
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        self.glutin_window.hidpi_factor()
    }

    #[inline]
    pub fn create_window_proxy(&self) -> Proxy {
        Proxy {
            inner: self.glutin_window.create_window_proxy(),
        }
    }

    #[inline]
    pub fn swap_buffers(&self) -> Result<()> {
        self.glutin_window
            .swap_buffers()
            .map_err(From::from)
    }

    /// Poll for any available events
    #[inline]
    pub fn poll_events(&self) -> glutin::PollEventsIterator {
        self.glutin_window.poll_events()
    }

    /// Block waiting for events
    ///
    /// FIXME should return our own type
    #[inline]
    pub fn wait_events(&self) -> glutin::WaitEventsIterator {
        self.glutin_window.wait_events()
    }

    /// Set the window title
    #[inline]
    pub fn set_title(&self, title: &str) {
        self.glutin_window.set_title(title);
    }

    /// Set cursor visible
    pub fn set_cursor_visible(&mut self, visible: bool) {
        if visible != self.cursor_visible {
            self.cursor_visible = visible;
            self.glutin_window.set_cursor_state(if visible { glutin::CursorState::Normal }
                                                else { glutin::CursorState::Hide }).unwrap();
        }
    }
}

impl Proxy {
    /// Wakes up the event loop of the window
    ///
    /// This is useful for triggering a draw when the renderer would otherwise
    /// be waiting on user input.
    pub fn wakeup_event_loop(&self) {
        self.inner.wakeup_event_loop();
    }
}

pub trait SetInnerSize<T> {
    fn set_inner_size<S: ToPoints>(&mut self, size: S);
}

impl SetInnerSize<Pixels<u32>> for Window {
    fn set_inner_size<T: ToPoints>(&mut self, size: T) {
        let size = size.to_points(self.hidpi_factor());
        self.glutin_window.set_inner_size(*size.width as _, *size.height as _);
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use xcb;
use cairo::{self, Context, XCBSurface};
use cairo_sys;

use text::{Color, Text};

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

// TODO: impl Drop?
pub struct Window {
    conn: Rc<xcb::Connection>,
    screen_idx: usize,
    surface: cairo::Surface,
}

impl Window {
    pub fn new(conn: Rc<xcb::Connection>, screen_idx: usize) -> Window {
        let id = conn.generate_id();

        let surface =
            {
                let screen = conn.get_setup()
                    .roots()
                    .nth(screen_idx)
                    .expect("invalid screen");
                let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                              (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

                let (width, height) = (screen.width_in_pixels(), 100);

                xcb::create_window(&conn,
                                   xcb::COPY_FROM_PARENT as u8,
                                   id,
                                   screen.root(),
                                   0,
                                   0,
                                   width,
                                   height,
                                   10,
                                   xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                                   screen.root_visual(),
                                   &values);

                unsafe {
                    let cairo_conn =
                        cairo::XCBConnection::from_raw_none(conn.get_raw_conn() as
                                                            *mut cairo_sys::xcb_connection_t);
                    let visual =
                        cairo::XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn,
                                                                                &screen)
                                                                         .base as
                                                            *mut xcb::ffi::xcb_visualtype_t as
                                                            *mut cairo_sys::xcb_visualtype_t);
                    let drawable = cairo::XCBDrawable(id);
                    cairo::Surface::create(&cairo_conn,
                                           &drawable,
                                           &visual,
                                           width as i32,
                                           height as i32)
                    // TODO: Update surface width/height when window size changes.
                }
            };

        xcb::map_window(&conn, id);
        conn.flush();

        Window {
            conn,
            screen_idx,
            surface,
        }
    }

    fn screen(&self) -> xcb::Screen {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    pub fn expose(&self, texts: Vec<Text>) {
        // Clear to black before re-painting.
        let context = Context::new(&self.surface);
        Color::black().apply_to_context(&context);
        context.paint();

        self.render_text_blocks(texts);
        self.conn.flush();
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in &mut layouts {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in &mut stretched {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }
}
<commit_msg>cargo fmt<commit_after>use std::rc::Rc;

use xcb;
use cairo::{self, Context, XCBSurface};
use cairo_sys;

use text::{Color, Text};

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

// TODO: impl Drop?
pub struct Window {
    conn: Rc<xcb::Connection>,
    screen_idx: usize,
    surface: cairo::Surface,
}

impl Window {
    pub fn new(conn: Rc<xcb::Connection>, screen_idx: usize) -> Window {
        let id = conn.generate_id();

        let surface = {
            let screen = conn.get_setup()
                .roots()
                .nth(screen_idx)
                .expect("invalid screen");
            let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                          (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

            let (width, height) = (screen.width_in_pixels(), 100);

            xcb::create_window(&conn,
                               xcb::COPY_FROM_PARENT as u8,
                               id,
                               screen.root(),
                               0,
                               0,
                               width,
                               height,
                               10,
                               xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                               screen.root_visual(),
                               &values);

            unsafe {
                let cairo_conn =
                    cairo::XCBConnection::from_raw_none(conn.get_raw_conn() as
                                                        *mut cairo_sys::xcb_connection_t);
                let visual =
                        cairo::XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn,
                                                                                &screen)
                                                                         .base as
                                                            *mut xcb::ffi::xcb_visualtype_t as
                                                            *mut cairo_sys::xcb_visualtype_t);
                let drawable = cairo::XCBDrawable(id);
                cairo::Surface::create(&cairo_conn, &drawable, &visual, width as i32, height as i32)
                // TODO: Update surface width/height when window size changes.
            }
        };

        xcb::map_window(&conn, id);
        conn.flush();

        Window {
            conn,
            screen_idx,
            surface,
        }
    }

    fn screen(&self) -> xcb::Screen {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    pub fn expose(&self, texts: Vec<Text>) {
        // Clear to black before re-painting.
        let context = Context::new(&self.surface);
        Color::black().apply_to_context(&context);
        context.paint();

        self.render_text_blocks(texts);
        self.conn.flush();
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in &mut layouts {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in &mut stretched {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }
}
<|endoftext|>


<commit_before>use std;

fn main() {

    obj a() {
        fn foo() -> int {
            ret 2;
        }
        fn bar() -> int {
            ret self.foo();
        }
    }

    auto my_a = a();

    auto my_b = obj {
        fn baz() -> int {
            ret self.foo();
        }
        with my_a
    };

    assert (my_b.baz() == 2);

}
<commit_msg>Exercise self-calls and overriding together a bit more.<commit_after>use std;

fn main() {

    obj a() {
        fn foo() -> int {
            ret 2;
        }
        fn bar() -> int {
            ret self.foo();
        }
    }

    auto my_a = a();

    auto my_b = obj {
        fn baz() -> int {
            ret self.foo();
        }
        with my_a
    };

    assert (my_b.baz() == 2);

    auto my_c = obj {
        fn foo() -> int {
            ret 3;
        }
        fn baz() -> int {
            ret self.foo();
        }
        with my_a
    };

    assert (my_c.baz() == 3);
    assert (my_c.bar() == 3);
}
<|endoftext|>


<commit_before>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! For feature highlights and a quick start, please review the
//! [README](https://github.com/djc/askama/blob/main/README.md).
//!
//! The primary documentation for this crate now lives in
//! [the book](https://djc.github.io/askama/).
//!
//! # Creating Askama templates
//!
//! An Askama template is a `struct` definition which provides the template
//! context combined with a UTF-8 encoded text file (or inline source, see
//! below). Askama can be used to generate any kind of text-based format.
//! The template file's extension may be used to provide content type hints.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## The `template()` attribute
//!
//! Askama works by generating one or more trait implementations for any
//! `struct` type decorated with the `#[derive(Template)]` attribute. The
//! code generation process takes some options that can be specified through
//! the `template()` attribute. The following sub-attributes are currently
//! recognized:
//!
//! * `path` (as `path = "foo.html"`): sets the path to the template file. The
//!   path is interpreted as relative to the configured template directories
//!   (by default, this is a `templates` directory next to your `Cargo.toml`).
//!   The file name extension is used to infer an escape mode (see below). In
//!   web framework integrations, the path's extension may also be used to
//!   infer the content type of the resulting response.
//!   Cannot be used together with `source`.
//! * `source` (as `source = "{{ foo }}"`): directly sets the template source.
//!   This can be useful for test cases or short templates. The generated path
//!   is undefined, which generally makes it impossible to refer to this
//!   template from other templates. If `source` is specified, `ext` must also
//!   be specified (see below). Cannot be used together with `path`.
//! * `ext` (as `ext = "txt"`): lets you specify the content type as a file
//!   extension. This is used to infer an escape mode (see below), and some
//!   web framework integrations use it to determine the content type.
//!   Cannot be used together with `path`.
//! * `print` (as `print = "code"`): enable debugging by printing nothing
//!   (`none`), the parsed syntax tree (`ast`), the generated code (`code`)
//!   or `all` for both. The requested data will be printed to stdout at
//!   compile time.
//! * `escape` (as `escape = "none"`): override the template's extension used for
//!   the purpose of determining the escaper for this template. See the section
//!   on configuring custom escapers for more information.
//! * `syntax` (as `syntax = "foo"`): set the syntax name for a parser defined
//!   in the configuration file. The default syntax , "default",  is the one
//!   provided by Askama.

#![allow(unused_imports)]
#![deny(elided_lifetimes_in_paths)]

#[macro_use]
extern crate askama_derive;
pub use askama_shared as shared;

use std::fs::{self, DirEntry};
use std::io;
use std::path::Path;

pub use askama_escape::{Html, Text};

/// Main `Template` trait; implementations are generally derived
///
/// If you need an object-safe template, use [`DynTemplate`].
pub trait Template {
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> Result<String> {
        let mut buf = String::with_capacity(Self::SIZE_HINT);
        self.render_into(&mut buf)?;
        Ok(buf)
    }

    /// Renders the template to the given `writer` buffer
    fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()>;

    /// The template's extension, if provided
    const EXTENSION: Option<&'static str>;

    /// Provides a conservative estimate of the expanded length of the rendered template
    const SIZE_HINT: usize;
}

/// Object-safe wrapper trait around [`Template`] implementers
///
/// This trades reduced performance (mostly due to writing into `dyn Write`) for object safety.
pub trait DynTemplate {
    /// Helper method which allocates a new `String` and renders into it
    fn dyn_render(&self) -> Result<String>;

    /// Renders the template to the given `writer` buffer
    fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()>;

    /// Helper function to inspect the template's extension
    fn extension(&self) -> Option<&'static str>;

    /// Provides a conservative estimate of the expanded length of the rendered template
    fn size_hint(&self) -> usize;
}

impl<T: Template> DynTemplate for T {
    fn dyn_render(&self) -> Result<String> {
        <Self as Template>::render(self)
    }

    fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()> {
        <Self as Template>::render_into(self, writer)
    }

    fn extension(&self) -> Option<&'static str> {
        Self::EXTENSION
    }

    fn size_hint(&self) -> usize {
        Self::SIZE_HINT
    }
}

pub use crate::shared::filters;
pub use crate::shared::helpers;
pub use crate::shared::{read_config_file, Error, MarkupDisplay, Result};
pub use askama_derive::*;

pub mod mime {
    #[cfg(all(feature = "mime_guess", feature = "mime"))]
    pub fn extension_to_mime_type(ext: &str) -> mime_guess::Mime {
        let basic_type = mime_guess::from_ext(ext).first_or_octet_stream();
        for (simple, utf_8) in &TEXT_TYPES {
            if &basic_type == simple {
                return utf_8.clone();
            }
        }
        basic_type
    }

    #[cfg(all(feature = "mime_guess", feature = "mime"))]
    const TEXT_TYPES: [(mime_guess::Mime, mime_guess::Mime); 6] = [
        (mime::TEXT_PLAIN, mime::TEXT_PLAIN_UTF_8),
        (mime::TEXT_HTML, mime::TEXT_HTML_UTF_8),
        (mime::TEXT_CSS, mime::TEXT_CSS_UTF_8),
        (mime::TEXT_CSV, mime::TEXT_CSV_UTF_8),
        (
            mime::TEXT_TAB_SEPARATED_VALUES,
            mime::TEXT_TAB_SEPARATED_VALUES_UTF_8,
        ),
        (
            mime::APPLICATION_JAVASCRIPT,
            mime::APPLICATION_JAVASCRIPT_UTF_8,
        ),
    ];
}

/// Old build script helper to rebuild crates if contained templates have changed
///
/// This function is now deprecated and does nothing.
#[deprecated(
    since = "0.8.1",
    note = "file-level dependency tracking is handled automatically without build script"
)]
pub fn rerun_if_templates_changed() {}

#[cfg(test)]
mod tests {
    use super::{DynTemplate, Template};

    #[test]
    fn dyn_template() {
        struct Test;
        impl Template for Test {
            fn render_into(
                &self,
                writer: &mut (impl std::fmt::Write + ?Sized),
            ) -> askama_shared::Result<()> {
                Ok(writer.write_str("test")?)
            }

            const EXTENSION: Option<&'static str> = Some("txt");

            const SIZE_HINT: usize = 4;
        }

        fn render(t: &dyn DynTemplate) -> String {
            t.dyn_render().unwrap()
        }

        assert_eq!(render(&Test), "test");
    }
}
<commit_msg>Remove unused imports<commit_after>//! Askama implements a type-safe compiler for Jinja-like templates.
//! It lets you write templates in a Jinja-like syntax,
//! which are linked to a `struct` defining the template context.
//! This is done using a custom derive implementation (implemented
//! in [`askama_derive`](https://crates.io/crates/askama_derive)).
//!
//! For feature highlights and a quick start, please review the
//! [README](https://github.com/djc/askama/blob/main/README.md).
//!
//! The primary documentation for this crate now lives in
//! [the book](https://djc.github.io/askama/).
//!
//! # Creating Askama templates
//!
//! An Askama template is a `struct` definition which provides the template
//! context combined with a UTF-8 encoded text file (or inline source, see
//! below). Askama can be used to generate any kind of text-based format.
//! The template file's extension may be used to provide content type hints.
//!
//! A template consists of **text contents**, which are passed through as-is,
//! **expressions**, which get replaced with content while being rendered, and
//! **tags**, which control the template's logic.
//! The template syntax is very similar to [Jinja](http://jinja.pocoo.org/),
//! as well as Jinja-derivatives like [Twig](http://twig.sensiolabs.org/) or
//! [Tera](https://github.com/Keats/tera).
//!
//! ## The `template()` attribute
//!
//! Askama works by generating one or more trait implementations for any
//! `struct` type decorated with the `#[derive(Template)]` attribute. The
//! code generation process takes some options that can be specified through
//! the `template()` attribute. The following sub-attributes are currently
//! recognized:
//!
//! * `path` (as `path = "foo.html"`): sets the path to the template file. The
//!   path is interpreted as relative to the configured template directories
//!   (by default, this is a `templates` directory next to your `Cargo.toml`).
//!   The file name extension is used to infer an escape mode (see below). In
//!   web framework integrations, the path's extension may also be used to
//!   infer the content type of the resulting response.
//!   Cannot be used together with `source`.
//! * `source` (as `source = "{{ foo }}"`): directly sets the template source.
//!   This can be useful for test cases or short templates. The generated path
//!   is undefined, which generally makes it impossible to refer to this
//!   template from other templates. If `source` is specified, `ext` must also
//!   be specified (see below). Cannot be used together with `path`.
//! * `ext` (as `ext = "txt"`): lets you specify the content type as a file
//!   extension. This is used to infer an escape mode (see below), and some
//!   web framework integrations use it to determine the content type.
//!   Cannot be used together with `path`.
//! * `print` (as `print = "code"`): enable debugging by printing nothing
//!   (`none`), the parsed syntax tree (`ast`), the generated code (`code`)
//!   or `all` for both. The requested data will be printed to stdout at
//!   compile time.
//! * `escape` (as `escape = "none"`): override the template's extension used for
//!   the purpose of determining the escaper for this template. See the section
//!   on configuring custom escapers for more information.
//! * `syntax` (as `syntax = "foo"`): set the syntax name for a parser defined
//!   in the configuration file. The default syntax , "default",  is the one
//!   provided by Askama.

#![deny(elided_lifetimes_in_paths)]

pub use askama_shared as shared;

pub use askama_escape::{Html, Text};

/// Main `Template` trait; implementations are generally derived
///
/// If you need an object-safe template, use [`DynTemplate`].
pub trait Template {
    /// Helper method which allocates a new `String` and renders into it
    fn render(&self) -> Result<String> {
        let mut buf = String::with_capacity(Self::SIZE_HINT);
        self.render_into(&mut buf)?;
        Ok(buf)
    }

    /// Renders the template to the given `writer` buffer
    fn render_into(&self, writer: &mut (impl std::fmt::Write + ?Sized)) -> Result<()>;

    /// The template's extension, if provided
    const EXTENSION: Option<&'static str>;

    /// Provides a conservative estimate of the expanded length of the rendered template
    const SIZE_HINT: usize;
}

/// Object-safe wrapper trait around [`Template`] implementers
///
/// This trades reduced performance (mostly due to writing into `dyn Write`) for object safety.
pub trait DynTemplate {
    /// Helper method which allocates a new `String` and renders into it
    fn dyn_render(&self) -> Result<String>;

    /// Renders the template to the given `writer` buffer
    fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()>;

    /// Helper function to inspect the template's extension
    fn extension(&self) -> Option<&'static str>;

    /// Provides a conservative estimate of the expanded length of the rendered template
    fn size_hint(&self) -> usize;
}

impl<T: Template> DynTemplate for T {
    fn dyn_render(&self) -> Result<String> {
        <Self as Template>::render(self)
    }

    fn dyn_render_into(&self, writer: &mut dyn std::fmt::Write) -> Result<()> {
        <Self as Template>::render_into(self, writer)
    }

    fn extension(&self) -> Option<&'static str> {
        Self::EXTENSION
    }

    fn size_hint(&self) -> usize {
        Self::SIZE_HINT
    }
}

pub use crate::shared::filters;
pub use crate::shared::helpers;
pub use crate::shared::{read_config_file, Error, MarkupDisplay, Result};
pub use askama_derive::*;

pub mod mime {
    #[cfg(all(feature = "mime_guess", feature = "mime"))]
    pub fn extension_to_mime_type(ext: &str) -> mime_guess::Mime {
        let basic_type = mime_guess::from_ext(ext).first_or_octet_stream();
        for (simple, utf_8) in &TEXT_TYPES {
            if &basic_type == simple {
                return utf_8.clone();
            }
        }
        basic_type
    }

    #[cfg(all(feature = "mime_guess", feature = "mime"))]
    const TEXT_TYPES: [(mime_guess::Mime, mime_guess::Mime); 6] = [
        (mime::TEXT_PLAIN, mime::TEXT_PLAIN_UTF_8),
        (mime::TEXT_HTML, mime::TEXT_HTML_UTF_8),
        (mime::TEXT_CSS, mime::TEXT_CSS_UTF_8),
        (mime::TEXT_CSV, mime::TEXT_CSV_UTF_8),
        (
            mime::TEXT_TAB_SEPARATED_VALUES,
            mime::TEXT_TAB_SEPARATED_VALUES_UTF_8,
        ),
        (
            mime::APPLICATION_JAVASCRIPT,
            mime::APPLICATION_JAVASCRIPT_UTF_8,
        ),
    ];
}

/// Old build script helper to rebuild crates if contained templates have changed
///
/// This function is now deprecated and does nothing.
#[deprecated(
    since = "0.8.1",
    note = "file-level dependency tracking is handled automatically without build script"
)]
pub fn rerun_if_templates_changed() {}

#[cfg(test)]
mod tests {
    use super::{DynTemplate, Template};

    #[test]
    fn dyn_template() {
        struct Test;
        impl Template for Test {
            fn render_into(
                &self,
                writer: &mut (impl std::fmt::Write + ?Sized),
            ) -> askama_shared::Result<()> {
                Ok(writer.write_str("test")?)
            }

            const EXTENSION: Option<&'static str> = Some("txt");

            const SIZE_HINT: usize = 4;
        }

        fn render(t: &dyn DynTemplate) -> String {
            t.dyn_render().unwrap()
        }

        assert_eq!(render(&Test), "test");
    }
}
<|endoftext|>


<commit_before>use collections::VecDeque;
// Temporary hack until libredox get hashmaps
use redox::*;

#[derive(Clone, PartialEq, Copy, Hash)]
pub enum InsertMode {
    Append,
    Insert,
    Replace,
}

#[derive(Clone, PartialEq, Copy, Hash)]
pub struct InsertOptions {
    mode: InsertMode,
}

/// A mode
#[derive(Clone, PartialEq, Copy, Hash)]
pub enum Mode {
    /// A primitive mode (no repeat, no delimiters, no preprocessing)
    Primitive(PrimitiveMode),
    /// Command mode
    Command(CommandMode),
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A command mode
pub enum CommandMode {
//    Visual(VisualOptions),
    /// Normal mode
    Normal,
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A primitive mode
pub enum PrimitiveMode {
    /// Insert mode
    Insert(InsertOptions),
}

#[derive(Clone, PartialEq, Hash)]
pub enum Unit {
    /// Single [repeated] instruction
    Inst(u16, char),
    /// Multiple instructions
    Block(u16, Vec<Unit>),
}

#[derive(Clone, PartialEq, Hash)]
/// The state of the editor
pub struct State {
    /// The current cursor
    pub current_cursor: u8,
    /// The cursors
    pub cursors: Vec<Cursor>,
    /// The text (document)
    pub text: VecDeque<VecDeque<char>>,
    /// The x coordinate of the scroll
    pub scroll_x: u32,
    /// The y coordinate of the scroll
    pub scroll_y: u32,
}

impl State {
    fn insert(&mut self, c: char) {

    }
    fn new() -> State {
        State {
            current_cursor: 0,
            cursors: Vec::new(),
            text: VecDeque::new(),
            scroll_x: 0,
            scroll_y: 0,
        }
    }
}

/// A command char
#[derive(Clone, Copy, Hash, PartialEq)]
pub enum CommandChar {
    /// A char
    Char(char),
    /// A wildcard
    Wildcard,
}

/// The editor
pub struct Editor {
    /// The state of the editor
    pub state: State,
}

impl Editor {
    pub fn new() -> Self {
        Editor {
            state: State::new(),
        }
    }

    pub fn exec(&mut self, cmd: &Unit) {

        match *cmd {
            Unit::Inst(n, ref c) => {
                // Execute commands
            },
            Unit::Block(n, ref units) => {
                for _ in 1..n {
                    for i in units {
                        self.exec(&i);
                    }
                }
            },
        }
    }
}

#[derive(Clone, PartialEq, Hash)]
/// A cursor
pub struct Cursor {
    /// The x coordinate of the cursor
    pub x: u32,
    /// The y coordinate of the cursor
    pub y: u32,
    /// The mode of the cursor
    pub mode: Mode,
    /// The history of the cursor
    pub history: Vec<Unit>,
}

/// An iterator over units
pub struct UnitIterator<'a, I: Iterator<Item = char> + 'a> {
    /// The iterator over the chars
    char_iter: &'a mut I,
    /// The state
    state: &'a mut State,
}

impl<'a, I: Iterator<Item = char> + 'a> Iterator for UnitIterator<'a, I> {
    type Item = Unit;

    fn next(&mut self) -> Option<Unit> {
        match self.state.cursors[self.state.current_cursor as usize].mode {
            Mode::Primitive(_) => Some(Unit::Inst(1, match self.char_iter.next() {
                Some(c) => c,
                None => return None,
            })),
            Mode::Command(_) => {
                let mut ch = self.char_iter.next().unwrap_or('\0');
                let mut n = 1;

                let mut unset = true;
                for c in *self.char_iter {
                    n = match c {
                        '0' if n != 0 => n * 10,
                        '1'           => n * 10 + 1,
                        '2'           => n * 10 + 2,
                        '3'           => n * 10 + 3,
                        '4'           => n * 10 + 4,
                        '5'           => n * 10 + 5,
                        '6'           => n * 10 + 6,
                        '7'           => n * 10 + 7,
                        '8'           => n * 10 + 8,
                        '9'           => n * 10 + 9,
                        _             => {
                            ch = c;
                            break;
                        },
                    };

                    if unset {
                        unset = false;
                        n     = 0;
                    }
                }

                if ch == '(' {
                    let mut level = 0;
                    let mut vec = self.char_iter.take_while(|c| {
                        level = match *c {
                            '(' => level + 1,
                            ')' => level - 1,
                            ';' => 0,
                            _ => level,
                        };
                        level != 0
                    }).skip(1).collect::<Vec<_>>();
                    vec.pop();
                    Some(Unit::Block(n, vec.into_iter().unit_iter(&mut self.state).collect()))
                } else if let Some(ch) = self.char_iter.next() {
                    Some(Unit::Inst(n, ch))
                } else {
                    None
                }
            }
        }
    }
}

pub trait ToUnitIterator<'a>: Iterator<Item = char> + 'a {
    /// Create a iterator of the unit given by the chars
    fn unit_iter(&'a mut self, state: &'a mut State) -> UnitIterator<'a, Self>;
}

impl<'a, I: Iterator<Item = char> + 'a> ToUnitIterator<'a> for I {
    fn unit_iter(&'a mut self, state: &'a mut State) -> UnitIterator<'a, I> {
        UnitIterator {
            char_iter: self,
            state: state,
        }
    }
}
<commit_msg>Die errors die<commit_after>use collections::VecDeque;
// Temporary hack until libredox get hashmaps
use redox::*;

#[derive(Clone, PartialEq, Copy, Hash)]
pub enum InsertMode {
    Append,
    Insert,
    Replace,
}

#[derive(Clone, PartialEq, Copy, Hash)]
pub struct InsertOptions {
    mode: InsertMode,
}

/// A mode
#[derive(Clone, PartialEq, Copy, Hash)]
pub enum Mode {
    /// A primitive mode (no repeat, no delimiters, no preprocessing)
    Primitive(PrimitiveMode),
    /// Command mode
    Command(CommandMode),
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A command mode
pub enum CommandMode {
//    Visual(VisualOptions),
    /// Normal mode
    Normal,
}

#[derive(Clone, PartialEq, Copy, Hash)]
/// A primitive mode
pub enum PrimitiveMode {
    /// Insert mode
    Insert(InsertOptions),
}

#[derive(Clone, PartialEq, Hash)]
pub enum Unit {
    /// Single [repeated] instruction
    Inst(u16, char),
    /// Multiple instructions
    Block(u16, Vec<Unit>),
}

#[derive(Clone, PartialEq, Hash)]
/// The state of the editor
pub struct State {
    /// The current cursor
    pub current_cursor: u8,
    /// The cursors
    pub cursors: Vec<Cursor>,
    /// The text (document)
    pub text: VecDeque<VecDeque<char>>,
    /// The x coordinate of the scroll
    pub scroll_x: u32,
    /// The y coordinate of the scroll
    pub scroll_y: u32,
}

impl State {
    fn insert(&mut self, c: char) {

    }
    fn new() -> State {
        State {
            current_cursor: 0,
            cursors: Vec::new(),
            text: VecDeque::new(),
            scroll_x: 0,
            scroll_y: 0,
        }
    }
}

/// A command char
#[derive(Clone, Copy, Hash, PartialEq)]
pub enum CommandChar {
    /// A char
    Char(char),
    /// A wildcard
    Wildcard,
}

/// The editor
pub struct Editor {
    /// The state of the editor
    pub state: State,
}

impl Editor {
    pub fn new() -> Self {
        Editor {
            state: State::new(),
        }
    }

    pub fn exec(&mut self, cmd: &Unit) {

        match *cmd {
            Unit::Inst(n, ref c) => {
                // Execute commands
            },
            Unit::Block(n, ref units) => {
                for _ in 1..n {
                    for i in units {
                        self.exec(&i);
                    }
                }
            },
        }
    }
}

#[derive(Clone, PartialEq, Hash)]
/// A cursor
pub struct Cursor {
    /// The x coordinate of the cursor
    pub x: u32,
    /// The y coordinate of the cursor
    pub y: u32,
    /// The mode of the cursor
    pub mode: Mode,
    /// The history of the cursor
    pub history: Vec<Unit>,
}

/// An iterator over units
pub struct UnitIterator<'a, I: Iterator<Item = char> + 'a> {
    /// The iterator over the chars
    char_iter: &'a mut I,
    /// The state
    state: &'a mut State,
}

impl<'a, I: Iterator<Item = char> + 'a> Iterator for UnitIterator<'a, I> {
    type Item = Unit;

    fn next(&mut self) -> Option<Unit> {
        match self.state.cursors[self.state.current_cursor as usize].mode {
            Mode::Primitive(_) => Some(Unit::Inst(1, match self.char_iter.next() {
                Some(c) => c,
                None => return None,
            })),
            Mode::Command(_) => {
                let mut ch = self.char_iter.next().unwrap_or('\0');
                let mut n = 1;

                let mut unset = true;
                for c in self.char_iter {
                    n = match c {
                        '0' if n != 0 => n * 10,
                        '1'           => n * 10 + 1,
                        '2'           => n * 10 + 2,
                        '3'           => n * 10 + 3,
                        '4'           => n * 10 + 4,
                        '5'           => n * 10 + 5,
                        '6'           => n * 10 + 6,
                        '7'           => n * 10 + 7,
                        '8'           => n * 10 + 8,
                        '9'           => n * 10 + 9,
                        r             => {
                            ch = r;
                            break;
                        },
                    };

                    if unset {
                        unset = false;
                        n     = 0;
                    }
                }

                if ch == '(' {
                    let mut level = 0;
                    let mut vec = self.char_iter.take_while(|c| {
                        level = match *c {
                            '(' => level + 1,
                            ')' => level - 1,
                            ';' => 0,
                            _ => level,
                        };
                        level != 0
                    }).skip(1).collect::<Vec<_>>();
                    vec.pop();
                    Some(Unit::Block(n, vec.into_iter().unit_iter(&mut self.state).collect()))
                } else if let Some(ch) = self.char_iter.next() {
                    Some(Unit::Inst(n, ch))
                } else {
                    None
                }
            }
        }
    }
}

pub trait ToUnitIterator<'a>: Iterator<Item = char> + 'a {
    /// Create a iterator of the unit given by the chars
    fn unit_iter(&'a mut self, state: &'a mut State) -> UnitIterator<'a, Self>;
}

impl<'a, I: Iterator<Item = char> + 'a> ToUnitIterator<'a> for I {
    fn unit_iter(&'a mut self, state: &'a mut State) -> UnitIterator<'a, I> {
        UnitIterator {
            char_iter: self,
            state: state,
        }
    }
}
<|endoftext|>