<commit_before>#![allow(unsafe_code)]

use std::{
    alloc::{alloc, dealloc, Layout},
    convert::TryFrom,
    fmt,
    hash::{Hash, Hasher},
    iter::FromIterator,
    mem::size_of,
    ops::{Deref, DerefMut},
    sync::atomic::{AtomicUsize, Ordering},
};

const SZ: usize = size_of::<usize>() * 2;
const CUTOFF: usize = SZ - 1;

/// A buffer that may either be inline or remote and protected
/// by an Arc. The inner buffer is guaranteed to be aligned to
/// 8 byte boundaries.
#[repr(align(8))]
pub struct IVec([u8; SZ]);

impl Clone for IVec {
    fn clone(&self) -> IVec {
        if !self.is_inline() {
            self.deref_header().rc.fetch_add(1, Ordering::Relaxed);
        }
        IVec(self.0)
    }
}

impl Drop for IVec {
    fn drop(&mut self) {
        if !self.is_inline() {
            let rc = self.deref_header().rc.fetch_sub(1, Ordering::Release) - 1;

            if rc == 0 {
                let layout = Layout::from_size_align(
                    self.deref_header().len + size_of::<RemoteHeader>(),
                    8,
                )
                .unwrap();

                std::sync::atomic::fence(Ordering::Acquire);

                unsafe {
                    dealloc(self.remote_ptr() as *mut u8, layout);
                }
            }
        }
    }
}

struct RemoteHeader {
    rc: AtomicUsize,
    len: usize,
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.is_inline() {
            &self.0[..self.inline_len()]
        } else {
            unsafe {
                let data_ptr = self.remote_ptr().add(size_of::<RemoteHeader>());
                let len = self.deref_header().len;
                std::slice::from_raw_parts(data_ptr, len)
            }
        }
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self
    }
}

impl DerefMut for IVec {
    #[inline]
    fn deref_mut(&mut self) -> &mut [u8] {
        let inline_len = self.inline_len();
        if self.is_inline() {
            &mut self.0[..inline_len]
        } else {
            self.make_mut();
            unsafe {
                let data_ptr = self.remote_ptr().add(size_of::<RemoteHeader>());
                let len = self.deref_header().len;
                std::slice::from_raw_parts_mut(data_ptr as *mut u8, len)
            }
        }
    }
}

impl AsMut<[u8]> for IVec {
    #[inline]
    fn as_mut(&mut self) -> &mut [u8] {
        self.deref_mut()
    }
}

impl Default for IVec {
    fn default() -> Self {
        Self::from(&[])
    }
}

impl Hash for IVec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.deref().hash(state);
    }
}

impl IVec {
    fn new(slice: &[u8]) -> Self {
        let mut data = [0_u8; SZ];
        if slice.len() <= CUTOFF {
            data[SZ - 1] = (u8::try_from(slice.len()).unwrap() << 1) | 1;
            data[..slice.len()].copy_from_slice(slice);
        } else {
            let layout = Layout::from_size_align(
                slice.len() + size_of::<RemoteHeader>(),
                8,
            )
            .unwrap();

            let header = RemoteHeader { rc: 1.into(), len: slice.len() };

            unsafe {
                let ptr = alloc(layout);

                std::ptr::write(ptr as *mut RemoteHeader, header);
                std::ptr::copy_nonoverlapping(
                    slice.as_ptr(),
                    ptr.add(size_of::<RemoteHeader>()),
                    slice.len(),
                );
                std::ptr::write_unaligned(data.as_mut_ptr() as _, ptr);
            }

            assert_eq!(data[SZ - 1], 0);
        }
        Self(data)
    }

    fn remote_ptr(&self) -> *const u8 {
        assert!(!self.is_inline());
        unsafe { std::ptr::read(self.0.as_ptr() as *const *const u8) }
    }

    fn deref_header(&self) -> &RemoteHeader {
        assert!(!self.is_inline());
        unsafe { &*(self.remote_ptr() as *mut RemoteHeader) }
    }

    const fn inline_len(&self) -> usize {
        (self.trailer() >> 1) as usize
    }

    const fn is_inline(&self) -> bool {
        self.trailer() & 1 == 1
    }

    const fn trailer(&self) -> u8 {
        self.0[SZ - 1]
    }

    fn make_mut(&mut self) {
        assert!(!self.is_inline());
        if self.deref_header().rc.load(Ordering::Acquire) != 1 {
            *self = IVec::from(self.deref())
        }
    }
}

impl FromIterator<u8> for IVec {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = u8>,
    {
        let bs: Vec<u8> = iter.into_iter().collect();
        bs.into()
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> Self {
        IVec::new(slice)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> Self {
        Self::from(s.as_bytes())
    }
}

impl From<String> for IVec {
    fn from(s: String) -> Self {
        Self::from(s.as_bytes())
    }
}

impl From<&String> for IVec {
    fn from(s: &String) -> Self {
        Self::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &Self) -> Self {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> Self {
        IVec::new(&v)
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(v: Box<[u8]>) -> Self {
        IVec::new(&v)
    }
}

impl std::borrow::Borrow<[u8]> for IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl std::borrow::Borrow<[u8]> for &IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

macro_rules! from_array {
    ($($s:expr),*) => {
        $(
            impl From<&[u8; $s]> for IVec {
                fn from(v: &[u8; $s]) -> Self {
                    Self::from(&v[..])
                }
            }
        )*
    }
}

from_array!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
);

impl Ord for IVec {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec {}

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[cfg(test)]
mod qc {
    use super::IVec;

    #[test]
    fn ivec_usage() {
        let iv1 = IVec::from(vec![1, 2, 3]);
        assert_eq!(iv1, vec![1, 2, 3]);
        let iv2 = IVec::from(&[4; 128][..]);
        assert_eq!(iv2, vec![4; 128]);
    }

    #[test]
    fn boxed_slice_conversion() {
        let boite1: Box<[u8]> = Box::new([1, 2, 3]);
        let iv1: IVec = boite1.into();
        assert_eq!(iv1, vec![1, 2, 3]);
        let boite2: Box<[u8]> = Box::new([4; 128]);
        let iv2: IVec = boite2.into();
        assert_eq!(iv2, vec![4; 128]);
    }

    #[test]
    fn ivec_as_mut_identity() {
        let initial = &[1];
        let mut iv = IVec::from(initial);
        assert_eq!(&*initial, &*iv);
        assert_eq!(&*initial, &mut *iv);
        assert_eq!(&*initial, iv.as_mut());
    }

    fn prop_identity(ivec: &IVec) -> bool {
        let mut iv2 = ivec.clone();

        if iv2 != ivec {
            println!("expected clone to equal original");
            return false;
        }

        if *ivec != *iv2 {
            println!("expected AsMut to equal original");
            return false;
        }

        if *ivec != iv2.as_mut() {
            println!("expected AsMut to equal original");
            return false;
        }

        true
    }

    quickcheck::quickcheck! {
        #[cfg_attr(miri, ignore)]
        fn ivec(item: IVec) -> bool {
            prop_identity(&item)
        }
    }

