<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;

use boxed::Box;
use cmp;
use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
use fmt;
use mem;
use slice;
use string::String;
use vec::Vec;

// =============================================================================
// Forwarding implementations

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, R: Read + ?Sized> Read for &'a mut R {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_to_end(buf)
    }
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_to_string(buf)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, W: Write + ?Sized> Write for &'a mut W {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
    fn flush(&mut self) -> io::Result<()> { (**self).flush() }
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        (**self).write_all(buf)
    }
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        (**self).write_fmt(fmt)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
    fn consume(&mut self, amt: usize) { (**self).consume(amt) }
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_until(byte, buf)
    }
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_line(buf)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read + ?Sized> Read for Box<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_to_end(buf)
    }
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_to_string(buf)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write + ?Sized> Write for Box<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
    fn flush(&mut self) -> io::Result<()> { (**self).flush() }
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        (**self).write_all(buf)
    }
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        (**self).write_fmt(fmt)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<S: Seek + ?Sized> Seek for Box<S> {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B: BufRead + ?Sized> BufRead for Box<B> {
    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
    fn consume(&mut self, amt: usize) { (**self).consume(amt) }
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_until(byte, buf)
    }
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_line(buf)
    }
}

// =============================================================================
// In-memory buffer implementations

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Read for &'a [u8] {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let amt = cmp::min(buf.len(), self.len());
        let (a, b) = self.split_at(amt);
        slice::bytes::copy_memory(buf, a);
        *self = b;
        Ok(amt)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> BufRead for &'a [u8] {
    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }
    fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for &'a mut [u8] {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        let amt = cmp::min(data.len(), self.len());
        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
        slice::bytes::copy_memory(a, &data[..amt]);
        *self = b;
        Ok(amt)
    }

    fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
        if try!(self.write(data)) == data.len() {
            Ok(())
        } else {
            Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer", None))
        }
    }

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

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Vec<u8> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.push_all(buf);
        Ok(buf.len())
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.push_all(buf);
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
<commit_msg>Speed up reading/writing slices with #[inline]<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;

use boxed::Box;
use cmp;
use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
use fmt;
use mem;
use slice;
use string::String;
use vec::Vec;

// =============================================================================
// Forwarding implementations

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, R: Read + ?Sized> Read for &'a mut R {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_to_end(buf)
    }

    #[inline]
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_to_string(buf)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, W: Write + ?Sized> Write for &'a mut W {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { (**self).flush() }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        (**self).write_all(buf)
    }

    #[inline]
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        (**self).write_fmt(fmt)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }

    #[inline]
    fn consume(&mut self, amt: usize) { (**self).consume(amt) }

    #[inline]
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_until(byte, buf)
    }

    #[inline]
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_line(buf)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read + ?Sized> Read for Box<R> {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_to_end(buf)
    }

    #[inline]
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_to_string(buf)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write + ?Sized> Write for Box<W> {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { (**self).flush() }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        (**self).write_all(buf)
    }

    #[inline]
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        (**self).write_fmt(fmt)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<S: Seek + ?Sized> Seek for Box<S> {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B: BufRead + ?Sized> BufRead for Box<B> {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }

    #[inline]
    fn consume(&mut self, amt: usize) { (**self).consume(amt) }

    #[inline]
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_until(byte, buf)
    }

    #[inline]
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_line(buf)
    }
}

// =============================================================================
// In-memory buffer implementations

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Read for &'a [u8] {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let amt = cmp::min(buf.len(), self.len());
        let (a, b) = self.split_at(amt);
        slice::bytes::copy_memory(buf, a);
        *self = b;
        Ok(amt)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> BufRead for &'a [u8] {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }

    #[inline]
    fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for &'a mut [u8] {
    #[inline]
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        let amt = cmp::min(data.len(), self.len());
        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
        slice::bytes::copy_memory(a, &data[..amt]);
        *self = b;
        Ok(amt)
    }

    #[inline]
    fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
        if try!(self.write(data)) == data.len() {
            Ok(())
        } else {
            Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer", None))
        }
    }

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

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Vec<u8> {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.push_all(buf);
        Ok(buf.len())
    }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.push_all(buf);
        Ok(())
    }

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

#[cfg(test)]
mod tests {
    use io::prelude::*;
    use vec::Vec;
    use test;

    #[bench]
    fn bench_read_slice(b: &mut test::Bencher) {
        let buf = [5; 1024];
        let mut dst = [0; 128];

        b.iter(|| {
            let mut rd = &buf[..];
            for _ in (0 .. 8) {
                let _ = rd.read(&mut dst);
                test::black_box(&dst);
            }
        })
    }

    #[bench]
    fn bench_write_slice(b: &mut test::Bencher) {
        let mut buf = [0; 1024];
        let src = [5; 128];

        b.iter(|| {
            let mut wr = &mut buf[..];
            for _ in (0 .. 8) {
                let _ = wr.write_all(&src);
                test::black_box(&wr);
            }
        })
    }

    #[bench]
    fn bench_read_vec(b: &mut test::Bencher) {
        let buf = vec![5; 1024];
        let mut dst = [0; 128];

        b.iter(|| {
            let mut rd = &buf[..];
            for _ in (0 .. 8) {
                let _ = rd.read(&mut dst);
                test::black_box(&dst);
            }
        })
    }

    #[bench]
    fn bench_write_vec(b: &mut test::Bencher) {
        let mut buf = Vec::with_capacity(1024);
        let src = [5; 128];

        b.iter(|| {
            let mut wr = &mut buf[..];
            for _ in (0 .. 8) {
                let _ = wr.write_all(&src);
                test::black_box(&wr);
            }
        })
    }
}
<|endoftext|>


<commit_before>use piston::AssetStore;
use serialize::json;
use std::collections::HashMap;
use std::f32::consts::{PI, SQRT2};
use std::f32::INFINITY;
use std::io::fs::File;

use array::*;
use cube;
use texture::AtlasBuilder;

pub struct Vertex {
    pub xyz: [f32, ..3],
    pub uv: [f32, ..2]
}

#[deriving(Clone)]
pub enum TintSource {
    NoTint,
    GrassTint,
    FoliageTint,
    RedstoneTint
}

pub enum OrthoRotation {
    Rotate0,
    Rotate90,
    Rotate180,
    Rotate270
}

impl OrthoRotation {
    pub fn from_json(json: &json::Json) -> Option<OrthoRotation> {
        json.as_i64().and_then(|r| Some(match r {
            0 => Rotate0,
            90 => Rotate90,
            180 => Rotate180,
            270 => Rotate270,
            _ => return None
        }))
    }
}

pub struct Face {
    pub vertices: [Vertex, ..4],
    pub tint: bool,
    pub cull_face: Option<cube::Face>,
    pub ao_face: Option<cube::Face>
}

impl Clone for Face {
    fn clone(&self) -> Face { *self }
}

#[deriving(Clone)]
enum PartialTexture {
    TextureVariable(String),
    TextureCoords(f32, f32)
}

#[deriving(Clone)]
pub struct PartialModel {
    textures: HashMap<String, PartialTexture>,
    faces: Vec<(Face, String)>,
    full_faces: Vec<uint>,
    no_ambient_occlusion: bool
}

#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Opacity {
    Transparent,
    TranslucentSolid,
    TransparentSolid,
    Opaque
}

impl Opacity {
    pub fn is_opaque(self) -> bool {
        self == Opaque
    }

    pub fn is_solid(self) -> bool {
        self != Transparent
    }
}

#[deriving(Clone)]
pub struct Model {
    pub faces: Vec<Face>,
    pub opacity: Opacity,
    pub tint_source: TintSource
}