    #[test]
    fn ivec_bug_00() {
        assert!(prop_identity(&IVec::new(&[
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        ])));
    }
}
<commit_msg>Cut IVec size down to 8 bytes<commit_after>#![allow(unsafe_code)]

use std::{
    alloc::{alloc, dealloc, Layout},
    convert::TryFrom,
    fmt,
    hash::{Hash, Hasher},
    iter::FromIterator,
    mem::size_of,
    ops::{Deref, DerefMut},
    sync::atomic::{AtomicUsize, Ordering},
};

const SZ: usize = size_of::<usize>();
const CUTOFF: usize = SZ - 1;

/// A buffer that may either be inline or remote and protected
/// by an Arc. The inner buffer is guaranteed to be aligned to
/// 8 byte boundaries.
#[repr(align(8))]
pub struct IVec([u8; SZ]);

impl Clone for IVec {
    fn clone(&self) -> IVec {
        if !self.is_inline() {
            self.deref_header().rc.fetch_add(1, Ordering::Relaxed);
        }
        IVec(self.0)
    }
}

impl Drop for IVec {
    fn drop(&mut self) {
        if !self.is_inline() {
            let rc = self.deref_header().rc.fetch_sub(1, Ordering::Release) - 1;

            if rc == 0 {
                let layout = Layout::from_size_align(
                    self.deref_header().len + size_of::<RemoteHeader>(),
                    8,
                )
                .unwrap();

                std::sync::atomic::fence(Ordering::Acquire);

                unsafe {
                    dealloc(self.remote_ptr() as *mut u8, layout);
                }
            }
        }
    }
}

struct RemoteHeader {
    rc: AtomicUsize,
    len: usize,
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.is_inline() {
            &self.0[..self.inline_len()]
        } else {
            unsafe {
                let data_ptr = self.remote_ptr().add(size_of::<RemoteHeader>());
                let len = self.deref_header().len;
                std::slice::from_raw_parts(data_ptr, len)
            }
        }
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self
    }
}

impl DerefMut for IVec {
    #[inline]
    fn deref_mut(&mut self) -> &mut [u8] {
        let inline_len = self.inline_len();
        if self.is_inline() {
            &mut self.0[..inline_len]
        } else {
            self.make_mut();
            unsafe {
                let data_ptr = self.remote_ptr().add(size_of::<RemoteHeader>());
                let len = self.deref_header().len;
                std::slice::from_raw_parts_mut(data_ptr as *mut u8, len)
            }
        }
    }
}

impl AsMut<[u8]> for IVec {
    #[inline]
    fn as_mut(&mut self) -> &mut [u8] {
        self.deref_mut()
    }
}

impl Default for IVec {
    fn default() -> Self {
        Self::from(&[])
    }
}

impl Hash for IVec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.deref().hash(state);
    }
}

impl IVec {
    fn new(slice: &[u8]) -> Self {
        let mut data = [0_u8; SZ];
        if slice.len() <= CUTOFF {
            data[SZ - 1] = (u8::try_from(slice.len()).unwrap() << 1) | 1;
            data[..slice.len()].copy_from_slice(slice);
        } else {
            let layout = Layout::from_size_align(
                slice.len() + size_of::<RemoteHeader>(),
                8,
            )
            .unwrap();

            let header = RemoteHeader { rc: 1.into(), len: slice.len() };

            unsafe {
                let ptr = alloc(layout);

                std::ptr::write(ptr as *mut RemoteHeader, header);
                std::ptr::copy_nonoverlapping(
                    slice.as_ptr(),
                    ptr.add(size_of::<RemoteHeader>()),
                    slice.len(),
                );
                std::ptr::write_unaligned(data.as_mut_ptr() as _, ptr);
            }

            assert_eq!(data[SZ - 1] & 1, 0);
        }
        Self(data)
    }

    fn remote_ptr(&self) -> *const u8 {
        assert!(!self.is_inline());
        unsafe { std::ptr::read(self.0.as_ptr() as *const *const u8) }
    }

    fn deref_header(&self) -> &RemoteHeader {
        assert!(!self.is_inline());
        unsafe { &*(self.remote_ptr() as *mut RemoteHeader) }
    }

    const fn inline_len(&self) -> usize {
        (self.trailer() >> 1) as usize
    }

    const fn is_inline(&self) -> bool {
        self.trailer() & 1 == 1
    }

    const fn trailer(&self) -> u8 {
        self.0[SZ - 1]
    }

    fn make_mut(&mut self) {
        assert!(!self.is_inline());
        if self.deref_header().rc.load(Ordering::Acquire) != 1 {
            *self = IVec::from(self.deref())
        }
    }
}

impl FromIterator<u8> for IVec {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = u8>,
    {
        let bs: Vec<u8> = iter.into_iter().collect();
        bs.into()
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> Self {
        IVec::new(slice)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> Self {
        Self::from(s.as_bytes())
    }
}

impl From<String> for IVec {
    fn from(s: String) -> Self {
        Self::from(s.as_bytes())
    }
}

impl From<&String> for IVec {
    fn from(s: &String) -> Self {
        Self::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &Self) -> Self {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> Self {
        IVec::new(&v)
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(v: Box<[u8]>) -> Self {
        IVec::new(&v)
    }
}

impl std::borrow::Borrow<[u8]> for IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl std::borrow::Borrow<[u8]> for &IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

macro_rules! from_array {
    ($($s:expr),*) => {
        $(
            impl From<&[u8; $s]> for IVec {
                fn from(v: &[u8; $s]) -> Self {
                    Self::from(&v[..])
                }
            }
        )*
    }
}

from_array!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
);

impl Ord for IVec {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec {}

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[cfg(test)]
mod qc {
    use super::IVec;

    #[test]
    fn ivec_usage() {
        let iv1 = IVec::from(vec![1, 2, 3]);
        assert_eq!(iv1, vec![1, 2, 3]);
        let iv2 = IVec::from(&[4; 128][..]);
        assert_eq!(iv2, vec![4; 128]);
    }

    #[test]
    fn boxed_slice_conversion() {
        let boite1: Box<[u8]> = Box::new([1, 2, 3]);
        let iv1: IVec = boite1.into();
        assert_eq!(iv1, vec![1, 2, 3]);
        let boite2: Box<[u8]> = Box::new([4; 128]);
        let iv2: IVec = boite2.into();
        assert_eq!(iv2, vec![4; 128]);
    }

    #[test]
    fn ivec_as_mut_identity() {
        let initial = &[1];
        let mut iv = IVec::from(initial);
        assert_eq!(&*initial, &*iv);
        assert_eq!(&*initial, &mut *iv);
        assert_eq!(&*initial, iv.as_mut());
    }

    fn prop_identity(ivec: &IVec) -> bool {
        let mut iv2 = ivec.clone();

        if iv2 != ivec {
            println!("expected clone to equal original");
            return false;
        }

        if *ivec != *iv2 {
            println!("expected AsMut to equal original");
            return false;
        }

        if *ivec != iv2.as_mut() {
            println!("expected AsMut to equal original");
            return false;
        }

        true
    }

    quickcheck::quickcheck! {
        #[cfg_attr(miri, ignore)]
        fn ivec(item: IVec) -> bool {
            prop_identity(&item)
        }
    }