impl PartialModel {
    fn load<T>(name: &str, assets: &AssetStore, atlas: &mut AtlasBuilder,
               cache: &mut HashMap<String, PartialModel>,
               f: |&PartialModel, &mut AtlasBuilder| -> T) -> T {
        match cache.find_equiv(&name) {
            Some(model) => return f(model, atlas),
            None => {}
        }
        let path = assets.path(format!("minecraft/models/{}.json", name).as_slice());
        let json = json::from_reader(&mut File::open(&path.unwrap()).unwrap()).unwrap();
        let json = json.as_object().unwrap();

        let mut model = match json.find_with(|k| "parent".cmp(&k.as_slice())).and_then(|x| x.as_string()) {
            Some(parent) => PartialModel::load(parent, assets, atlas, cache, |m, _| m.clone()),
            None => PartialModel {
                textures: HashMap::new(),
                faces: vec![],
                full_faces: vec![],
                no_ambient_occlusion: false
            }
        };

        match json.find_with(|k| "ambientocclusion".cmp(&k.as_slice())).and_then(|x| x.as_boolean()) {
            Some(ambient_occlusion) => model.no_ambient_occlusion = !ambient_occlusion,
            None => {}
        }

        match json.find_with(|k| "textures".cmp(&k.as_slice())).and_then(|x| x.as_object()) {
            Some(textures) => for (name, tex) in textures.iter() {
                let tex = tex.as_string().unwrap();
                let tex = if tex.starts_with("#") {
                    TextureVariable(tex.slice_from(1).to_string())
                } else {
                    let (u, v) = atlas.load(tex);
                    TextureCoords(u as f32, v as f32)
                };
                model.textures.insert(name.clone(), tex);
            },
            None => {}
        }
        match json.find_with(|k| "elements".cmp(&k.as_slice())).and_then(|x| x.as_list()) {
            Some(elements) => for element in elements.iter().map(|x| x.as_object().unwrap()) {
                fn array3_num<T>(json: &json::Json, f: |f64| -> T) -> [T, ..3] {
                    Array::from_iter(json.as_list().unwrap().iter().map(|x| f(x.as_f64().unwrap())))
                }
                let from = array3_num(element.find_with(|k| "from".cmp(&k.as_slice())).unwrap(), |x| x as f32 / 16.0);
                let to = array3_num(element.find_with(|k| "to".cmp(&k.as_slice())).unwrap(), |x| x as f32 / 16.0);
                let scale = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];

                let is_full_cube = from == [0.0, 0.0, 0.0] && to == [1.0, 1.0, 1.0];
                let element_start = model.faces.len();

                for (k, v) in element.find_with(|k| "faces".cmp(&k.as_slice())).unwrap().as_object().unwrap().iter() {
                    let face: cube::Face = from_str(k.as_slice()).unwrap();
                    let o = v.as_object().unwrap();
                    let [u0, v0, u1, v1] = match o.find_with(|k| "uv".cmp(&k.as_slice())) {
                        Some(uv) => {
                            Array::from_iter(uv.as_list().unwrap().iter().map(|x| x.as_f64().unwrap() as f32))
                        }
                        None => match face {
                            cube::West | cube::East => [from[2], from[1], to[2], to[1]],
                            cube::Down | cube::Up => [from[0], from[2], to[0], to[2]],
                            cube::North | cube::South => [from[0], from[1], to[0], to[1]]
                        }.map(|x| x * 16.0)
                    };

                    let tex = o.find_with(|k| "texture".cmp(&k.as_slice())).unwrap().as_string().unwrap();
                    assert!(tex.starts_with("#"));
                    let tex = tex.slice_from(1).to_string();

                    let cull_face = o.find_with(|k| "cullface".cmp(&k.as_slice())).map(|s| {
                        from_str(s.as_string().unwrap()).unwrap()
                    });

                    if cull_face.is_some() && cull_face != Some(face) {
                        println!("odd case: cull_face = {} for face = {}", cull_face.unwrap(), face);
                    }

                    let tint = o.find_with(|k| "tintindex".cmp(&k.as_slice())).map(|x| {
                        let x = x.as_i64().unwrap();
                        if x != 0 {
                            println!("odd case: tint_index = {}", x);
                        }
                    }).is_some();

                    if cull_face == Some(face) && is_full_cube {
                        model.full_faces.push(model.faces.len());
                    }

                    let rotation = o.find_with(|k| "rotation".cmp(&k.as_slice())).map_or(Rotate0, |r| {
                        match OrthoRotation::from_json(r) {
                            Some(r) => r,
                            None => fail!("invalid rotation for face {}", r)
                        }
                    });

                    let xyz = face.vertices(from, scale);
                    // Swap vertical texture coordinates.
                    let [v0, v1] = [v1, v0];
                    // Bring texture coordinates closer to avoid seams.
                    let u_center = (u0 + u1) / 2.0;
                    let [u0, u1] = [u0, u1].map(|u| u - (u - u_center).signum() / 128.0);
                    let v_center = (v0 + v1) / 2.0;
                    let [v0, v1] = [v0, v1].map(|v| v - (v - v_center).signum() / 128.0);
                    // Clockwise quad (from bottom-right to top-right).
                    let uvs = [
                        [u1, v0],
                        [u0, v0],
                        [u0, v1],
                        [u1, v1]
                    ].map(|[u, v]| match rotation {
                        Rotate0 => [u, v],
                        Rotate90 => [v, 16.0 - u],
                        Rotate180 => [16.0 - u, 16.0 - v],
                        Rotate270 => [16.0 - v, u]
                    });

                    model.faces.push((Face {
                        vertices: Array::from_fn(|i| Vertex { xyz: xyz[i], uv: uvs[i] }),
                        tint: tint,
                        cull_face: cull_face,
                        ao_face: Some(face)
                    }, tex));
                }

                match element.find_with(|k| "rotation".cmp(&k.as_slice())) {
                    Some(r) => {
                        let r = r.as_object().unwrap();
                        let angle = r.find_with(|k| "angle".cmp(&k.as_slice())).unwrap().as_f64().unwrap();
                        let angle = angle as f32 / 180.0 * PI;
                        let rescale = r.find_with(|k| "rescale".cmp(&k.as_slice())).map_or(false, |x| x.as_boolean().unwrap());
                        let origin = array3_num(r.find_with(|k| "origin".cmp(&k.as_slice())).unwrap(), |x| x as f32 / 16.0);

                        let (s, c) = (angle.sin(), angle.cos());
                        let rot = |ix, iy| {
                            for &(ref mut face, _) in model.faces.mut_slice_from(element_start).mut_iter() {
                                face.ao_face = None;

                                let [ox, oy] = [origin[ix], origin[iy]];
                                for v in face.vertices.mut_iter() {
                                    let [x, y] = [v.xyz[ix] - ox, v.xyz[iy] - oy];
                                    v.xyz[ix] = x * c + y * s;
                                    v.xyz[iy] =-x * s + y * c;
                                }

                                if rescale {
                                    for v in face.vertices.mut_iter() {
                                        v.xyz[ix] *= SQRT2;
                                        v.xyz[iy] *= SQRT2;
                                    }
                                }

                                for v in face.vertices.mut_iter() {
                                    v.xyz[ix] += ox;
                                    v.xyz[iy] += oy;
                                }
                            }
                        };
                        match r.find_with(|k| "axis".cmp(&k.as_slice())).unwrap().as_string().unwrap() {
                            "x" => rot(2, 1),
                            "y" => rot(0, 2),
                            "z" => rot(0, 1),
                            axis => fail!("invalid rotation axis {}", axis)
                        }
                    }
                    None => {}
                }
            },
            None => {}
        }

        f(cache.find_or_insert(name.to_string(), model), atlas)
    }
}

impl Model {
    pub fn load(name: &str, assets: &AssetStore, atlas: &mut AtlasBuilder,
                cache: &mut HashMap<String, PartialModel>) -> Model {
        PartialModel::load(format!("block/{}", name).as_slice(), assets, atlas, cache, |partial, atlas| {
            let mut faces: Vec<Face> = partial.faces.iter().map(|&(mut face, ref tex)| {
                fn texture_coords(textures: &HashMap<String, PartialTexture>,
                                  tex: &String) -> Option<(f32, f32)> {
                    match textures.find(tex) {
                        Some(&TextureVariable(ref tex)) => texture_coords(textures, tex),
                        Some(&TextureCoords(u, v)) => Some((u, v)),
                        None => None
                    }
                }
                let (u, v) = texture_coords(&partial.textures, tex).unwrap();
                for vertex in face.vertices.mut_iter() {
                    vertex.uv[0] += u;
                    vertex.uv[1] += v;
                }
                face
            }).collect();

            let mut full_faces = [Transparent, ..6];
            if partial.full_faces.len() >= 6 {
                for &i in partial.full_faces.iter() {
                    let face = faces[i].cull_face.unwrap() as uint;
                    if full_faces[face] == Opaque {
                        continue;
                    }
                    let (mut min_u, mut min_v) = (INFINITY, INFINITY);
                    let (mut max_u, mut max_v) = (0.0, 0.0);
                    for vertex in faces[i].vertices.iter() {
                        let [u, v] = vertex.uv;
                        min_u = u.min(min_u);
                        min_v = v.min(min_v);
                        max_u = u.max(max_u);
                        max_v = v.max(max_v);
                    }
                    let (u0, v0) = (min_u.floor() as u32, min_v.floor() as u32);
                    let (u1, v1) = (max_u.ceil() as u32, max_v.ceil() as u32);
                    let opacity = match atlas.min_alpha(u0, v0, u1 - u0, v1 - v0) {
                        0 => TransparentSolid,
                        255 => Opaque,
                        _ => TranslucentSolid
                    };
                    if full_faces[face] < opacity {
                        full_faces[face] = opacity;
                    }
                }
            }

            if !partial.no_ambient_occlusion {
                if faces.iter().any(|f| f.ao_face.is_none()) {
                    println!("Warning: model {} uses AO but has faces which are unsuitable", name);
                }
            } else {
                for face in faces.mut_iter() {
                    face.ao_face = None;
                }
            }

            let tint_source = if faces.iter().any(|f| f.tint) {
                match name {
                    name if name.starts_with("grass_") ||
                            name.starts_with("double_grass_") ||
                            name.starts_with("double_fern_") => GrassTint,
                    "reeds" | "fern" | "tall_grass" => GrassTint,
                    name if name.ends_with("_leaves") || name.ends_with("_stem_fruit") ||
                            name.starts_with("vine_") || name.starts_with("stem_") => FoliageTint,
                    "waterlily" => FoliageTint,
                    name if name.starts_with("redstone_") => RedstoneTint,
                    _ => {
                        println!("tint source not known for '{}'", name);
                        NoTint
                    }
                }
            } else {
                NoTint
            };

            Model {
                faces: faces,
                opacity: *full_faces.iter().min().unwrap(),
                tint_source: tint_source
            }
        })
    }

    pub fn empty() -> Model {
        Model {
            faces: Vec::new(),
            opacity: Transparent,
            tint_source: NoTint
        }
    }