    #[test]
    fn ivec_bug_00() {
        assert!(prop_identity(&IVec::new(&[
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        ])));
    }
}
<|endoftext|>


<commit_before>//! Draw Line

use current::{ Get, Modifier, Set };
use internal;
use triangulation;
use BackEnd;
use Context;
use ImageSize;
use Color;

/// The shape of the line
pub enum Shape {
    /// Square edges
    Square,
    /// Round edges
    Round,
    /// Bevel edges
    Bevel,
}

/// Wrapper trait for `Get<Shape>`
pub trait GetShape: Get<Shape> {
    /// Get shape
    #[inline(always)]
    fn get_shape(&self) -> Shape {
        self.get()
    }
}

impl<T: Get<Shape>> GetShape for T {}

/// Wrapper trait for `Set<Shape>`
pub trait SetShape: Set<Shape> {
    /// Set shape
    #[inline(always)]
    fn set_shape(&mut self, val: Shape) {
        self.set_mut(val);
    }
}

impl<T: Set<Shape>> SetShape for T {}

/// The line border radius
pub struct Radius(pub internal::Radius);

/// Wrapper trait for `Get<Radius>`
pub trait GetRadius: Get<Radius> {
    /// Get radius
    #[inline(always)]
    fn get_radius(&self) -> Radius {
        self.get()
    }
}

impl<T: Get<Radius>> GetRadius for T {}

/// Wrapper trait for `Set<Radius>`
pub trait SetRadius: Set<Radius> {
    /// Set radius
    #[inline(always)]
    fn set_radius(&mut self, val: Radius) {
        self.set_mut(val);
    }
}

impl<T: Set<Radius>> SetRadius for T {}

/// The line border width
pub struct Width(pub internal::Width);

/// Wrapper trait for `Get<Width>`
pub trait GetWidth: Get<Width> {
    /// Get width
    #[inline(always)]
    fn get_width(&self) -> Width {
        self.get()
    }
}

impl<T: Get<Width>> GetWidth for T {}

/// Wrapper trait for `Set<Width>`
pub trait SetWidth: Set<Width> {
    /// Set width
    #[inline(always)]
    fn set_width(&mut self, val: Width) {
        self.set_mut(val);
    }
}

impl<T: Set<Width>> SetWidth for T {}

/// A colored line with a default border radius
#[deriving(Copy)]
pub struct Line {
    /// The line color
    pub color: internal::Color,
    /// The line radius
    pub radius: internal::Radius,
    /// The line shape
    pub shape: Shape,
}

impl Line {
    /// Creates a new line
    pub fn new(color: internal::Color, radius: internal::Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Square,
        }
    }

    /// Draw the line.
    pub fn draw<B: BackEnd<I>, I: ImageSize>(
        &self,
        line: internal::Line,
        c: &Context,
        back_end: &mut B
    ) {
        // Complete transparency does not need to be rendered.
        if self.color[3] == 0.0 { return; }
        back_end.color(self.color);
        match self.shape {
            Shape::Square => {
                triangulation::with_round_border_line_tri_list(
                    2,
                    c.transform,
                    line,
                    self.radius,
                    |vertices| back_end.tri_list(vertices)
                );
            }
            Shape::Round => {
                triangulation::with_round_border_line_tri_list(
                    64,
                    c.transform,
                    line,
                    self.radius,
                    |vertices| back_end.tri_list(vertices)
                );
            }
            Shape::Bevel => {
                triangulation::with_round_border_line_tri_list(
                    3,
                    c.transform,
                    line,
                    self.radius,
                    |vertices| back_end.tri_list(vertices)
                );
            }
        }
    }
}

impl Modifier<Line> for Color {
    #[inline(always)]
    fn modify(self, l: &mut Line) {
        let Color(val) = self;
        l.color = val;
    }
}

impl Get<Color> for Line {
    #[inline(always)]
    fn get(&self) -> Color {
        Color(self.color)
    }
}

impl Modifier<Line> for Radius {
    #[inline(always)]
    fn modify(self, l: &mut Line) {
        let Radius(val) = self;
        l.radius = val;
    }
}

impl Get<Radius> for Line {
    #[inline(always)]
    fn get(&self) -> Radius {
        Radius(self.radius)
    }
}

impl Modifier<Line> for Width {
    #[inline(always)]
    fn modify(self, l: &mut Line) {
        let Width(val) = self;
        l.radius = 0.5 * val;
    }
}

impl Get<Width> for Line {
    #[inline(always)]
    fn get(&self) -> Width {
        Width(2.0 * self.radius)
    }
}

impl Modifier<Line> for Shape {
    #[inline(always)]
    fn modify(self, l: &mut Line) {
        l.shape = self;
    }
}

impl Get<Shape> for Line {
    #[inline(always)]
    fn get(&self) -> Shape {
        self.shape
    }
}

#[cfg(test)]
mod test {
    use current::Set;
    use super::Line;
    use super::Shape;
    use super::Radius;
    use Color;

    #[test]
    fn test_line() {
        let _line = Line::new([0.0, ..4], 3.0)
            .set(Color([1.0, ..4]))
            .set(Radius(3.0))
            .set(Shape::Round);
    }
}
<commit_msg>Added round constructor to Line<commit_after>//! Draw Line

use current::{ Get, Modifier, Set };
use internal;
use triangulation;
use BackEnd;
use Context;
use ImageSize;
use Color;

/// The shape of the line
pub enum Shape {
    /// Square edges
    Square,
    /// Round edges
    Round,
    /// Bevel edges
    Bevel,
}

/// Wrapper trait for `Get<Shape>`
pub trait GetShape: Get<Shape> {
    /// Get shape
    #[inline(always)]
    fn get_shape(&self) -> Shape {
        self.get()
    }
}

impl<T: Get<Shape>> GetShape for T {}

/// Wrapper trait for `Set<Shape>`
pub trait SetShape: Set<Shape> {
    /// Set shape
    #[inline(always)]
    fn set_shape(&mut self, val: Shape) {
        self.set_mut(val);
    }
}

impl<T: Set<Shape>> SetShape for T {}

/// The line border radius
pub struct Radius(pub internal::Radius);

/// Wrapper trait for `Get<Radius>`
pub trait GetRadius: Get<Radius> {
    /// Get radius
    #[inline(always)]
    fn get_radius(&self) -> Radius {
        self.get()
    }
}

impl<T: Get<Radius>> GetRadius for T {}

/// Wrapper trait for `Set<Radius>`
pub trait SetRadius: Set<Radius> {
    /// Set radius
    #[inline(always)]
    fn set_radius(&mut self, val: Radius) {
        self.set_mut(val);
    }
}

impl<T: Set<Radius>> SetRadius for T {}

/// The line border width
pub struct Width(pub internal::Width);

/// Wrapper trait for `Get<Width>`
pub trait GetWidth: Get<Width> {
    /// Get width
    #[inline(always)]
    fn get_width(&self) -> Width {
        self.get()
    }
}

impl<T: Get<Width>> GetWidth for T {}

/// Wrapper trait for `Set<Width>`
pub trait SetWidth: Set<Width> {
    /// Set width
    #[inline(always)]
    fn set_width(&mut self, val: Width) {
        self.set_mut(val);
    }
}

impl<T: Set<Width>> SetWidth for T {}

/// A colored line with a default border radius
#[deriving(Copy)]
pub struct Line {
    /// The line color
    pub color: internal::Color,
    /// The line radius
    pub radius: internal::Radius,
    /// The line shape
    pub shape: Shape,
}

impl Line {
    /// Creates a new line
    pub fn new(color: internal::Color, radius: internal::Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Square,
        }
    }

    /// Creates a new line
    pub fn round(color: internal::Color, radius: internal::Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Round,
        }
    }

    /// Draw the line.
    pub fn draw<B: BackEnd<I>, I: ImageSize>(
        &self,
        line: internal::Line,
        c: &Context,
        back_end: &mut B
    ) {
        // Complete transparency does not need to be rendered.
        if self.color[3] == 0.0 { return; }
        back_end.color(self.color);
        match self.shape {
            Shape::Square => {
                triangulation::with_round_border_line_tri_list(
                    2,
                    c.transform,
                    line,
                    self.radius,
                    |vertices| back_end.tri_list(vertices)
                );
            }
            Shape::Round => {
                triangulation::with_round_border_line_tri_list(
                    64,
                    c.transform,
                    line,
                    self.radius,
                    |vertices| back_end.tri_list(vertices)
                );
            }
            Shape::Bevel => {
                triangulation::with_round_border_line_tri_list(
                    3,
                    c.transform,
                    line,
                    self.radius,
                    |vertices| back_end.tri_list(vertices)
                );
            }
        }
    }
}

impl Modifier<Line> for Color {
    #[inline(always)]
    fn modify(self, l: &mut Line) {
        let Color(val) = self;
        l.color = val;
    }
}

impl Get<Color> for Line {
    #[inline(always)]
    fn get(&self) -> Color {
        Color(self.color)
    }
}

impl Modifier<Line> for Radius {
    #[inline(always)]
    fn modify(self, l: &mut Line) {
        let Radius(val) = self;
        l.radius = val;
    }
}

impl Get<Radius> for Line {
    #[inline(always)]
    fn get(&self) -> Radius {
        Radius(self.radius)
    }
}

impl Modifier<Line> for Width {
    #[inline(always)]
    fn modify(self, l: &mut Line) {
        let Width(val) = self;
        l.radius = 0.5 * val;
    }
}

impl Get<Width> for Line {
    #[inline(always)]
    fn get(&self) -> Width {
        Width(2.0 * self.radius)
    }
}

impl Modifier<Line> for Shape {
    #[inline(always)]
    fn modify(self, l: &mut Line) {
        l.shape = self;
    }
}

impl Get<Shape> for Line {
    #[inline(always)]
    fn get(&self) -> Shape {
        self.shape
    }
}

#[cfg(test)]
mod test {
    use current::Set;
    use super::Line;
    use super::Shape;
    use super::Radius;
    use Color;

    #[test]
    fn test_line() {
        let _line = Line::new([0.0, ..4], 3.0)
            .set(Color([1.0, ..4]))
            .set(Radius(3.0))
            .set(Shape::Round);
    }
}
<|endoftext|>


<commit_before>//! This module contains all the operations related to the Ardite Schema
//! Definition, a format which is used to imperitevly define the data interface
//! used with Ardite services.

mod definition;
mod schema;
mod serde;

pub use schema::definition::{Definition, Type};
pub use schema::schema::Schema;
pub use schema::serde::from_file;
<commit_msg>fix(schema): publicly use schema variants<commit_after>//! This module contains all the operations related to the Ardite Schema
//! Definition, a format which is used to imperitevly define the data interface
//! used with Ardite services.

mod definition;
mod schema;
mod serde;

pub use schema::schema::*;
pub use schema::definition::{Definition, Type};
pub use schema::serde::from_file;
<|endoftext|>


<commit_before>//! Map application-level credential names to secrets in the backend store.
//!
//! In the case of Vault, this is necessary to transform
//! environment-variable-style credential names into Vault secret paths and
//! keys: from `MY_SECRET_PASSWORD` to the path `secret/my_secret` and the
//! key `"password"`.

use backend::{BoxedError, err};
use regex::{Captures, Regex};
use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;

/// The location of a secret in a given backend.  This is exported to the
/// rest of this crate, but isn't part of the public `Secretfile` API,
/// because we might add more types of locations in the future.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Location {
    // Used for systems which identify credentials with simple string keys.
    Path(String),
    /// Used for systems like Vault where a path _and_ a hash key are
    /// needed to identify a specific credential.
    PathWithKey(String, String),
}

impl Location {
    /// Create a new `Location` from a regex `Captures` containing the
    /// named match `path` and optionally `key`.
    fn from_caps<'a>(caps: &Captures<'a>) -> Result<Location, BoxedError> {
        match (caps.name("path"), caps.name("key")) {
            (Some(path), None) =>
                Ok(Location::Path(try!(interpolate_env(path)))),
            (Some(path), Some(key)) =>
                Ok(Location::PathWithKey(try!(interpolate_env(path)),
                                         key.to_owned())),
            (_, _) =>
                Err(err!("Could not parse location in Secretfile: {}",
                         caps.at(0).unwrap())),
        }
    }
}

/// Interpolate environment variables into a string.
fn interpolate_env(text: &str) -> Result<String, BoxedError> {
    // Only compile this Regex once.
    lazy_static! {
        static ref RE: Regex =
            Regex::new(r"\$(?:(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)|\{(?P<name2>[a-zA-Z_][a-zA-Z0-9_]*)\})").unwrap();
    }

    // Perform the replacement.  This is mostly error-handling logic,
    // because `replace_all` doesn't anticipate any errors.
    let mut undefined_env_var = None;
    let result = RE.replace_all(text, |caps: &Captures| {
        let name =
            caps.name("name").or_else(|| { caps.name("name2") }).unwrap();
        match env::var(name) {
            Ok(s) => s.to_owned(),
            Err(_) => {
                undefined_env_var = Some(name.to_owned());
                "".to_owned()
            }
        }
    });
    match undefined_env_var {
        None => Ok(result),
        Some(var) =>
            Err(err!("Secretfile: Environment variable {} is not defined", var))
    }
}

#[derive(Debug, Clone)]
pub struct Secretfile {
    vars: BTreeMap<String, Location>,
    files: BTreeMap<String, Location>,
}