    pub fn is_empty(&self) -> bool {
        self.faces.is_empty()
    }
}
<commit_msg>minecraft: fix rotation over z axis<commit_after>use piston::AssetStore;
use serialize::json;
use std::collections::HashMap;
use std::f32::consts::{PI, SQRT2};
use std::f32::INFINITY;
use std::io::fs::File;

use array::*;
use cube;
use texture::AtlasBuilder;

pub struct Vertex {
    pub xyz: [f32, ..3],
    pub uv: [f32, ..2]
}

#[deriving(Clone)]
pub enum TintSource {
    NoTint,
    GrassTint,
    FoliageTint,
    RedstoneTint
}

pub enum OrthoRotation {
    Rotate0,
    Rotate90,
    Rotate180,
    Rotate270
}

impl OrthoRotation {
    pub fn from_json(json: &json::Json) -> Option<OrthoRotation> {
        json.as_i64().and_then(|r| Some(match r {
            0 => Rotate0,
            90 => Rotate90,
            180 => Rotate180,
            270 => Rotate270,
            _ => return None
        }))
    }
}

pub struct Face {
    pub vertices: [Vertex, ..4],
    pub tint: bool,
    pub cull_face: Option<cube::Face>,
    pub ao_face: Option<cube::Face>
}

impl Clone for Face {
    fn clone(&self) -> Face { *self }
}

#[deriving(Clone)]
enum PartialTexture {
    TextureVariable(String),
    TextureCoords(f32, f32)
}

#[deriving(Clone)]
pub struct PartialModel {
    textures: HashMap<String, PartialTexture>,
    faces: Vec<(Face, String)>,
    full_faces: Vec<uint>,
    no_ambient_occlusion: bool
}

#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Opacity {
    Transparent,
    TranslucentSolid,
    TransparentSolid,
    Opaque
}

impl Opacity {
    pub fn is_opaque(self) -> bool {
        self == Opaque
    }

    pub fn is_solid(self) -> bool {
        self != Transparent
    }
}

#[deriving(Clone)]
pub struct Model {
    pub faces: Vec<Face>,
    pub opacity: Opacity,
    pub tint_source: TintSource
}

impl PartialModel {
    fn load<T>(name: &str, assets: &AssetStore, atlas: &mut AtlasBuilder,
               cache: &mut HashMap<String, PartialModel>,
               f: |&PartialModel, &mut AtlasBuilder| -> T) -> T {
        match cache.find_equiv(&name) {
            Some(model) => return f(model, atlas),
            None => {}
        }
        let path = assets.path(format!("minecraft/models/{}.json", name).as_slice());
        let json = json::from_reader(&mut File::open(&path.unwrap()).unwrap()).unwrap();
        let json = json.as_object().unwrap();

        let mut model = match json.find_with(|k| "parent".cmp(&k.as_slice())).and_then(|x| x.as_string()) {
            Some(parent) => PartialModel::load(parent, assets, atlas, cache, |m, _| m.clone()),
            None => PartialModel {
                textures: HashMap::new(),
                faces: vec![],
                full_faces: vec![],
                no_ambient_occlusion: false
            }
        };

        match json.find_with(|k| "ambientocclusion".cmp(&k.as_slice())).and_then(|x| x.as_boolean()) {
            Some(ambient_occlusion) => model.no_ambient_occlusion = !ambient_occlusion,
            None => {}
        }

        match json.find_with(|k| "textures".cmp(&k.as_slice())).and_then(|x| x.as_object()) {
            Some(textures) => for (name, tex) in textures.iter() {
                let tex = tex.as_string().unwrap();
                let tex = if tex.starts_with("#") {
                    TextureVariable(tex.slice_from(1).to_string())
                } else {
                    let (u, v) = atlas.load(tex);
                    TextureCoords(u as f32, v as f32)
                };
                model.textures.insert(name.clone(), tex);
            },
            None => {}
        }
        match json.find_with(|k| "elements".cmp(&k.as_slice())).and_then(|x| x.as_list()) {
            Some(elements) => for element in elements.iter().map(|x| x.as_object().unwrap()) {
                fn array3_num<T>(json: &json::Json, f: |f64| -> T) -> [T, ..3] {
                    Array::from_iter(json.as_list().unwrap().iter().map(|x| f(x.as_f64().unwrap())))
                }
                let from = array3_num(element.find_with(|k| "from".cmp(&k.as_slice())).unwrap(), |x| x as f32 / 16.0);
                let to = array3_num(element.find_with(|k| "to".cmp(&k.as_slice())).unwrap(), |x| x as f32 / 16.0);
                let scale = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];

                let is_full_cube = from == [0.0, 0.0, 0.0] && to == [1.0, 1.0, 1.0];
                let element_start = model.faces.len();

                for (k, v) in element.find_with(|k| "faces".cmp(&k.as_slice())).unwrap().as_object().unwrap().iter() {
                    let face: cube::Face = from_str(k.as_slice()).unwrap();
                    let o = v.as_object().unwrap();
                    let [u0, v0, u1, v1] = match o.find_with(|k| "uv".cmp(&k.as_slice())) {
                        Some(uv) => {
                            Array::from_iter(uv.as_list().unwrap().iter().map(|x| x.as_f64().unwrap() as f32))
                        }
                        None => match face {
                            cube::West | cube::East => [from[2], from[1], to[2], to[1]],
                            cube::Down | cube::Up => [from[0], from[2], to[0], to[2]],
                            cube::North | cube::South => [from[0], from[1], to[0], to[1]]
                        }.map(|x| x * 16.0)
                    };

                    let tex = o.find_with(|k| "texture".cmp(&k.as_slice())).unwrap().as_string().unwrap();
                    assert!(tex.starts_with("#"));
                    let tex = tex.slice_from(1).to_string();

                    let cull_face = o.find_with(|k| "cullface".cmp(&k.as_slice())).map(|s| {
                        from_str(s.as_string().unwrap()).unwrap()
                    });

                    if cull_face.is_some() && cull_face != Some(face) {
                        println!("odd case: cull_face = {} for face = {}", cull_face.unwrap(), face);
                    }

                    let tint = o.find_with(|k| "tintindex".cmp(&k.as_slice())).map(|x| {
                        let x = x.as_i64().unwrap();
                        if x != 0 {
                            println!("odd case: tint_index = {}", x);
                        }
                    }).is_some();

                    if cull_face == Some(face) && is_full_cube {
                        model.full_faces.push(model.faces.len());
                    }

                    let rotation = o.find_with(|k| "rotation".cmp(&k.as_slice())).map_or(Rotate0, |r| {
                        match OrthoRotation::from_json(r) {
                            Some(r) => r,
                            None => fail!("invalid rotation for face {}", r)
                        }
                    });

                    let xyz = face.vertices(from, scale);
                    // Swap vertical texture coordinates.
                    let [v0, v1] = [v1, v0];
                    // Bring texture coordinates closer to avoid seams.
                    let u_center = (u0 + u1) / 2.0;
                    let [u0, u1] = [u0, u1].map(|u| u - (u - u_center).signum() / 128.0);
                    let v_center = (v0 + v1) / 2.0;
                    let [v0, v1] = [v0, v1].map(|v| v - (v - v_center).signum() / 128.0);
                    // Clockwise quad (from bottom-right to top-right).
                    let uvs = [
                        [u1, v0],
                        [u0, v0],
                        [u0, v1],
                        [u1, v1]
                    ].map(|[u, v]| match rotation {
                        Rotate0 => [u, v],
                        Rotate90 => [v, 16.0 - u],
                        Rotate180 => [16.0 - u, 16.0 - v],
                        Rotate270 => [16.0 - v, u]
                    });

                    model.faces.push((Face {
                        vertices: Array::from_fn(|i| Vertex { xyz: xyz[i], uv: uvs[i] }),
                        tint: tint,
                        cull_face: cull_face,
                        ao_face: Some(face)
                    }, tex));
                }

                match element.find_with(|k| "rotation".cmp(&k.as_slice())) {
                    Some(r) => {
                        let r = r.as_object().unwrap();
                        let angle = r.find_with(|k| "angle".cmp(&k.as_slice())).unwrap().as_f64().unwrap();
                        let angle = angle as f32 / 180.0 * PI;
                        let rescale = r.find_with(|k| "rescale".cmp(&k.as_slice())).map_or(false, |x| x.as_boolean().unwrap());
                        let origin = array3_num(r.find_with(|k| "origin".cmp(&k.as_slice())).unwrap(), |x| x as f32 / 16.0);

                        let (s, c) = (angle.sin(), angle.cos());
                        let rot = |ix, iy| {
                            for &(ref mut face, _) in model.faces.mut_slice_from(element_start).mut_iter() {
                                face.ao_face = None;

                                let [ox, oy] = [origin[ix], origin[iy]];
                                for v in face.vertices.mut_iter() {
                                    let [x, y] = [v.xyz[ix] - ox, v.xyz[iy] - oy];
                                    v.xyz[ix] = x * c + y * s;
                                    v.xyz[iy] =-x * s + y * c;
                                }

                                if rescale {
                                    for v in face.vertices.mut_iter() {
                                        v.xyz[ix] *= SQRT2;
                                        v.xyz[iy] *= SQRT2;
                                    }
                                }

                                for v in face.vertices.mut_iter() {
                                    v.xyz[ix] += ox;
                                    v.xyz[iy] += oy;
                                }
                            }
                        };
                        match r.find_with(|k| "axis".cmp(&k.as_slice())).unwrap().as_string().unwrap() {
                            "x" => rot(2, 1),
                            "y" => rot(0, 2),
                            "z" => rot(1, 0),
                            axis => fail!("invalid rotation axis {}", axis)
                        }
                    }
                    None => {}
                }
            },
            None => {}
        }