impl Secretfile {
    /// Read in from an `io::Read` object.
    pub fn read(read: &mut io::Read) -> Result<Secretfile, BoxedError> {
        // Only compile this Regex once.
        lazy_static! {
            // Match an individual line in a Secretfile.
            static ref RE: Regex = Regex::new(r"(?x)
^(?:
   # Blank line with optional comment.
   \s*(?:\#.*)?
 |
   (?:
     # VAR
     (?P<var>[a-zA-Z_][a-zA-Z0-9_]*)
   |
     # >file
     >(?P<file>\S+)
   )
   \s+
   # path/to/secret:key
   (?P<path>\S+?)(?::(?P<key>\S+))?
   \s*
 )$").unwrap();
        }

        let mut sf = Secretfile {
            vars: BTreeMap::new(),
            files: BTreeMap::new(),
        };
        let buffer = io::BufReader::new(read);
        for line_or_err in buffer.lines() {
            let line = try!(line_or_err);
            match RE.captures(&line) {
                Some(ref caps) if caps.name("path").is_some() => {
                    let location = try!(Location::from_caps(caps));
                    if caps.name("file").is_some() {
                        let file =
                            try!(interpolate_env(caps.name("file").unwrap()));
                        sf.files.insert(file, location);
                    } else if caps.name("var").is_some() {
                        let var = caps.name("var").unwrap().to_owned();
                        sf.vars.insert(var, location);
                    }
                }
                Some(_) => { /* Blank or comment */ },
                _ =>
                    return Err(err!("Error parsing Secretfile line: {}", &line)),
            }
        }
        Ok(sf)
    }

    /// Read a `Secretfile` from a string.  Currently only used for testing.
    pub fn from_str<S: AsRef<str>>(s: S) -> Result<Secretfile, BoxedError> {
        let mut cursor = io::Cursor::new(s.as_ref().as_bytes());
        Secretfile::read(&mut cursor)
    }

    /// Load the `Secretfile` at the specified path.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Secretfile, BoxedError>
    {
        Secretfile::read(&mut try!(File::open(path)))
    }

    /// Load the default `Secretfile`.
    pub fn default() -> Result<Secretfile, BoxedError> {
        let mut path = try!(env::current_dir());
        path.push("Secretfile");
        Secretfile::from_path(path)
    }
}

/// Internal methods for looking up `Location`s in `Secretfile`.  These are
/// hidden in a separate trait so that we can export them _within_ this
/// crate, but not expose them to other crates.
pub trait SecretfileLookup {
    /// Fetch the backend path for a variable listed in a `Secretfile`.
    fn var(&self, name: &str) -> Option<&Location>;

    /// Fetch the backend path for a file listed in a `Secretfile`.
    fn file(&self, name: &str) -> Option<&Location>;
}

impl SecretfileLookup for Secretfile {
    fn var(&self, name: &str) -> Option<&Location> {
        self.vars.get(name)
    }

    fn file(&self, name: &str) -> Option<&Location> {
        self.files.get(name)
    }
}

#[test]
fn test_parse() {
    let data = "\
# This is a comment.

FOO_USERNAME secret/$SECRET_NAME:username\n\
FOO_PASSWORD secret/${SECRET_NAME}:password\n\

# Try a Keywhiz-style secret, too.
FOO_USERNAME2 ${SECRET_NAME}_username\n\

# Credentials to copy to a file.  Interpolation allowed on the left here.
>$SOMEDIR/.conf/key.pem secret/ssl:key_pem\n\
";
    env::set_var("SECRET_NAME", "foo");
    env::set_var("SOMEDIR", "/home/foo");
    let secretfile = Secretfile::from_str(data).unwrap();
    assert_eq!(&Location::PathWithKey("secret/foo".to_owned(),
                                      "username".to_owned()),
               secretfile.var("FOO_USERNAME").unwrap());
    assert_eq!(&Location::PathWithKey("secret/foo".to_owned(),
                                      "password".to_owned()),
               secretfile.var("FOO_PASSWORD").unwrap());
    assert_eq!(&Location::Path("foo_username".to_owned()),
               secretfile.var("FOO_USERNAME2").unwrap());
    assert_eq!(&Location::PathWithKey("secret/ssl".to_owned(),
                                      "key_pem".to_owned()),
               secretfile.file("/home/foo/.conf/key.pem").unwrap());
}
<commit_msg>Allow iterating over `Secretfile` keys<commit_after>//! Map application-level credential names to secrets in the backend store.
//!
//! In the case of Vault, this is necessary to transform
//! environment-variable-style credential names into Vault secret paths and
//! keys: from `MY_SECRET_PASSWORD` to the path `secret/my_secret` and the
//! key `"password"`.

use backend::{BoxedError, err};
use regex::{Captures, Regex};
use std::collections::{btree_map, BTreeMap};
use std::env;
use std::fs::File;
use std::iter::Iterator;
use std::io::{self, BufRead};
use std::path::Path;

/// The location of a secret in a given backend.  This is exported to the
/// rest of this crate, but isn't part of the public `Secretfile` API,
/// because we might add more types of locations in the future.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Location {
    // Used for systems which identify credentials with simple string keys.
    Path(String),
    /// Used for systems like Vault where a path _and_ a hash key are
    /// needed to identify a specific credential.
    PathWithKey(String, String),
}

impl Location {
    /// Create a new `Location` from a regex `Captures` containing the
    /// named match `path` and optionally `key`.
    fn from_caps<'a>(caps: &Captures<'a>) -> Result<Location, BoxedError> {
        match (caps.name("path"), caps.name("key")) {
            (Some(path), None) =>
                Ok(Location::Path(try!(interpolate_env(path)))),
            (Some(path), Some(key)) =>
                Ok(Location::PathWithKey(try!(interpolate_env(path)),
                                         key.to_owned())),
            (_, _) =>
                Err(err!("Could not parse location in Secretfile: {}",
                         caps.at(0).unwrap())),
        }
    }
}

/// Interpolate environment variables into a string.
fn interpolate_env(text: &str) -> Result<String, BoxedError> {
    // Only compile this Regex once.
    lazy_static! {
        static ref RE: Regex =
            Regex::new(r"\$(?:(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)|\{(?P<name2>[a-zA-Z_][a-zA-Z0-9_]*)\})").unwrap();
    }

    // Perform the replacement.  This is mostly error-handling logic,
    // because `replace_all` doesn't anticipate any errors.
    let mut undefined_env_var = None;
    let result = RE.replace_all(text, |caps: &Captures| {
        let name =
            caps.name("name").or_else(|| { caps.name("name2") }).unwrap();
        match env::var(name) {
            Ok(s) => s.to_owned(),
            Err(_) => {
                undefined_env_var = Some(name.to_owned());
                "".to_owned()
            }
        }
    });
    match undefined_env_var {
        None => Ok(result),
        Some(var) =>
            Err(err!("Secretfile: Environment variable {} is not defined", var))
    }
}

#[derive(Debug, Clone)]
pub struct Secretfile {
    varmap: BTreeMap<String, Location>,
    filemap: BTreeMap<String, Location>,
}

impl Secretfile {
    /// Read in from an `io::Read` object.
    pub fn read(read: &mut io::Read) -> Result<Secretfile, BoxedError> {
        // Only compile this Regex once.
        lazy_static! {
            // Match an individual line in a Secretfile.
            static ref RE: Regex = Regex::new(r"(?x)
^(?:
   # Blank line with optional comment.
   \s*(?:\#.*)?
 |
   (?:
     # VAR
     (?P<var>[a-zA-Z_][a-zA-Z0-9_]*)
   |
     # >file
     >(?P<file>\S+)
   )
   \s+
   # path/to/secret:key
   (?P<path>\S+?)(?::(?P<key>\S+))?
   \s*
 )$").unwrap();
        }

        let mut sf = Secretfile {
            varmap: BTreeMap::new(),
            filemap: BTreeMap::new(),
        };
        let buffer = io::BufReader::new(read);
        for line_or_err in buffer.lines() {
            let line = try!(line_or_err);
            match RE.captures(&line) {
                Some(ref caps) if caps.name("path").is_some() => {
                    let location = try!(Location::from_caps(caps));
                    if caps.name("file").is_some() {
                        let file =
                            try!(interpolate_env(caps.name("file").unwrap()));
                        sf.filemap.insert(file, location);
                    } else if caps.name("var").is_some() {
                        let var = caps.name("var").unwrap().to_owned();
                        sf.varmap.insert(var, location);
                    }
                }
                Some(_) => { /* Blank or comment */ },
                _ =>
                    return Err(err!("Error parsing Secretfile line: {}", &line)),
            }
        }
        Ok(sf)
    }

    /// Read a `Secretfile` from a string.  Currently only used for testing.
    pub fn from_str<S: AsRef<str>>(s: S) -> Result<Secretfile, BoxedError> {
        let mut cursor = io::Cursor::new(s.as_ref().as_bytes());
        Secretfile::read(&mut cursor)
    }

    /// Load the `Secretfile` at the specified path.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Secretfile, BoxedError>
    {
        Secretfile::read(&mut try!(File::open(path)))
    }

    /// Load the default `Secretfile`.
    pub fn default() -> Result<Secretfile, BoxedError> {
        let mut path = try!(env::current_dir());
        path.push("Secretfile");
        Secretfile::from_path(path)
    }

    /// Return an iterator over the environment variables listed in this
    /// file.
    pub fn vars(&self) -> SecretfileKeys {
        SecretfileKeys { keys: self.varmap.keys() }
    }

    /// Return an iterator over the credential files listed in this file.
    pub fn files(&self) -> SecretfileKeys {
        SecretfileKeys { keys: self.filemap.keys() }
    }
}

/// Internal methods for looking up `Location`s in `Secretfile`.  These are
/// hidden in a separate trait so that we can export them _within_ this
/// crate, but not expose them to other crates.
pub trait SecretfileLookup {
    /// Fetch the backend path for a variable listed in a `Secretfile`.
    fn var(&self, name: &str) -> Option<&Location>;

    /// Fetch the backend path for a file listed in a `Secretfile`.
    fn file(&self, name: &str) -> Option<&Location>;
}

impl SecretfileLookup for Secretfile {
    fn var(&self, name: &str) -> Option<&Location> {
        self.varmap.get(name)
    }

    fn file(&self, name: &str) -> Option<&Location> {
        self.filemap.get(name)
    }
}

/// An iterator over the keys mentioned in a `Secretfile`.
#[derive(Clone)]
pub struct SecretfileKeys<'a> {
    /// Our actual iterator, wrapped up only so that we don't need to
    /// expose the underlying implementation type in our stable API.
    keys: btree_map::Keys<'a, String, Location>,
}

// 'a is a lifetime specifier bound to the underlying collection we're
// iterating over, which keeps anybody from modifying it while we
// iterating.
impl<'a> Iterator for SecretfileKeys<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.keys.next()
    }
}

#[test]
fn test_parse() {
    let data = "\
# This is a comment.

FOO_USERNAME secret/$SECRET_NAME:username\n\
FOO_PASSWORD secret/${SECRET_NAME}:password\n\

# Try a Keywhiz-style secret, too.
FOO_USERNAME2 ${SECRET_NAME}_username\n\

# Credentials to copy to a file.  Interpolation allowed on the left here.
>$SOMEDIR/.conf/key.pem secret/ssl:key_pem\n\
";
    env::set_var("SECRET_NAME", "foo");
    env::set_var("SOMEDIR", "/home/foo");
    let secretfile = Secretfile::from_str(data).unwrap();
    assert_eq!(&Location::PathWithKey("secret/foo".to_owned(),
                                      "username".to_owned()),
               secretfile.var("FOO_USERNAME").unwrap());
    assert_eq!(&Location::PathWithKey("secret/foo".to_owned(),
                                      "password".to_owned()),
               secretfile.var("FOO_PASSWORD").unwrap());
    assert_eq!(&Location::Path("foo_username".to_owned()),
               secretfile.var("FOO_USERNAME2").unwrap());
    assert_eq!(&Location::PathWithKey("secret/ssl".to_owned(),
                                      "key_pem".to_owned()),
               secretfile.file("/home/foo/.conf/key.pem").unwrap());

    assert_eq!(vec!("FOO_PASSWORD", "FOO_USERNAME", "FOO_USERNAME2"),
               secretfile.vars().collect::<Vec<_>>());
    assert_eq!(vec!("/home/foo/.conf/key.pem"),
               secretfile.files().collect::<Vec<_>>());
}
<|endoftext|>


<commit_before>use std::time::{Duration, SystemTime, Instant};
use std::convert::TryFrom;

use crate::stacked_borrows::Tag;
use crate::*;
use helpers::{immty_from_int_checked, immty_from_uint_checked};

use rustc_middle::ty::layout::LayoutOf;

/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
    time.duration_since(SystemTime::UNIX_EPOCH)
        .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn clock_gettime(
        &mut self,
        clk_id_op: OpTy<'tcx, Tag>,
        tp_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("linux", "clock_gettime");
        this.check_no_isolation("clock_gettime")?;

        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
        let tp = this.deref_operand(tp_op)?;

        let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
            system_time_to_duration(&SystemTime::now())?
        } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
            // Absolute time does not matter, only relative time does, so we can just
            // use our own time anchor here.
            Instant::now().duration_since(this.machine.time_anchor)
        } else {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        };

        let tv_sec = duration.as_secs();
        let tv_nsec = duration.subsec_nanos();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
        ];

        this.write_packed_immediates(tp, &imms)?;

        Ok(0)
    }

    fn gettimeofday(
        &mut self,
        tv_op: OpTy<'tcx, Tag>,
        tz_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("macos", "gettimeofday");
        this.check_no_isolation("gettimeofday")?;

        // Using tz is obsolete and should always be null
        let tz = this.read_scalar(tz_op)?.not_undef()?;
        if !this.is_null(tz)? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tv = this.deref_operand(tv_op)?;

        let duration = system_time_to_duration(&SystemTime::now())?;
        let tv_sec = duration.as_secs();
        let tv_usec = duration.subsec_micros();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
        ];

        this.write_packed_immediates(tv, &imms)?;

        Ok(0)
    }

    #[allow(non_snake_case)]
    fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "GetSystemTimeAsFileTime");
        this.check_no_isolation("GetSystemTimeAsFileTime")?;

        let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
        let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
        let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
        let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;

        let duration = system_time_to_duration(&SystemTime::now())?
            .checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH))
            .unwrap();
        let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?;

        let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
        let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
        let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?;
        let imms = [
            immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?,
            immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?,
        ];
        this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?;
        Ok(())
    }

    fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
        let this = self.eval_context_ref();

        this.assert_target_os("macos", "mach_absolute_time");
        this.check_no_isolation("mach_absolute_time")?;

        // This returns a u64, with time units determined dynamically by `mach_timebase_info`.
        // We return plain nanoseconds.
        let duration = Instant::now().duration_since(this.machine.time_anchor);
        u64::try_from(duration.as_nanos())
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into())
    }
}
<commit_msg>Auto merge of #1297 - RalfJung:win-ticks, r=RalfJung<commit_after>use std::time::{Duration, SystemTime, Instant};
use std::convert::TryFrom;