        f(cache.find_or_insert(name.to_string(), model), atlas)
    }
}

impl Model {
    pub fn load(name: &str, assets: &AssetStore, atlas: &mut AtlasBuilder,
                cache: &mut HashMap<String, PartialModel>) -> Model {
        PartialModel::load(format!("block/{}", name).as_slice(), assets, atlas, cache, |partial, atlas| {
            let mut faces: Vec<Face> = partial.faces.iter().map(|&(mut face, ref tex)| {
                fn texture_coords(textures: &HashMap<String, PartialTexture>,
                                  tex: &String) -> Option<(f32, f32)> {
                    match textures.find(tex) {
                        Some(&TextureVariable(ref tex)) => texture_coords(textures, tex),
                        Some(&TextureCoords(u, v)) => Some((u, v)),
                        None => None
                    }
                }
                let (u, v) = texture_coords(&partial.textures, tex).unwrap();
                for vertex in face.vertices.mut_iter() {
                    vertex.uv[0] += u;
                    vertex.uv[1] += v;
                }
                face
            }).collect();

            let mut full_faces = [Transparent, ..6];
            if partial.full_faces.len() >= 6 {
                for &i in partial.full_faces.iter() {
                    let face = faces[i].cull_face.unwrap() as uint;
                    if full_faces[face] == Opaque {
                        continue;
                    }
                    let (mut min_u, mut min_v) = (INFINITY, INFINITY);
                    let (mut max_u, mut max_v) = (0.0, 0.0);
                    for vertex in faces[i].vertices.iter() {
                        let [u, v] = vertex.uv;
                        min_u = u.min(min_u);
                        min_v = v.min(min_v);
                        max_u = u.max(max_u);
                        max_v = v.max(max_v);
                    }
                    let (u0, v0) = (min_u.floor() as u32, min_v.floor() as u32);
                    let (u1, v1) = (max_u.ceil() as u32, max_v.ceil() as u32);
                    let opacity = match atlas.min_alpha(u0, v0, u1 - u0, v1 - v0) {
                        0 => TransparentSolid,
                        255 => Opaque,
                        _ => TranslucentSolid
                    };
                    if full_faces[face] < opacity {
                        full_faces[face] = opacity;
                    }
                }
            }

            if !partial.no_ambient_occlusion {
                if faces.iter().any(|f| f.ao_face.is_none()) {
                    println!("Warning: model {} uses AO but has faces which are unsuitable", name);
                }
            } else {
                for face in faces.mut_iter() {
                    face.ao_face = None;
                }
            }

            let tint_source = if faces.iter().any(|f| f.tint) {
                match name {
                    name if name.starts_with("grass_") ||
                            name.starts_with("double_grass_") ||
                            name.starts_with("double_fern_") => GrassTint,
                    "reeds" | "fern" | "tall_grass" => GrassTint,
                    name if name.ends_with("_leaves") || name.ends_with("_stem_fruit") ||
                            name.starts_with("vine_") || name.starts_with("stem_") => FoliageTint,
                    "waterlily" => FoliageTint,
                    name if name.starts_with("redstone_") => RedstoneTint,
                    _ => {
                        println!("tint source not known for '{}'", name);
                        NoTint
                    }
                }
            } else {
                NoTint
            };

            Model {
                faces: faces,
                opacity: *full_faces.iter().min().unwrap(),
                tint_source: tint_source
            }
        })
    }

    pub fn empty() -> Model {
        Model {
            faces: Vec::new(),
            opacity: Transparent,
            tint_source: NoTint
        }
    }

    pub fn is_empty(&self) -> bool {
        self.faces.is_empty()
    }
}
<|endoftext|>


<commit_before>//! Fractional Brownian motion and fractional Gaussian noise.

use complex::Complex;
use probability::distribution::{Distribution, Gaussian};
use probability::generator::Generator;

use {Process, Stationary};
use gaussian::circulant_embedding;

macro_rules! hurst(
    ($value:expr) => ({
        let value = $value;
        debug_assert!(value > 0.0 && value < 1.0);
        value
    });
);

macro_rules! step(
    ($value:expr) => ({
        let value = $value;
        debug_assert!(value > 0.0);
        value
    });
);

/// A fractional Brownian motion.
pub struct Motion {
    hurst: f64,
}

/// A fractional Gaussian noise.
pub struct Noise {
    hurst: f64,
    step: f64,
}

impl Motion {
    /// Create a fractional Brownian motion.
    #[inline]
    pub fn new(hurst: f64) -> Motion {
        Motion { hurst: hurst!(hurst) }
    }

    /// Generate a sample path.
    pub fn sample<G>(&self, points: usize, step: f64, generator: &mut G) -> Vec<f64>
        where G: Generator
    {
        match points {
            0 => vec![],
            1 => vec![0.0],
            _ => {
                let mut data = vec![0.0];
                data.extend(Noise::new(self.hurst, step).sample(points - 1, generator));
                for i in 2..points {
                    data[i] += data[i - 1];
                }
                data
            },
        }
    }
}

impl Noise {
    /// Create a fractional Gaussian noise.
    #[inline]
    pub fn new(hurst: f64, step: f64) -> Noise {
        Noise { hurst: hurst!(hurst), step: step!(step) }
    }

    /// Generate a sample path.
    pub fn sample<G>(&self, points: usize, generator: &mut G) -> Vec<f64>
        where G: Generator
    {
        match points {
            0 => vec![],
            1 => vec![Gaussian::new(0.0, Stationary::var(self).sqrt()).sample(generator)],
            _ => {
                let n = points - 1;
                let gaussian = Gaussian::new(0.0, 1.0);
                let data = circulant_embedding(self, n, || gaussian.sample(generator));
                data.iter().take(points).map(|point| point.re()).collect()
            },
        }
    }
}

impl Process for Motion {
    type Index = f64;
    type State = f64;

    fn cov(&self, t: f64, s: f64) -> f64 {
        debug_assert!(t >= 0.0 && s >= 0.0);
        let power = 2.0 * self.hurst;
        0.5 * (t.powf(power) + s.powf(power) - (t - s).abs().powf(power))
    }
}

impl Process for Noise {
    type Index = usize;
    type State = f64;

    #[inline]
    fn cov(&self, t: usize, s: usize) -> f64 {
        Stationary::cov(self, if t < s { s - t } else { t - s })
    }
}

impl Stationary for Noise {
    type Distance = usize;

    fn cov(&self, delta: usize) -> f64 {
        let delta = delta as f64;
        let power = 2.0 * self.hurst;
        let var = self.step.powf(power);
        0.5 * var * ((delta + 1.0).powf(power) - 2.0 * delta.powf(power) +
                     (delta - 1.0).abs().powf(power))
    }
}

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

    #[test]
    fn motion_var() {
        use Process;
        let process = Motion::new(0.25);
        let variances = (0..3).map(|i| process.var(i as f64)).collect::<Vec<_>>();
        assert_eq!(&variances, &[0.0, 1.0, 2f64.sqrt()]);
    }

    #[test]
    fn noise_var() {
        let process = Noise::new(0.42, 1.0);
        {
            use Process;
            let variances = (0..3).map(|i| process.var(i)).collect::<Vec<_>>();
            assert_eq!(&variances, &[1.0, 1.0, 1.0]);
        }
        {
            use Stationary;
            assert_eq!(process.var(), 1.0);
        }
        let process = Noise::new(0.25, 0.01);
        {
            use Process;
            let variances = (0..3).map(|i| process.var(i)).collect::<Vec<_>>();
            assert_eq!(&variances, &[0.1, 0.1, 0.1]);
        }
        {
            use Stationary;
            assert_eq!(process.var(), 0.1);
        }
    }
}
<commit_msg>Update the usage of probability<commit_after>//! Fractional Brownian motion and fractional Gaussian noise.

use complex::Complex;
use probability::distribution::{Distribution, Gaussian};
use probability::prelude::Source;

use {Process, Stationary};
use gaussian::circulant_embedding;

macro_rules! hurst(
    ($value:expr) => ({
        let value = $value;
        debug_assert!(value > 0.0 && value < 1.0);
        value
    });
);

macro_rules! step(
    ($value:expr) => ({
        let value = $value;
        debug_assert!(value > 0.0);
        value
    });
);

/// A fractional Brownian motion.
pub struct Motion {
    hurst: f64,
}

/// A fractional Gaussian noise.
pub struct Noise {
    hurst: f64,
    step: f64,
}

impl Motion {
    /// Create a fractional Brownian motion.
    #[inline]
    pub fn new(hurst: f64) -> Motion {
        Motion { hurst: hurst!(hurst) }
    }

    /// Generate a sample path.
    pub fn sample<S>(&self, points: usize, step: f64, source: &mut S) -> Vec<f64>
        where S: Source
    {
        match points {
            0 => vec![],
            1 => vec![0.0],
            _ => {
                let mut data = vec![0.0];
                data.extend(Noise::new(self.hurst, step).sample(points - 1, source));
                for i in 2..points {
                    data[i] += data[i - 1];
                }
                data
            },
        }
    }
}

impl Noise {
    /// Create a fractional Gaussian noise.
    #[inline]
    pub fn new(hurst: f64, step: f64) -> Noise {
        Noise { hurst: hurst!(hurst), step: step!(step) }
    }

    /// Generate a sample path.
    pub fn sample<S>(&self, points: usize, source: &mut S) -> Vec<f64>
        where S: Source
    {
        match points {
            0 => vec![],
            1 => vec![Gaussian::new(0.0, Stationary::var(self).sqrt()).sample(source)],
            _ => {
                let n = points - 1;
                let gaussian = Gaussian::new(0.0, 1.0);
                let data = circulant_embedding(self, n, || gaussian.sample(source));
                data.iter().take(points).map(|point| point.re()).collect()
            },
        }
    }
}

impl Process for Motion {
    type Index = f64;
    type State = f64;

    fn cov(&self, t: f64, s: f64) -> f64 {
        debug_assert!(t >= 0.0 && s >= 0.0);
        let power = 2.0 * self.hurst;
        0.5 * (t.powf(power) + s.powf(power) - (t - s).abs().powf(power))
    }
}

impl Process for Noise {
    type Index = usize;
    type State = f64;

    #[inline]
    fn cov(&self, t: usize, s: usize) -> f64 {
        Stationary::cov(self, if t < s { s - t } else { t - s })
    }
}

impl Stationary for Noise {
    type Distance = usize;