use crate::stacked_borrows::Tag;
use crate::*;
use helpers::{immty_from_int_checked, immty_from_uint_checked};

use rustc_middle::ty::layout::LayoutOf;

/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
    time.duration_since(SystemTime::UNIX_EPOCH)
        .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn clock_gettime(
        &mut self,
        clk_id_op: OpTy<'tcx, Tag>,
        tp_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("linux", "clock_gettime");
        this.check_no_isolation("clock_gettime")?;

        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
        let tp = this.deref_operand(tp_op)?;

        let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
            system_time_to_duration(&SystemTime::now())?
        } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
            // Absolute time does not matter, only relative time does, so we can just
            // use our own time anchor here.
            Instant::now().duration_since(this.machine.time_anchor)
        } else {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        };

        let tv_sec = duration.as_secs();
        let tv_nsec = duration.subsec_nanos();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
        ];

        this.write_packed_immediates(tp, &imms)?;

        Ok(0)
    }

    fn gettimeofday(
        &mut self,
        tv_op: OpTy<'tcx, Tag>,
        tz_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("macos", "gettimeofday");
        this.check_no_isolation("gettimeofday")?;

        // Using tz is obsolete and should always be null
        let tz = this.read_scalar(tz_op)?.not_undef()?;
        if !this.is_null(tz)? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tv = this.deref_operand(tv_op)?;

        let duration = system_time_to_duration(&SystemTime::now())?;
        let tv_sec = duration.as_secs();
        let tv_usec = duration.subsec_micros();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
        ];

        this.write_packed_immediates(tv, &imms)?;

        Ok(0)
    }

    #[allow(non_snake_case)]
    fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "GetSystemTimeAsFileTime");
        this.check_no_isolation("GetSystemTimeAsFileTime")?;

        let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
        let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
        let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
        let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;

        let duration = system_time_to_duration(&SystemTime::now())? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH);
        let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
            .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?;

        let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
        let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
        let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?;
        let imms = [
            immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?,
            immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?,
        ];
        this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?;
        Ok(())
    }

    fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
        let this = self.eval_context_ref();

        this.assert_target_os("macos", "mach_absolute_time");
        this.check_no_isolation("mach_absolute_time")?;

        // This returns a u64, with time units determined dynamically by `mach_timebase_info`.
        // We return plain nanoseconds.
        let duration = Instant::now().duration_since(this.machine.time_anchor);
        u64::try_from(duration.as_nanos())
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into())
    }
}
<|endoftext|>


<commit_before>
struct CircularBuffer<T : Copy> {
  seqno : usize,
  data  : Vec<T>,
}

impl <T : Copy> CircularBuffer<T> {
  fn new(size : usize, default_value : T) -> CircularBuffer<T> {

    if size == 0 { panic!("size cannot be zero"); }

    let mut ret = CircularBuffer {
      seqno : 0,
      data  : vec![],
    };

    // make sure there is enough place and fill it with the
    // default value
    ret.data.resize(size, default_value);
    ret
  }

  fn put<F>(&mut self, setter: F) -> usize
    where F : Fn(&mut T)
  {
    // calculate where to put the data
    let pos = self.seqno % self.data.len();

    // get a reference to the data
    let mut opt : Option<&mut T> = self.data.get_mut(pos);

    // make sure the index worked
    match opt.as_mut() {
      Some(v) => setter(v),
      None    => { panic!("out of bounds {}", pos); }
    }

    // increase sequence number
    self.seqno = self.seqno + 1;
    self.seqno
  }
}

pub fn tests() {
  let mut x = CircularBuffer::new(4, 0 as i32);
  x.put(|v| *v = 1);
}

#[test]
#[should_panic]
fn create_zero_sized() {
  let _x = CircularBuffer::new(0, 0 as i32);
}

#[test]
fn create_non_zero_sized() {
  let _x = CircularBuffer::new(1, 0 as i32);
}

#[test]
fn can_put() {
  let mut x = CircularBuffer::new(1, 0 as i32);
  x.put(|v| *v = 1);
}
<commit_msg>added FnMut<commit_after>
struct CircularBuffer<T : Copy> {
  seqno : usize,
  data  : Vec<T>,
}

impl <T : Copy> CircularBuffer<T> {
  fn new(size : usize, default_value : T) -> CircularBuffer<T> {

    if size == 0 { panic!("size cannot be zero"); }

    let mut ret = CircularBuffer {
      seqno : 0,
      data  : vec![],
    };

    // make sure there is enough place and fill it with the
    // default value
    ret.data.resize(size, default_value);
    ret
  }

  fn put<F>(&mut self, setter: F) -> usize
    where F : Fn(&mut T)
  {
    // calculate where to put the data
    let pos = self.seqno % self.data.len();

    // get a reference to the data
    let mut opt : Option<&mut T> = self.data.get_mut(pos);

    // make sure the index worked
    match opt.as_mut() {
      Some(v) => setter(v),
      None    => { panic!("out of bounds {}", pos); }
    }

    // increase sequence number
    self.seqno += 1;
    self.seqno
  }

  fn put_mut<F>(&mut self, mut setter: F) -> usize
    where F : FnMut(&mut T)
  {
    // calculate where to put the data
    let pos = self.seqno % self.data.len();

    // get a reference to the data
    let mut opt : Option<&mut T> = self.data.get_mut(pos);

    // make sure the index worked
    match opt.as_mut() {
      Some(v) => setter(v),
      None    => { panic!("out of bounds {}", pos); }
    }

    // increase sequence number
    self.seqno += 1;
    self.seqno
  }
}

pub fn tests() {
  let mut x = CircularBuffer::new(4, 0 as i32);
  x.put(|v| *v = 1);
  let mut y = 0;
  x.put_mut(|v| { *v = y; y += 1; });
}

#[test]
#[should_panic]
fn create_zero_sized() {
  let _x = CircularBuffer::new(0, 0 as i32);
}

#[test]
fn create_non_zero_sized() {
  let _x = CircularBuffer::new(1, 0 as i32);
}

#[test]
fn can_put() {
  let mut x = CircularBuffer::new(1, 0 as i32);
  x.put(|v| *v = 1);
}

#[test]
fn can_put_with_env() {
  let mut x = CircularBuffer::new(1, 0 as i32);
  let mut y = 0;
  let my_fn = |v : &mut i32| {
    *v = y;
    y += 1;
  };
  x.put_mut(my_fn);
}

#[test]
fn can_put_with_env2() {
  let mut x = CircularBuffer::new(1, 0 as i32);
  let mut y = 0;
  x.put_mut(|v| { *v = y; y += 1; });
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]
#![cfg_attr(nightly, feature(scoped))]

extern crate unicode_width;

mod args;
mod matching;
mod screen;
mod version;
#[cfg(not(windows))] mod ansi;

use version::*;
use std::collections::HashSet;
use std::process;
use std::io::{stdin, BufRead};
use std::cmp::min;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

fn main() {
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        if COMMIT == "" {
            println!("heatseeker {} (built {})", VERSION, TIMESTAMP);
        } else {
            println!("heatseeker {} ({}) (built {})", VERSION, COMMIT, TIMESTAMP);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        event_loop(&choices, &initial_search);
    }
}