    fn cov(&self, delta: usize) -> f64 {
        let delta = delta as f64;
        let power = 2.0 * self.hurst;
        let var = self.step.powf(power);
        0.5 * var * ((delta + 1.0).powf(power) - 2.0 * delta.powf(power) +
                     (delta - 1.0).abs().powf(power))
    }
}

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

    #[test]
    fn motion_var() {
        use Process;
        let process = Motion::new(0.25);
        let variances = (0..3).map(|i| process.var(i as f64)).collect::<Vec<_>>();
        assert_eq!(&variances, &[0.0, 1.0, 2f64.sqrt()]);
    }

    #[test]
    fn noise_var() {
        let process = Noise::new(0.42, 1.0);
        {
            use Process;
            let variances = (0..3).map(|i| process.var(i)).collect::<Vec<_>>();
            assert_eq!(&variances, &[1.0, 1.0, 1.0]);
        }
        {
            use Stationary;
            assert_eq!(process.var(), 1.0);
        }
        let process = Noise::new(0.25, 0.01);
        {
            use Process;
            let variances = (0..3).map(|i| process.var(i)).collect::<Vec<_>>();
            assert_eq!(&variances, &[0.1, 0.1, 0.1]);
        }
        {
            use Stationary;
            assert_eq!(process.var(), 0.1);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Add subpel motion search<commit_after><|endoftext|>


<commit_before>use crate::index::diff::Error;
use crate::{Change, CrateVersion};
use bstr::BStr;
use git_repository as git;
use std::collections::BTreeSet;
use std::ops::Range;

#[derive(Default)]
pub(crate) struct Delegate {
    changes: Vec<Change>,
    deleted_version_ids: BTreeSet<u64>,
    err: Option<Error>,
}

impl Delegate {
    pub fn handle(
        &mut self,
        change: git::object::tree::diff::Change<'_, '_, '_>,
    ) -> Result<git::object::tree::diff::Action, Error> {
        use git::bstr::ByteSlice;
        use git::object::tree::diff::change::Event::*;
        use git::objs::tree::EntryMode::*;
        fn entry_data(
            entry: git::objs::tree::EntryMode,
            id: git::Id<'_>,
        ) -> Result<Option<git::Object<'_>>, Error> {
            matches!(entry, Blob | BlobExecutable)
                .then(|| id.object())
                .transpose()
                .map_err(Into::into)
        }
        if change.location.contains(&b'.') {
            return Ok(Default::default());
        }
        match change.event {
            Addition { entry_mode, id } => {
                if let Some(obj) = entry_data(entry_mode, id)? {
                    for line in obj.data.lines() {
                        let version = version_from_json_line(line, change.location)?;
                        self.changes.push(if version.yanked {
                            Change::Yanked(version)
                        } else {
                            Change::Added(version)
                        });
                    }
                }
            }
            Deletion { entry_mode, id, .. } => {
                if entry_mode.is_no_tree() {
                    let obj = id.object()?;
                    let mut deleted = Vec::with_capacity(obj.data.lines().count());
                    for line in obj.data.lines() {
                        deleted.push(version_from_json_line(line.into(), change.location)?);
                    }
                    self.changes.push(Change::Deleted {
                        name: change.location.to_string(),
                        versions: deleted,
                    });
                }
            }
            Modification { .. } => {
                if let Some(diff) = change.event.diff().transpose()? {
                    let location = change.location;

                    let input = diff.line_tokens();
                    let mut err = None;
                    git::diff::blob::diff(
                        diff.algo,
                        &input,
                        |before: Range<u32>, after: Range<u32>| {
                            if err.is_some() {
                                return;
                            }
                            let mut lines_before = input.before
                                [before.start as usize..before.end as usize]
                                .iter()
                                .map(|&line| input.interner[line].as_bstr())
                                .peekable();
                            let mut lines_after = input.after
                                [after.start as usize..after.end as usize]
                                .iter()
                                .map(|&line| input.interner[line].as_bstr())
                                .peekable();
                            let mut remember = |version: CrateVersion| {
                                self.changes.push(if version.yanked {
                                    Change::Yanked(version)
                                } else {
                                    Change::Added(version)
                                });
                            };
                            'outer: loop {
                                match (lines_before.peek().is_some(), lines_after.peek().is_some())
                                {
                                    (true, false) => {
                                        for removed in lines_before {
                                            match version_from_json_line(removed, location) {
                                                Ok(version) => {
                                                    self.deleted_version_ids.insert(version.id());
                                                }
                                                Err(e) => {
                                                    err = Some(e);
                                                    break;
                                                }
                                            }
                                        }
                                        break 'outer;
                                    }
                                    (false, true) => {
                                        for inserted in lines_after {
                                            match version_from_json_line(inserted, location) {
                                                Ok(version) => remember(version),
                                                Err(e) => {
                                                    err = Some(e);
                                                    break;
                                                }
                                            }
                                        }
                                        break 'outer;
                                    }
                                    (true, true) => {
                                        for (removed, inserted) in
                                            lines_before.by_ref().zip(lines_after.by_ref())
                                        {
                                            match version_from_json_line(inserted, location)
                                                .and_then(|inserted| {
                                                    version_from_json_line(removed, location)
                                                        .map(|removed| (removed, inserted))
                                                }) {
                                                Ok((removed_version, inserted_version)) => {
                                                    if removed_version.yanked
                                                        != inserted_version.yanked
                                                    {
                                                        remember(inserted_version);
                                                    }
                                                }
                                                Err(e) => {
                                                    err = Some(e);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                    (false, false) => break 'outer,
                                }
                            }
                        },
                    );
                    if let Some(err) = err {
                        return Err(err);
                    }
                }
            }
        }
        Ok(Default::default())
    }

    pub fn into_result(mut self) -> Result<Vec<Change>, Error> {
        match self.err {
            Some(err) => Err(err),
            None => {
                if !self.deleted_version_ids.is_empty() {
                    let deleted_version_ids = &self.deleted_version_ids;
                    self.changes.retain(|change| match change {
                        Change::Added(v) | Change::Yanked(v) => {
                            !deleted_version_ids.contains(&v.id())
                        }
                        Change::Deleted { .. } => true,
                    })
                }
                Ok(self.changes)
            }
        }
    }
}

fn version_from_json_line(line: &[u8], file_name: &BStr) -> Result<CrateVersion, Error> {
    serde_json::from_slice(line).map_err(|err| Error::VersionDecode {
        source: err,
        file_name: file_name.into(),
        line: line.into(),
    })
}
<commit_msg>thanks clippy<commit_after>use crate::index::diff::Error;
use crate::{Change, CrateVersion};
use bstr::BStr;
use git_repository as git;
use std::collections::BTreeSet;
use std::ops::Range;

#[derive(Default)]
pub(crate) struct Delegate {
    changes: Vec<Change>,
    deleted_version_ids: BTreeSet<u64>,
    err: Option<Error>,
}

impl Delegate {
    pub fn handle(
        &mut self,
        change: git::object::tree::diff::Change<'_, '_, '_>,
    ) -> Result<git::object::tree::diff::Action, Error> {
        use git::bstr::ByteSlice;
        use git::object::tree::diff::change::Event::*;
        use git::objs::tree::EntryMode::*;
        fn entry_data(
            entry: git::objs::tree::EntryMode,
            id: git::Id<'_>,
        ) -> Result<Option<git::Object<'_>>, Error> {
            matches!(entry, Blob | BlobExecutable)
                .then(|| id.object())
                .transpose()
                .map_err(Into::into)
        }
        if change.location.contains(&b'.') {
            return Ok(Default::default());
        }
        match change.event {
            Addition { entry_mode, id } => {
                if let Some(obj) = entry_data(entry_mode, id)? {
                    for line in obj.data.lines() {
                        let version = version_from_json_line(line, change.location)?;
                        self.changes.push(if version.yanked {
                            Change::Yanked(version)
                        } else {
                            Change::Added(version)
                        });
                    }
                }
            }
            Deletion { entry_mode, id, .. } => {
                if entry_mode.is_no_tree() {
                    let obj = id.object()?;
                    let mut deleted = Vec::with_capacity(obj.data.lines().count());
                    for line in obj.data.lines() {
                        deleted.push(version_from_json_line(line, change.location)?);
                    }
                    self.changes.push(Change::Deleted {
                        name: change.location.to_string(),
                        versions: deleted,
                    });
                }
            }
            Modification { .. } => {
                if let Some(diff) = change.event.diff().transpose()? {
                    let location = change.location;

                    let input = diff.line_tokens();
                    let mut err = None;
                    git::diff::blob::diff(
                        diff.algo,
                        &input,
                        |before: Range<u32>, after: Range<u32>| {
                            if err.is_some() {
                                return;
                            }
                            let mut lines_before = input.before
                                [before.start as usize..before.end as usize]
                                .iter()
                                .map(|&line| input.interner[line].as_bstr())
                                .peekable();
                            let mut lines_after = input.after
                                [after.start as usize..after.end as usize]
                                .iter()
                                .map(|&line| input.interner[line].as_bstr())
                                .peekable();
                            let mut remember = |version: CrateVersion| {
                                self.changes.push(if version.yanked {
                                    Change::Yanked(version)
                                } else {
                                    Change::Added(version)
                                });
                            };
                            'outer: loop {
                                match (lines_before.peek().is_some(), lines_after.peek().is_some())
                                {
                                    (true, false) => {
                                        for removed in lines_before {
                                            match version_from_json_line(removed, location) {
                                                Ok(version) => {
                                                    self.deleted_version_ids.insert(version.id());
                                                }
                                                Err(e) => {
                                                    err = Some(e);
                                                    break;
                                                }
                                            }
                                        }
                                        break 'outer;
                                    }
                                    (false, true) => {
                                        for inserted in lines_after {
                                            match version_from_json_line(inserted, location) {
                                                Ok(version) => remember(version),
                                                Err(e) => {
                                                    err = Some(e);
                                                    break;
                                                }
                                            }
                                        }
                                        break 'outer;
                                    }
                                    (true, true) => {
                                        for (removed, inserted) in
                                            lines_before.by_ref().zip(lines_after.by_ref())
                                        {
                                            match version_from_json_line(inserted, location)
                                                .and_then(|inserted| {
                                                    version_from_json_line(removed, location)
                                                        .map(|removed| (removed, inserted))
                                                }) {
                                                Ok((removed_version, inserted_version)) => {
                                                    if removed_version.yanked
                                                        != inserted_version.yanked
                                                    {
                                                        remember(inserted_version);
                                                    }
                                                }
                                                Err(e) => {
                                                    err = Some(e);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                    (false, false) => break 'outer,
                                }
                            }
                        },
                    );
                    if let Some(err) = err {
                        return Err(err);
                    }
                }
            }
        }
        Ok(Default::default())
    }

    pub fn into_result(mut self) -> Result<Vec<Change>, Error> {
        match self.err {
            Some(err) => Err(err),
            None => {
                if !self.deleted_version_ids.is_empty() {
                    let deleted_version_ids = &self.deleted_version_ids;
                    self.changes.retain(|change| match change {
                        Change::Added(v) | Change::Yanked(v) => {
                            !deleted_version_ids.contains(&v.id())
                        }
                        Change::Deleted { .. } => true,
                    })
                }
                Ok(self.changes)
            }
        }
    }
}

fn version_from_json_line(line: &[u8], file_name: &BStr) -> Result<CrateVersion, Error> {
    serde_json::from_slice(line).map_err(|err| Error::VersionDecode {
        source: err,
        file_name: file_name.into(),
        line: line.into(),
    })
}
<|endoftext|>


<commit_before>use super::{colors::Colors, flow_control::Function};
use crate::{
    expansion,
    shell::IonError,
    types::{self, Array},
};
use nix::unistd::{geteuid, gethostname, getpid, getuid};
use scopes::{Namespace, Scope, Scopes};
use std::{env, ffi::CStr, rc::Rc};
use unicode_segmentation::UnicodeSegmentation;

/// Contain a dynamically-typed variable value
pub use types_rs::Value;
/// A structure containing dynamically-typed values organised in scopes
pub struct Variables(Scopes<types::Str, Value<Rc<Function>>>);

impl Variables {
    /// Get all strings
    pub fn string_vars(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
        self.0.scopes().flat_map(|map| {
            map.iter().filter_map(|(key, val)| {
                if let types_rs::Value::Str(val) = val {
                    Some((key, val))
                } else {
                    None
                }
            })
        })
    }

    /// Get all aliases
    pub fn aliases(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, possible_alias)| {
                if let types_rs::Value::Alias(alias) = possible_alias {
                    Some((key, &**alias))
                } else {
                    None
                }
            })
        })
    }

    /// Get all the functions
    pub fn functions(&self) -> impl Iterator<Item = (&types::Str, &Rc<Function>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, val)| {
                if let types_rs::Value::Function(val) = val {
                    Some((key, val))
                } else {
                    None
                }
            })
        })
    }

    /// Get all the variables
    pub fn variables(&self) -> impl Iterator<Item = (&types::Str, &Value<Rc<Function>>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, val)| match val {
                val @ Value::Array(_)
                | val @ Value::Str(_)
                | val @ Value::HashMap(_)
                | val @ Value::BTreeMap(_) => Some((key, val)),
                _ => None,
            })
        })
    }

    /// Get all the array values
    pub fn arrays(&self) -> impl Iterator<Item = (&types::Str, &types::Array<Rc<Function>>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, val)| {
                if let types_rs::Value::Array(val) = val {
                    Some((key, val))
                } else {
                    None
                }
            })
        })
    }

    /// Create a new scope. If namespace is true, variables won't be droppable across the scope
    /// boundary
    pub fn new_scope(&mut self, namespace: bool) {
        self.0.new_scope(namespace)
    }

    /// Exit the current scope
    pub fn pop_scope(&mut self) {
        self.0.pop_scope()
    }

    pub(crate) fn pop_scopes<'b>(
        &'b mut self,
        index: usize,
    ) -> impl Iterator<Item = Scope<types::Str, Value<Rc<Function>>>> + 'b {
        self.0.pop_scopes(index)
    }

    pub(crate) fn append_scopes(&mut self, scopes: Vec<Scope<types::Str, Value<Rc<Function>>>>) {
        self.0.append_scopes(scopes)
    }

    #[must_use]
    pub(crate) fn index_scope_for_var(&self, name: &str) -> Option<usize> {
        self.0.index_scope_for_var(name)
    }

    /// Set a variable to a value in the current scope. If a variable already exists in a writable
    /// scope, it is updated, else a new variable is created in the current scope, possibly
    /// shadowing other variables
    pub fn set<T: Into<Value<Rc<Function>>>>(&mut self, name: &str, value: T) {
        let value = value.into();
        if let Some(val) = self.0.get_mut(name) {
            std::mem::replace(val, value);
        } else {
            self.0.set(name, value);
        }
    }

    /// Obtains the value for the **MWD** variable.
    ///
    /// Further minimizes the directory path in the same manner that Fish does by default.
    /// That is, if more than two parents are visible in the path, all parent directories
    /// of the current directory will be reduced to a single character.
    #[must_use]
    fn get_minimal_directory(&self) -> types::Str {
        let swd = self.get_simplified_directory();

        {
            // Temporarily borrow the `swd` variable while we attempt to assemble a minimal
            // variant of the directory path. If that is not possible, we will cancel the
            // borrow and return `swd` itself as the minified path.
            let elements = swd.split('/').filter(|s| !s.is_empty()).collect::<Vec<&str>>();
            if elements.len() > 2 {
                let mut output = types::Str::new();
                for element in &elements[..elements.len() - 1] {
                    let mut segmenter = UnicodeSegmentation::graphemes(*element, true);
                    let grapheme = segmenter.next().unwrap();
                    output.push_str(grapheme);
                    if grapheme == "." {
                        output.push_str(segmenter.next().unwrap());
                    }
                    output.push('/');
                }
                output.push_str(elements[elements.len() - 1]);
                return output;
            }
        }

        swd
    }

    /// Obtains the value for the **SWD** variable.
    ///
    /// Useful for getting smaller prompts, this will produce a simplified variant of the
    /// working directory which the leading `HOME` prefix replaced with a tilde character.
    #[must_use]
    fn get_simplified_directory(&self) -> types::Str {
        let home = self.get_str("HOME").unwrap_or_else(|_| "?".into());
        env::var("PWD").unwrap().replace(&*home, "~").into()
    }

    /// Indicates if name is valid for functions and variables
    #[must_use]
    pub fn is_valid_name(name: &str) -> bool {
        let mut iter = name.chars();
        iter.next().map_or(false, |c| c.is_alphabetic() || c == '_')
            && iter.all(|c| c.is_alphanumeric() || c == '_')
    }

    /// Remove a variable from the current scope. If the value can't be removed (it is outside a
    /// function or does not exist), returns None
    pub fn remove(&mut self, name: &str) -> Option<Value<Rc<Function>>> {
        if name.starts_with("super::") || name.starts_with("global::") {
            // Cannot mutate outer namespace
            return None;
        }
        self.0.remove_variable(name)
    }

    /// Get the string value associated with a name on the current scope. This includes fetching
    /// env vars, colors & hexes and some extra values like MWD and SWD
    pub fn get_str(&self, name: &str) -> expansion::Result<types::Str, IonError> {
        use expansion::Error;
        match name {
            "MWD" => return Ok(self.get_minimal_directory()),
            "SWD" => return Ok(self.get_simplified_directory()),
            _ => (),
        }
        // If the parsed name contains the '::' pattern, then a namespace was
        // designated. Find it.
        match name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) {
            Some(("c", variable)) | Some(("color", variable)) => {
                Ok(Colors::collect(variable)?.to_string().into())
            }
            Some(("x", variable)) | Some(("hex", variable)) => {
                let c = u8::from_str_radix(variable, 16)
                    .map_err(|cause| Error::InvalidHex(variable.into(), cause))?;
                Ok((c as char).to_string().into())
            }
            Some(("env", variable)) => match env::var(variable) {
                Ok(v) => Ok(v.into()),
                Err(_) => Ok("".into()),
            },
            Some(("super", _)) | Some(("global", _)) | None => {
                // Otherwise, it's just a simple variable name.
                match self.get(name) {
                    Some(Value::Str(val)) => Ok(val.clone()),
                    _ => env::var(name).map(Into::into).map_err(|_| Error::VarNotFound),
                }
            }
            Some((..)) => Err(Error::UnsupportedNamespace(name.into())),
        }
    }

    /// Get a variable on the current scope
    #[must_use]
    pub fn get(&self, mut name: &str) -> Option<&Value<Rc<Function>>> {
        const GLOBAL_NS: &str = "global::";
        const SUPER_NS: &str = "super::";

        let namespace = if name.starts_with(GLOBAL_NS) {
            name = &name[GLOBAL_NS.len()..];
            // Go up as many namespaces as possible
            Namespace::Global
        } else if name.starts_with(SUPER_NS) {
            let mut up = 0;
            while name.starts_with(SUPER_NS) {
                name = &name[SUPER_NS.len()..];
                up += 1;
            }

            Namespace::Specific(up)
        } else {
            Namespace::Any
        };
        self.0.get(name, namespace)
    }

    /// Get a mutable access to a variable on the current scope
    #[must_use]
    pub fn get_mut(&mut self, name: &str) -> Option<&mut Value<Rc<Function>>> {
        if name.starts_with("super::") || name.starts_with("global::") {
            // Cannot mutate outer namespace
            return None;
        }
        self.0.get_mut(name)
    }
}

impl Default for Variables {
    #[must_use]
    fn default() -> Self {
        let mut map: Scopes<types::Str, Value<Rc<Function>>> = Scopes::with_capacity(64);
        map.set("HISTORY_SIZE", "1000");
        map.set("HISTFILE_SIZE", "100000");
        map.set(
            "PROMPT",
            "${x::1B}]0;${USER}: \
             ${PWD}${x::07}${c::0x55,bold}${USER}${c::default}:${c::0x4B}${SWD}${c::default}# \
             ${c::reset}",
        );

        // Set the PID, UID, and EUID variables.
        map.set("PID", Value::Str(getpid().to_string().into()));
        map.set("UID", Value::Str(getuid().to_string().into()));
        map.set("EUID", Value::Str(geteuid().to_string().into()));

        map.set("CDPATH", Array::new());

        // Initialize the HOST variable
        let mut host_name = [0_u8; 512];
        env::set_var(
            "HOST",
            &gethostname(&mut host_name)
                .ok()
                .map_or_else(|| "?".into(), CStr::to_string_lossy)
                .as_ref(),
        );

        Variables(map)
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use super::*;
    use crate::{
        expansion::{Expander, Result, Select},
        shell::IonError,
    };
    use serial_test_derive::serial;

    pub struct VariableExpander(pub Variables);

    impl Expander for VariableExpander {
        type Error = IonError;

        fn string(&self, var: &str) -> Result<types::Str, IonError> {
            self.0.get_str(var)
        }

        fn array(
            &self,
            _variable: &str,
            _selection: &Select<types::Str>,
        ) -> Result<types::Args, Self::Error> {
            Err(expansion::Error::VarNotFound)
        }

        fn command(
            &mut self,
            cmd: &str,
            _set_cmd_duration: bool,
        ) -> Result<types::Str, Self::Error> {
            Ok(cmd.into())
        }

        fn tilde(&self, input: &str) -> Result<types::Str, Self::Error> {
            Ok(input.into())
        }

        fn map_keys(&self, _name: &str) -> Result<types::Args, Self::Error> {
            Err(expansion::Error::VarNotFound)
        }

        fn map_values(&self, _name: &str) -> Result<types::Args, Self::Error> {
            Err(expansion::Error::VarNotFound)
        }
    }

    #[test]
    fn undefined_variable_errors() {
        let variables = Variables::default();
        assert!(VariableExpander(variables).expand_string("$FOO").is_err());
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::default();
        variables.set("FOO", "BAR");
        let expanded = VariableExpander(variables).expand_string("$FOO").unwrap().join("");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    #[serial]
    fn minimal_directory_var_should_compact_path() {
        let variables = Variables::default();
        env::set_var("PWD", "/var/log/nix");
        assert_eq!(
            types::Str::from("v/l/nix"),
            variables.get_str("MWD").expect("no value returned"),
        );
    }

    #[test]
    #[serial]
    fn minimal_directory_var_shouldnt_compact_path() {
        let variables = Variables::default();
        env::set_var("PWD", "/var/log");
        assert_eq!(
            types::Str::from("/var/log"),
            variables.get_str("MWD").expect("no value returned"),
        );
    }
}
<commit_msg>make fmt<commit_after>use super::{colors::Colors, flow_control::Function};
use crate::{
    expansion,
    shell::IonError,
    types::{self, Array},
};
use nix::unistd::{geteuid, gethostname, getpid, getuid};
use scopes::{Namespace, Scope, Scopes};
use std::{env, ffi::CStr, rc::Rc};
use unicode_segmentation::UnicodeSegmentation;

/// Contain a dynamically-typed variable value
pub use types_rs::Value;
/// A structure containing dynamically-typed values organised in scopes
pub struct Variables(Scopes<types::Str, Value<Rc<Function>>>);

impl Variables {
    /// Get all strings
    pub fn string_vars(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
        self.0.scopes().flat_map(|map| {
            map.iter().filter_map(|(key, val)| {
                if let types_rs::Value::Str(val) = val {
                    Some((key, val))
                } else {
                    None
                }
            })
        })
    }

    /// Get all aliases
    pub fn aliases(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, possible_alias)| {
                if let types_rs::Value::Alias(alias) = possible_alias {
                    Some((key, &**alias))
                } else {
                    None
                }
            })
        })
    }

    /// Get all the functions
    pub fn functions(&self) -> impl Iterator<Item = (&types::Str, &Rc<Function>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, val)| {
                if let types_rs::Value::Function(val) = val {
                    Some((key, val))
                } else {
                    None
                }
            })
        })
    }

    /// Get all the variables
    pub fn variables(&self) -> impl Iterator<Item = (&types::Str, &Value<Rc<Function>>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, val)| match val {
                val @ Value::Array(_)
                | val @ Value::Str(_)
                | val @ Value::HashMap(_)
                | val @ Value::BTreeMap(_) => Some((key, val)),
                _ => None,
            })
        })
    }

    /// Get all the array values
    pub fn arrays(&self) -> impl Iterator<Item = (&types::Str, &types::Array<Rc<Function>>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, val)| {
                if let types_rs::Value::Array(val) = val {
                    Some((key, val))
                } else {
                    None
                }
            })
        })
    }

    /// Create a new scope. If namespace is true, variables won't be droppable across the scope
    /// boundary
    pub fn new_scope(&mut self, namespace: bool) { self.0.new_scope(namespace) }

    /// Exit the current scope
    pub fn pop_scope(&mut self) { self.0.pop_scope() }

    pub(crate) fn pop_scopes<'b>(
        &'b mut self,
        index: usize,
    ) -> impl Iterator<Item = Scope<types::Str, Value<Rc<Function>>>> + 'b {
        self.0.pop_scopes(index)
    }

    pub(crate) fn append_scopes(&mut self, scopes: Vec<Scope<types::Str, Value<Rc<Function>>>>) {
        self.0.append_scopes(scopes)
    }

    #[must_use]
    pub(crate) fn index_scope_for_var(&self, name: &str) -> Option<usize> {
        self.0.index_scope_for_var(name)
    }

    /// Set a variable to a value in the current scope. If a variable already exists in a writable
    /// scope, it is updated, else a new variable is created in the current scope, possibly
    /// shadowing other variables
    pub fn set<T: Into<Value<Rc<Function>>>>(&mut self, name: &str, value: T) {
        let value = value.into();
        if let Some(val) = self.0.get_mut(name) {
            std::mem::replace(val, value);
        } else {
            self.0.set(name, value);
        }
    }

    /// Obtains the value for the **MWD** variable.
    ///
    /// Further minimizes the directory path in the same manner that Fish does by default.
    /// That is, if more than two parents are visible in the path, all parent directories
    /// of the current directory will be reduced to a single character.
    #[must_use]
    fn get_minimal_directory(&self) -> types::Str {
        let swd = self.get_simplified_directory();

        {
            // Temporarily borrow the `swd` variable while we attempt to assemble a minimal
            // variant of the directory path. If that is not possible, we will cancel the
            // borrow and return `swd` itself as the minified path.
            let elements = swd.split('/').filter(|s| !s.is_empty()).collect::<Vec<&str>>();
            if elements.len() > 2 {
                let mut output = types::Str::new();
                for element in &elements[..elements.len() - 1] {
                    let mut segmenter = UnicodeSegmentation::graphemes(*element, true);
                    let grapheme = segmenter.next().unwrap();
                    output.push_str(grapheme);
                    if grapheme == "." {
                        output.push_str(segmenter.next().unwrap());
                    }
                    output.push('/');
                }
                output.push_str(elements[elements.len() - 1]);
                return output;
            }
        }

        swd
    }

    /// Obtains the value for the **SWD** variable.
    ///
    /// Useful for getting smaller prompts, this will produce a simplified variant of the
    /// working directory which the leading `HOME` prefix replaced with a tilde character.
    #[must_use]
    fn get_simplified_directory(&self) -> types::Str {
        let home = self.get_str("HOME").unwrap_or_else(|_| "?".into());
        env::var("PWD").unwrap().replace(&*home, "~").into()
    }

    /// Indicates if name is valid for functions and variables
    #[must_use]
    pub fn is_valid_name(name: &str) -> bool {
        let mut iter = name.chars();
        iter.next().map_or(false, |c| c.is_alphabetic() || c == '_')
            && iter.all(|c| c.is_alphanumeric() || c == '_')
    }

    /// Remove a variable from the current scope. If the value can't be removed (it is outside a
    /// function or does not exist), returns None
    pub fn remove(&mut self, name: &str) -> Option<Value<Rc<Function>>> {
        if name.starts_with("super::") || name.starts_with("global::") {
            // Cannot mutate outer namespace
            return None;
        }
        self.0.remove_variable(name)
    }

    /// Get the string value associated with a name on the current scope. This includes fetching
    /// env vars, colors & hexes and some extra values like MWD and SWD
    pub fn get_str(&self, name: &str) -> expansion::Result<types::Str, IonError> {
        use expansion::Error;
        match name {
            "MWD" => return Ok(self.get_minimal_directory()),
            "SWD" => return Ok(self.get_simplified_directory()),
            _ => (),
        }
        // If the parsed name contains the '::' pattern, then a namespace was
        // designated. Find it.
        match name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) {
            Some(("c", variable)) | Some(("color", variable)) => {
                Ok(Colors::collect(variable)?.to_string().into())
            }
            Some(("x", variable)) | Some(("hex", variable)) => {
                let c = u8::from_str_radix(variable, 16)
                    .map_err(|cause| Error::InvalidHex(variable.into(), cause))?;
                Ok((c as char).to_string().into())
            }
            Some(("env", variable)) => match env::var(variable) {
                Ok(v) => Ok(v.into()),
                Err(_) => Ok("".into()),
            },
            Some(("super", _)) | Some(("global", _)) | None => {
                // Otherwise, it's just a simple variable name.
                match self.get(name) {
                    Some(Value::Str(val)) => Ok(val.clone()),
                    _ => env::var(name).map(Into::into).map_err(|_| Error::VarNotFound),
                }
            }
            Some((..)) => Err(Error::UnsupportedNamespace(name.into())),
        }
    }

    /// Get a variable on the current scope
    #[must_use]
    pub fn get(&self, mut name: &str) -> Option<&Value<Rc<Function>>> {
        const GLOBAL_NS: &str = "global::";
        const SUPER_NS: &str = "super::";

        let namespace = if name.starts_with(GLOBAL_NS) {
            name = &name[GLOBAL_NS.len()..];
            // Go up as many namespaces as possible
            Namespace::Global
        } else if name.starts_with(SUPER_NS) {
            let mut up = 0;
            while name.starts_with(SUPER_NS) {
                name = &name[SUPER_NS.len()..];
                up += 1;
            }

            Namespace::Specific(up)
        } else {
            Namespace::Any
        };
        self.0.get(name, namespace)
    }

    /// Get a mutable access to a variable on the current scope
    #[must_use]
    pub fn get_mut(&mut self, name: &str) -> Option<&mut Value<Rc<Function>>> {
        if name.starts_with("super::") || name.starts_with("global::") {
            // Cannot mutate outer namespace
            return None;
        }
        self.0.get_mut(name)
    }
}