fn event_loop(choices: &[&str], initial_search: &str) {
    let mut search = Search::new(choices, initial_search.to_string());
    let mut screen = Screen::open_screen();

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(&mut screen, &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in keys.iter() {
            handle_key(&mut search, key, screen.visible_choices);
        }
    }

    screen.move_cursor_to_bottom();
    println!("{}", search.get_selections());
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace => search.backspace(),
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') => search.cancel(),
        Control('g') => search.cancel(),
        Control('p') => search.up(visible_choices),
        Control('t') => search.toggle_selection(),
        Control('n') => search.down(visible_choices),
        Tab => search.down(visible_choices),
        Enter => search.done(),
        _ => {}
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    index: usize,
    state: SearchState,
    selections: HashSet<String>,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices: choices,
            query: initial_search,
            matches: matches,
            stale: true,
            index: 0,
            state: InProgress,
            selections: HashSet::new(),
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == 0 { limit } else { self.index - 1 };
    }

    fn down(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == limit { 0 } else { self.index + 1 }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.index = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.index = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            self.recompute_matches();
            let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
            self.selections.insert(selection);
        }
        for selection in self.selections.iter() {
            ret.push_str(selection);
            ret.push('\n');
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices)\n", search.query, search.matches.len(), search.choices.len()));

    print_matches(screen, &search.matches, &search.query, search.index);

    let start = screen.start_line;
    let query_str: &str = &search.query;
    screen.move_cursor(start, 2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &[&str], query: &str, index: usize) {
    let mut i = 1;
    for choice in matches.iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width;
        print_match(choice, &indices, max_width, &mut |s, highlight| {
            if i == index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else {
                if highlight { screen.write_red(s); } else { screen.write(s); }
            }
        });
        if i >= screen.visible_choices as usize {
            return;
        } else {
            screen.write("\n");
        }
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let chars_to_draw = min(chars_in_choice, max_width as usize);
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(&slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(&slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(&slice_chars(choice, last_idx, chars_to_draw), false);
}

fn read_choices() -> Vec<String> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let mut stdin = stdin.lock();
    loop {
        let mut s = String::new();
        stdin.read_line(&mut s).unwrap();
        if s.len() == 0 {
            break;
        } else {
            trim(&mut s);
            lines.push(s);
        }
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

// This is technically a standard library function, but it's plastered with
// stability warnings and therefore only available on the nightly channel.
fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.slice_unchecked(a, b) }
    }
}

#[test]
fn trim_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        trim(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("\n", "");
    should_become("\n\n", "");
    should_become("asdf", "asdf");
    should_become("asdf\n", "asdf");
    should_become("asdf\nasdf\n", "asdf\nasdf");
}

#[test]
fn delete_word_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        delete_last_word(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("a", "");
    should_become("asdf", "");
    should_become("asdf asdf asdf", "asdf asdf ");
    should_become("asdf asdf asdf ", "asdf asdf ");
    should_become("asdf asdf asdf  ", "asdf asdf ");
}
<commit_msg>Draw a checkmark next to selections<commit_after>#![cfg_attr(test, allow(dead_code))]
#![cfg_attr(nightly, feature(scoped))]

extern crate unicode_width;

mod args;
mod matching;
mod screen;
mod version;
#[cfg(not(windows))] mod ansi;

use version::*;
use std::collections::HashSet;
use std::process;
use std::io::{stdin, BufRead};
use std::cmp::min;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

fn main() {
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        if COMMIT == "" {
            println!("heatseeker {} (built {})", VERSION, TIMESTAMP);
        } else {
            println!("heatseeker {} ({}) (built {})", VERSION, COMMIT, TIMESTAMP);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        event_loop(&choices, &initial_search);
    }
}

fn event_loop(choices: &[&str], initial_search: &str) {
    let mut search = Search::new(choices, initial_search.to_string());
    let mut screen = Screen::open_screen();

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(&mut screen, &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in keys.iter() {
            handle_key(&mut search, key, screen.visible_choices);
        }
    }

    screen.move_cursor_to_bottom();
    println!("{}", search.get_selections());
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace => search.backspace(),
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') => search.cancel(),
        Control('g') => search.cancel(),
        Control('p') => search.up(visible_choices),
        Control('t') => search.toggle_selection(),
        Control('n') => search.down(visible_choices),
        Tab => search.down(visible_choices),
        Enter => search.done(),
        _ => {}
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    index: usize,
    state: SearchState,
    selections: HashSet<String>,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices: choices,
            query: initial_search,
            matches: matches,
            stale: true,
            index: 0,
            state: InProgress,
            selections: HashSet::new(),
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == 0 { limit } else { self.index - 1 };
    }

    fn down(&mut self, visible_choices: u16) {
        let limit = min(visible_choices as usize - 1, self.matches.len() - 1);
        self.index = if self.index == limit { 0 } else { self.index + 1 }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.index = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.index = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            self.recompute_matches();
            let selection = self.matches.get(self.index).unwrap_or(&"").to_string();
            self.selections.insert(selection);
        }
        for selection in self.selections.iter() {
            ret.push_str(selection);
            ret.push('\n');
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices)\n", search.query, search.matches.len(), search.choices.len()));

    print_matches(screen, &search.matches, &search.query, search.index, &search.selections);

    let start = screen.start_line;
    let query_str: &str = &search.query;
    screen.move_cursor(start, 2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut Screen, matches: &[&str], query: &str, index: usize, selections: &HashSet<String>) {
    #[cfg(windows)] const SELECTED: char = '*';
    #[cfg(not(windows))] const SELECTED: char = '✓';
    let mut i = 1;
    for choice in matches.iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width;
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            annotated_choice.push(SELECTED);
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else {
                if highlight { screen.write_red(s); } else { screen.write(s); }
            }
        });
        if i >= screen.visible_choices as usize {
            return;
        } else {
            screen.write("\n");
        }
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let chars_to_draw = min(chars_in_choice, max_width as usize);
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(&slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(&slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(&slice_chars(choice, last_idx, chars_to_draw), false);
}

fn read_choices() -> Vec<String> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let mut stdin = stdin.lock();
    loop {
        let mut s = String::new();
        stdin.read_line(&mut s).unwrap();
        if s.len() == 0 {
            break;
        } else {
            trim(&mut s);
            lines.push(s);
        }
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

// This is technically a standard library function, but it's plastered with
// stability warnings and therefore only available on the nightly channel.
fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.slice_unchecked(a, b) }
    }
}

#[test]
fn trim_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        trim(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("\n", "");
    should_become("\n\n", "");
    should_become("asdf", "asdf");
    should_become("asdf\n", "asdf");
    should_become("asdf\nasdf\n", "asdf\nasdf");
}

#[test]
fn delete_word_test() {
    fn should_become(before: &str, after: &str) {
        let mut x = before.to_string();
        delete_last_word(&mut x);
        assert_eq!(after.to_string(), x);
    }
    should_become("", "");
    should_become("a", "");
    should_become("asdf", "");
    should_become("asdf asdf asdf", "asdf asdf ");
    should_become("asdf asdf asdf ", "asdf asdf ");
    should_become("asdf asdf asdf  ", "asdf asdf ");
}
<|endoftext|>