impl Default for Variables {
    #[must_use]
    fn default() -> Self {
        let mut map: Scopes<types::Str, Value<Rc<Function>>> = Scopes::with_capacity(64);
        map.set("HISTORY_SIZE", "1000");
        map.set("HISTFILE_SIZE", "100000");
        map.set(
            "PROMPT",
            "${x::1B}]0;${USER}: \
             ${PWD}${x::07}${c::0x55,bold}${USER}${c::default}:${c::0x4B}${SWD}${c::default}# \
             ${c::reset}",
        );

        // Set the PID, UID, and EUID variables.
        map.set("PID", Value::Str(getpid().to_string().into()));
        map.set("UID", Value::Str(getuid().to_string().into()));
        map.set("EUID", Value::Str(geteuid().to_string().into()));

        map.set("CDPATH", Array::new());

        // Initialize the HOST variable
        let mut host_name = [0_u8; 512];
        env::set_var(
            "HOST",
            &gethostname(&mut host_name)
                .ok()
                .map_or_else(|| "?".into(), CStr::to_string_lossy)
                .as_ref(),
        );

        Variables(map)
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use super::*;
    use crate::{
        expansion::{Expander, Result, Select},
        shell::IonError,
    };
    use serial_test_derive::serial;

    pub struct VariableExpander(pub Variables);

    impl Expander for VariableExpander {
        type Error = IonError;

        fn string(&self, var: &str) -> Result<types::Str, IonError> { self.0.get_str(var) }

        fn array(
            &self,
            _variable: &str,
            _selection: &Select<types::Str>,
        ) -> Result<types::Args, Self::Error> {
            Err(expansion::Error::VarNotFound)
        }

        fn command(
            &mut self,
            cmd: &str,
            _set_cmd_duration: bool,
        ) -> Result<types::Str, Self::Error> {
            Ok(cmd.into())
        }

        fn tilde(&self, input: &str) -> Result<types::Str, Self::Error> { Ok(input.into()) }

        fn map_keys(&self, _name: &str) -> Result<types::Args, Self::Error> {
            Err(expansion::Error::VarNotFound)
        }

        fn map_values(&self, _name: &str) -> Result<types::Args, Self::Error> {
            Err(expansion::Error::VarNotFound)
        }
    }

    #[test]
    fn undefined_variable_errors() {
        let variables = Variables::default();
        assert!(VariableExpander(variables).expand_string("$FOO").is_err());
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::default();
        variables.set("FOO", "BAR");
        let expanded = VariableExpander(variables).expand_string("$FOO").unwrap().join("");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    #[serial]
    fn minimal_directory_var_should_compact_path() {
        let variables = Variables::default();
        env::set_var("PWD", "/var/log/nix");
        assert_eq!(
            types::Str::from("v/l/nix"),
            variables.get_str("MWD").expect("no value returned"),
        );
    }

    #[test]
    #[serial]
    fn minimal_directory_var_shouldnt_compact_path() {
        let variables = Variables::default();
        env::set_var("PWD", "/var/log");
        assert_eq!(
            types::Str::from("/var/log"),
            variables.get_str("MWD").expect("no value returned"),
        );
    }
}
<|endoftext|>


<commit_before>use std::alloc::{Global, Alloc, Layout, System};

/// Issue #45955.
#[test]
fn alloc_system_overaligned_request() {
    check_overalign_requests(System)
}

#[test]
fn std_heap_overaligned_request() {
    check_overalign_requests(Global)
}

fn check_overalign_requests<T: Alloc>(mut allocator: T) {
    let size = 8;
    let align = 16; // greater than size
    let iterations = 100;
    unsafe {
        let pointers: Vec<_> = (0..iterations).map(|_| {
            allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap()
        }).collect();
        for &ptr in &pointers {
            assert_eq!((ptr.as_ptr() as usize) % align, 0,
                       "Got a pointer less aligned than requested")
        }

        // Clean up
        for &ptr in &pointers {
            allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
        }
    }
}
<commit_msg>test more possible overaligned requests<commit_after>use std::alloc::{Global, Alloc, Layout, System};

/// Issue #45955 and #62251.
#[test]
fn alloc_system_overaligned_request() {
    check_overalign_requests(System)
}

#[test]
fn std_heap_overaligned_request() {
    check_overalign_requests(Global)
}

fn check_overalign_requests<T: Alloc>(mut allocator: T) {
    for &align in &[4, 8, 16, 32] { // less than and bigger than `MIN_ALIGN`
        for &size in &[align/2, align-1] { // size less than alignment
            let iterations = 128;
            unsafe {
                let pointers: Vec<_> = (0..iterations).map(|_| {
                    allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap()
                }).collect();
                for &ptr in &pointers {
                    assert_eq!((ptr.as_ptr() as usize) % align, 0,
                               "Got a pointer less aligned than requested")
                }

                // Clean up
                for &ptr in &pointers {
                    allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
                }
            }
        }
    }
}
<|endoftext|>