<commit_before>
extern crate image;

use std::path::Path;

/// Panics if any pixels differ between the two input images.
#[macro_export]
macro_rules! assert_pixels_eq {
    ($actual:expr, $expected:expr) => ({
        let actual_dim = $actual.dimensions();
        let expected_dim = $expected.dimensions();

        if actual_dim != expected_dim {
            panic!("dimensions do not match. \
                actual: {:?}, expected: {:?}", actual_dim, expected_dim)
        }

        // Can't just call $image.pixels(), as that needn't hit the
        // trait pixels method - ImageBuffer defines its own pixels
        // method with a different signature
        let diffs = ::image::GenericImage::pixels(&$actual)
            .zip(::image::GenericImage::pixels(&$expected))
            .filter(|&(p, q)| p != q)
            .collect::<Vec<_>>();

        if !diffs.is_empty() {
            let mut err = "pixels do not match. ".to_string();

            let diff_messages = diffs
                .iter()
                .take(5)
                .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
                .collect::<Vec<_>>()
                .join("");

            err.push_str(&diff_messages);
            panic!(err)
        }
     })
}

/// Loads image at given path, panicking on failure.
pub fn load_image_or_panic(path: &Path) -> image::DynamicImage {
     image::open(path)
         .ok()
         .expect(&format!("Could not load image at {:?}", path))
}

/// Gray image to use in benchmarks. This is neither noise nor
/// similar to natural images - it's just a convenience method
/// to produce an image that's not constant.
pub fn gray_bench_image(width: u32, height: u32) -> image::GrayImage {
    let mut image = image::GrayImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let intensity = (x % 7 + y % 6) as u8;
            image.put_pixel(x, y, image::Luma([intensity]));
        }
    }
    image
}

/// RGB image to use in benchmarks. See comment on gray_bench_image.
pub fn rgb_bench_image(width: u32, height: u32) -> image::RgbImage {
    use std::cmp;
    let mut image = image::RgbImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let r = (x % 7 + y % 6) as u8;
            let g = 255u8 - r;
            let b = cmp::min(r, g);
            image.put_pixel(x, y, image::Rgb([r, g, b]));
        }
    }
    image
}
<commit_msg>Add assert_pixels_eq_within<commit_after>//! Utils to test with testing and debugging.

use image::{
    DynamicImage,
    GenericImage,
    GrayImage,
    Luma,
    open,
    Pixel,
    Rgb,
    RgbImage
};

use std::fmt::Debug;
use std::path::Path;

/// Panics if any pixels differ between the two input images.
#[macro_export]
macro_rules! assert_pixels_eq {
    ($actual:expr, $expected:expr) => ({
        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| p != q);
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
     })
}

/// Panics if any pixels differ between the two images by more than the
/// given tolerance in a single channel.
#[macro_export]
macro_rules! assert_pixels_eq_within {
    ($actual:expr, $expected:expr, $channel_tolerance:expr) => ({

        assert_dimensions_match!($actual, $expected);
        let diffs = $crate::utils::pixel_diffs(&$actual, &$expected, |p, q| {

            use image::Pixel;
            let cp = p.2.channels();
            let cq = q.2.channels();
            if cp.len() != cq.len() {
                panic!("pixels have different channel counts. \
                    actual: {:?}, expected: {:?}", cp.len(), cq.len())
            }

            let mut large_diff = false;
            for i in 0..cp.len() {
                let sp = cp[i];
                let sq = cq[i];
                // Handle unsigned subpixels
                let diff = if sp > sq {sp - sq} else {sq - sp};
                if diff > $channel_tolerance {
                    large_diff = true;
                    break;
                }
            }

            large_diff
        });
        if !diffs.is_empty() {
            panic!($crate::utils::describe_pixel_diffs(diffs.into_iter()))
        }
    })
}

#[macro_export]
macro_rules! assert_dimensions_match {
    ($actual:expr, $expected:expr) => ({

        let actual_dim = $actual.dimensions();
        let expected_dim = $expected.dimensions();

        if actual_dim != expected_dim {
            panic!("dimensions do not match. \
                actual: {:?}, expected: {:?}", actual_dim, expected_dim)
        }
     })
}

/// Lists pixels that differ between left and right images.
pub fn pixel_diffs<I, F>(left: &I, right: &I, is_diff: F)
        -> Vec<((u32, u32, I::Pixel), (u32, u32, I::Pixel))>
    where I: GenericImage,
          I::Pixel: PartialEq,
          F: Fn((u32, u32, I::Pixel), (u32, u32, I::Pixel)) -> bool {

    // Can't just call $image.pixels(), as that needn't hit the
    // trait pixels method - ImageBuffer defines its own pixels
    // method with a different signature
    GenericImage::pixels(left)
        .zip(GenericImage::pixels(right))
        .filter(|&(p, q)| is_diff(p, q))//p != q)
        .collect::<Vec<_>>()
}

/// Gives a summary description of a list of pixel diffs for use in error messages.
pub fn describe_pixel_diffs<I, P>(diffs: I) -> String
    where I: Iterator<Item=(P, P)>,
          P: Debug {

    let mut err = "pixels do not match. ".to_string();
    err.push_str(&(diffs
        .take(5)
        .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
        .collect::<Vec<_>>()
        .join("")));
    err
}

/// Loads image at given path, panicking on failure.
pub fn load_image_or_panic(path: &Path) -> DynamicImage {
     open(path)
         .ok()
         .expect(&format!("Could not load image at {:?}", path))
}

/// Gray image to use in benchmarks. This is neither noise nor
/// similar to natural images - it's just a convenience method
/// to produce an image that's not constant.
pub fn gray_bench_image(width: u32, height: u32) -> GrayImage {
    let mut image = GrayImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let intensity = (x % 7 + y % 6) as u8;
            image.put_pixel(x, y, Luma([intensity]));
        }
    }
    image
}

/// RGB image to use in benchmarks. See comment on gray_bench_image.
pub fn rgb_bench_image(width: u32, height: u32) -> RgbImage {
    use std::cmp;
    let mut image = RgbImage::new(width, height);
    for y in 0..image.height() {
        for x in 0..image.width() {
            let r = (x % 7 + y % 6) as u8;
            let g = 255u8 - r;
            let b = cmp::min(r, g);
            image.put_pixel(x, y, Rgb([r, g, b]));
        }
    }
    image
}

#[cfg(test)]
mod test {

    use image::{
        GrayImage,
        ImageBuffer
    };

    #[test]
    fn test_assert_pixels_eq_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(image, image);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 11, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq!(diff, image);
    }

    #[test]
    fn test_assert_pixels_eq_within_passes() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 02, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }

    #[test]
    #[should_panic]
    fn test_assert_pixels_eq_within_fails() {
        let image: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 01, 02,
            10, 11, 12]).unwrap();

        let diff: GrayImage = ImageBuffer::from_raw(3, 2, vec![
            00, 03, 02,
            10, 11, 12]).unwrap();

        assert_pixels_eq_within!(diff, image, 1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust-Windows Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// 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 std::mem;
use std::ffi::OsStr;
use std::fmt;
use std::fmt::Display;
use std::os::windows::ffi::OsStrExt;
use std::vec::Vec;

// Helper struct for *u16 manipulation.
#[allow(missing_copy_implementations)]
pub struct CU16String {
    buf: *const u16,
    /// length of buffer, including null
    len: usize,
}

impl CU16String {
    /// Create a CU16String from a pointer.
    pub unsafe fn new(buf: *const u16) -> CU16String {
        CU16String {
            buf: buf,
            len: {
                let mut length_counter = 0;
                loop {
                    if *buf.offset(length_counter)==0 {
                        break;
                    }
                    length_counter += 1;
                }
                length_counter += 1;
                length_counter as usize
            }
        }
    }

    /// Converts the CU16String into a `&[u16]` without copying.
    /// NULL is not included.
    ///
    /// # Failure
    ///
    /// Fails if the CU16String is null.
    #[inline]
    pub fn as_u16_vec<'a>(&'a self) -> &'a [u16] {
        if self.buf.is_null() { panic!("CU16String is null!"); }
        unsafe {
            mem::transmute((self.buf, self.len - 1))
        }
    }
}

impl fmt::Display for CU16String {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = if self.buf.is_null() {
            "".to_string()
        } else {
            String::from_utf16_lossy(self.as_u16_vec())
        };
        s.fmt(f)
    }
}

/// Parses a C utf-16 "multistring".
/// See `std::c_str::from_c_multistring` for detailed explanation.
pub unsafe fn from_c_u16_multistring<F>(buf: *const u16, count: Option<usize>, mut f: F) -> usize
    where F: FnMut(&[u16]) {
    let mut curr_ptr: usize = buf as usize;
    let mut ctr = 0;
    let (limited_count, limit) = match count {
        Some(limit) => (true, limit),
        None => (false, 0)
    };
    while ((limited_count && ctr < limit) || !limited_count)
          && *(curr_ptr as *const u16) != 0 as u16 {
        let cstr = CU16String::new(curr_ptr as *const u16);
        f(cstr.as_u16_vec());
        curr_ptr += cstr.len * 2;
        ctr += 1;
    }
    return ctr;
}

/// A generic trait for converting a value to a `CU16String`, like `ToCStr`.
pub trait ToCU16Str {
    fn to_c_u16(&self) -> Vec<u16>;
}

impl<'a> ToCU16Str for &'a str {
    fn to_c_u16(&self) -> Vec<u16> {
        let mut t : Vec<u16> = OsStr::new( self )
			.encode_wide()
			.chain(Some(0).into_iter())
			.collect::<Vec<_>>();
        t.push(0u16);
        t
    }
}

impl ToCU16Str for String {
    fn to_c_u16(&self) -> Vec<u16> {
        let x : &str = &self;
        x.to_c_u16()
    }
}

impl ToCU16Str for Option<String> {
    fn to_c_u16(&self) -> Vec<u16> {
        match self {
            &None => Vec::new(),
            &Some(ref s) => (&s).to_c_u16(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::CU16String;
    use super::from_c_u16_multistring;

    #[test]
    fn test_as_u16_vec() {
        let u16s: &[u16] = &[
            0xac00, 0x20, 0xac00, 0x00,
        ];

        let cu = unsafe { CU16String::new(u16s.as_ptr()) };
        let v = cu.as_u16_vec();
        assert_eq!(v, &u16s[..u16s.len() - 1]);
    }

    #[test]
    fn test_from_c_u16_multistring() {
        let test: &[u16] = &[
            0xac00, 0x00,
            0xac00, 0xac00, 0x00,
            0xac00, 0xac00, 0xac00, 0x00,
            0xac00, 0xac00, 0xac00, 0xac02, 0x00,
            0x00,
        ];
        let compare = [
            "가",
            "가가",
            "가가가",
            "가가가갂",
        ];
        let mut i = 0;
        let buf = test.as_ptr();
        unsafe {
            from_c_u16_multistring(buf, None, |p| {
                let b = String::from_utf16(p).unwrap();
                assert_eq!(b, compare[i].to_owned());
                assert_eq!(b.chars().count(), i + 1);
                i += 1;
            });
        }
        assert_eq!(i, 4);
    }
}
<commit_msg>add from_c_u16() function for String<commit_after>// Copyright 2015 The Rust-Windows Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// 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 std::mem;
use std::ffi::{OsStr,OsString};
use std::fmt;
use std::fmt::Display;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::vec::Vec;

// Helper struct for *u16 manipulation.
#[allow(missing_copy_implementations)]
pub struct CU16String {
    buf: *const u16,
    /// length of buffer, including null
    len: usize,
}

impl CU16String {
    /// Create a CU16String from a pointer.
    pub unsafe fn new(buf: *const u16) -> CU16String {
        CU16String {
            buf: buf,
            len: {
                let mut length_counter = 0;
                loop {
                    if *buf.offset(length_counter)==0 {
                        break;
                    }
                    length_counter += 1;
                }
                length_counter += 1;
                length_counter as usize
            }
        }
    }

    /// Converts the CU16String into a `&[u16]` without copying.
    /// NULL is not included.
    ///
    /// # Failure
    ///
    /// Fails if the CU16String is null.
    #[inline]
    pub fn as_u16_vec<'a>(&'a self) -> &'a [u16] {
        if self.buf.is_null() { panic!("CU16String is null!"); }
        unsafe {
            mem::transmute((self.buf, self.len - 1))
        }
    }
}

impl fmt::Display for CU16String {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = if self.buf.is_null() {
            "".to_string()
        } else {
            String::from_utf16_lossy(self.as_u16_vec())
        };
        s.fmt(f)
    }
}

/// Parses a C utf-16 "multistring".
/// See `std::c_str::from_c_multistring` for detailed explanation.
pub unsafe fn from_c_u16_multistring<F>(buf: *const u16, count: Option<usize>, mut f: F) -> usize
    where F: FnMut(&[u16]) {
    let mut curr_ptr: usize = buf as usize;
    let mut ctr = 0;
    let (limited_count, limit) = match count {
        Some(limit) => (true, limit),
        None => (false, 0)
    };
    while ((limited_count && ctr < limit) || !limited_count)
          && *(curr_ptr as *const u16) != 0 as u16 {
        let cstr = CU16String::new(curr_ptr as *const u16);
        f(cstr.as_u16_vec());
        curr_ptr += cstr.len * 2;
        ctr += 1;
    }
    return ctr;
}

/// A generic trait for converting a value to a `CU16String`, like `ToCStr`.
pub trait ToCU16Str {
    fn to_c_u16(&self) -> Vec<u16>;
}

impl<'a> ToCU16Str for &'a str {
    fn to_c_u16(&self) -> Vec<u16> {
        let mut t : Vec<u16> = OsStr::new( self )
			.encode_wide()
			.chain(Some(0).into_iter())
			.collect::<Vec<_>>();
        t.push(0u16);
        t
    }
}

impl ToCU16Str for String {
    fn to_c_u16(&self) -> Vec<u16> {
        let x : &str = &self;
        x.to_c_u16()
    }
}

impl ToCU16Str for Option<String> {
    fn to_c_u16(&self) -> Vec<u16> {
        match self {
            &None => Vec::new(),
            &Some(ref s) => (&s).to_c_u16(),
        }
    }
}

pub trait FromCU16Str {
    fn from_c_u16(wide: &Vec<u16>) -> Option<String>;
}

impl FromCU16Str for String {
    fn from_c_u16(wide: &Vec<u16>) -> Option<String> {
        let t = OsString::from_wide(wide);
        t.to_str().map( str::to_string )
    }
}

#[cfg(test)]
mod test {
    use super::CU16String;
    use super::from_c_u16_multistring;

    #[test]
    fn test_as_u16_vec() {
        let u16s: &[u16] = &[
            0xac00, 0x20, 0xac00, 0x00,
        ];

        let cu = unsafe { CU16String::new(u16s.as_ptr()) };
        let v = cu.as_u16_vec();
        assert_eq!(v, &u16s[..u16s.len() - 1]);
    }

    #[test]
    fn test_from_c_u16_multistring() {
        let test: &[u16] = &[
            0xac00, 0x00,
            0xac00, 0xac00, 0x00,
            0xac00, 0xac00, 0xac00, 0x00,
            0xac00, 0xac00, 0xac00, 0xac02, 0x00,
            0x00,
        ];
        let compare = [
            "가",
            "가가",
            "가가가",
            "가가가갂",
        ];
        let mut i = 0;
        let buf = test.as_ptr();
        unsafe {
            from_c_u16_multistring(buf, None, |p| {
                let b = String::from_utf16(p).unwrap();
                assert_eq!(b, compare[i].to_owned());
                assert_eq!(b.chars().count(), i + 1);
                i += 1;
            });
        }
        assert_eq!(i, 4);
    }
}
<|endoftext|>


<commit_before>#[doc (hidden)]
#[macro_export]
macro_rules! time_steward_define_simple_timeline {
  () => {
pub mod simple_timeline {
use std::collections::{BTreeSet, VecDeque};
use std::mem;

use super::super::super::api::*;
use super::*;
use implementation_support::common::{split_off_greater_set};

#[derive (Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
pub struct GetVarying;
impl PersistentlyIdentifiedType for GetVarying {
  const ID: PersistentTypeId = PersistentTypeId(0x8912fbb263c46434);
}

#[derive (Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
pub struct JustDestroyed;
impl PersistentlyIdentifiedType for JustDestroyed {
  const ID: PersistentTypeId = PersistentTypeId(0x4ee4ba51f56f884d);
}

pub trait IterateUniquelyOwnedPredictions <Steward: TimeSteward> {
  fn iterate_predictions <F: FnMut (& Steward::EventHandle)> (&self, _callback: &mut F) {}
}

#[serde(bound = "")]
#[derive (Serialize, Deserialize, Derivative)]
#[derivative (Clone (bound=""), Debug (bound=""))]
pub struct SimpleTimeline <VaryingData: QueryResult, Steward: TimeSteward> {
  // Hacky workaround for https://github.com/rust-lang/rust/issues/41617 (see https://github.com/serde-rs/serde/issues/943)
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  changes: VecDeque<(<Steward as TimeSteward>::EventHandle, VaryingData)>,
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  destroyer: Option<<Steward as TimeSteward>::EventHandle>,
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  other_dependent_events: BTreeSet<<Steward as TimeSteward>::EventHandle>,
}

impl <VaryingData: QueryResult, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  pub fn new ()->Self {
    SimpleTimeline {
      changes: VecDeque::new(),
      destroyer: None,
      other_dependent_events: BTreeSet::new(),
    }
  }

  fn search_changes (&self, time: &ExtendedTime <Steward::Basics>) -> Result <usize, usize> {
    // search at the end first, because we are usually in the present.

    match self.changes.back() {
      None => return Err(0),
      Some (&(ref event, _)) => {
        match event.extended_time().cmp(time) {
          Ordering::Greater => (),
          Ordering::Equal => return Ok(self.changes.len()-1),
          Ordering::Less => return Err(self.changes.len()),
        }
      },
    }

    let mut drop = 2;
    let mut max = self.changes.len()-1;
    let mut min;
    loop {
      if let Some(further) = self.changes.len().checked_sub (drop) {
        let change = self.changes.get (further).unwrap();
        match change.0.extended_time().cmp(time) {
          Ordering::Greater => {
            max = further;
            drop *= 2;
          },
          Ordering::Equal => return Ok(further),
          Ordering::Less => {
            min = further;
            break;
          },
        }
      }
      else {
        min = 0;
        break;
      }
    }
    while max >= min+2 {
      let mid = (max + min) >> 1;
      let change = self.changes.get (mid).unwrap();
      match change.0.extended_time().cmp(time) {
        Ordering::Greater => max = mid,
        Ordering::Equal => return Ok(mid),
        Ordering::Less => min = mid,
      }
    }

    if self.changes.get (min).unwrap().0.extended_time() > time {
      return Err (min)
    }
    Err(max)
  }
}
impl <VaryingData: QueryResult + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  fn remove_future <Accessor: FutureCleanupAccessor<Steward = Steward>> (&mut self, accessor: &Accessor, also_present: bool) {
    if self.destroyer.as_ref().map_or(false, |event| {
        let ordering = event.extended_time().cmp(accessor.extended_now());
        ordering == Ordering::Greater || (!also_present && ordering == Ordering::Equal)
      }) {
      self.destroyer = None;
    }
    let removed = split_off_greater_set (&mut self.other_dependent_events, accessor.extended_now());
    for event in removed {
      accessor.invalidate_execution(&event);
    }
    while let Some (change) = self.changes.pop_back() {
      let ordering = change.0.extended_time().cmp(accessor.extended_now());
      if ordering == Ordering::Less || (!also_present && ordering == Ordering::Equal) {
        IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (&change.1, &mut | prediction | {
          if also_present || accessor.get_prediction_destroyer (prediction).map_or (true, | destroyer | &destroyer > accessor.handle()) {
            accessor.change_prediction_destroyer (prediction, None);
          }
        });
        self.changes.push_back (change);
        break
      }
      // if we are actually discarding the event, we need to clean up some stuff about it
      IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (&change.1, &mut | prediction | accessor.change_prediction_destroyer (prediction, Some(& change.0)));

      // except don't re-invalidate the event we are currently in
      if ordering == Ordering::Greater {
        accessor.invalidate_execution(&change.0);
      }
    }
  }

  fn modify <Accessor: EventAccessor<Steward = Steward>> (&mut self, modification: VaryingData, accessor: &Accessor){
    if self.destroyer.as_ref().map_or(false, |event| event.extended_time() <= accessor.extended_now()) {
      panic!("Tried to modify a SimpleTimeline after it was destroyed")
    }
    let mut pop = false;
    if let Some(last) = self.changes.back() {
      assert!(& last.0 <= accessor.handle(), "All future changes should have been cleared before calling modify() ");
      if &last.0 == accessor.handle() {
        pop = true;
      }
    }
    if pop {self.changes.pop_back();}
    // we don't need to create incoming predictions, because they can't be incoming unless they were already created
    self.changes.push_back ((accessor.handle().clone(), modification));
  }
}

impl <VaryingData: QueryResult, Steward: TimeSteward> DataTimeline for SimpleTimeline <VaryingData, Steward> {
  type Basics = Steward::Basics;

  fn clone_for_snapshot (&self, time: &ExtendedTime <Self::Basics>)->Self {
    let mut changes = VecDeque::new();
    match self.search_changes(&time) {
      Ok(index) => {
        if let Some(previous) = index.checked_sub (1) {changes.push_back (self.changes [previous].clone());}
        changes.push_back (self.changes [index].clone());
      },
      Err (index) => if let Some(previous) = index.checked_sub (1) {changes.push_back (self.changes [previous].clone());},
    };
    SimpleTimeline {
      changes: changes,
      destroyer: self.destroyer.clone(),
      other_dependent_events: BTreeSet::new(),
    }
  }

  fn forget_before (&mut self, time: &ExtendedTime <Self::Basics>) {
    let retained = self.other_dependent_events.split_off (time);
    mem::replace (&mut self.other_dependent_events, retained);

    while self.changes.get(1).map_or (false, | change | change.0.extended_time() < time) {
      self.changes.pop_front ();
    }
  }
}
impl <VaryingData: QueryResult, Steward: TimeSteward> DataTimelineQueriableWith<GetVarying> for SimpleTimeline <VaryingData, Steward> {
  type QueryResult = VaryingData;

  fn query (&self, _: &GetVarying, time: &ExtendedTime <Self::Basics>)->Self::QueryResult {
    if self.destroyer.as_ref().map_or(false, |event| event.extended_time() <= time) {
      panic!("Tried to query a SimpleTimeline after it was destroyed")
    }
    let previous_change_index = match self.search_changes(&time) {
      Ok(index) => index,
      Err (index) => index.wrapping_sub (1),
    };
    self.changes.get (previous_change_index).expect("Tried to query a SimpleTimeline before it was first set").1.clone()
  }
}
impl <VaryingData: QueryResult, Steward: TimeSteward> DataTimelineQueryRefableWith<GetVarying> for SimpleTimeline <VaryingData, Steward> {
  fn query_ref (&self, _: &GetVarying, time: &ExtendedTime <Self::Basics>)->&Self::QueryResult {
    if self.destroyer.as_ref().map_or(false, |event| event.extended_time() <= time) {
      panic!("Tried to query a SimpleTimeline after it was destroyed")
    }
    let previous_change_index = match self.search_changes(&time) {
      Ok(index) => index,
      Err (index) => index.wrapping_sub (1),
    };
    &self.changes.get (previous_change_index).expect("Tried to query a SimpleTimeline before it was first set").1
  }
}
impl <VaryingData: QueryResult, Steward: TimeSteward> DataTimelineQueriableWith<JustDestroyed> for SimpleTimeline <VaryingData, Steward> {
  type QueryResult = bool;

  fn query (&self, _: &JustDestroyed, time: &ExtendedTime <Self::Basics>)->Self::QueryResult {
    match self.destroyer.as_ref().map_or(Ordering::Greater, |event| event.extended_time().cmp(time)) {
      Ordering::Greater => false,
      Ordering::Equal => true,
      Ordering::Less => panic!("Tried to query a SimpleTimeline after it was destroyed"),
    }
  }
}

pub fn query <VaryingData: QueryResult, Steward: TimeSteward, A: Accessor <Steward = Steward>> (accessor: & A, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->VaryingData {
  accessor.query (handle, &GetVarying)
}
pub fn tracking_query <VaryingData: QueryResult, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->VaryingData {
  accessor.modify (handle, |timeline| {
    timeline.other_dependent_events.insert (accessor.handle().clone());
  });
  query (accessor, handle)
}
pub fn query_ref <'timeline, VaryingData: QueryResult, Steward: TimeSteward, A: Accessor <Steward = Steward>> (accessor: &'timeline A, handle: &'timeline DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->DataTimelineCellReadGuard<'timeline, VaryingData> {
  accessor.query_ref (handle, &GetVarying)
}
pub fn tracking_query_ref <'timeline, VaryingData: QueryResult, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: &'timeline Accessor, handle: &'timeline DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->DataTimelineCellReadGuard<'timeline, VaryingData> {
  accessor.modify (handle, |timeline| {
    timeline.other_dependent_events.insert (accessor.handle().clone());
  });
  query_ref (accessor, handle)
}
pub fn set <VaryingData: QueryResult + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, modification: VaryingData) {
  //#[cfg (debug_assertions)]
  //let confirm1 = accessor.query (handle, &GetVarying, QueryOffset::Before);
  #[cfg (debug_assertions)]
  let confirm2 = modification.clone();

  let mut do_modify = true;
  if let Some(accessor) = accessor.future_cleanup() {
    // currently, we can't do this culling because
    // distinct predictions at the same time compare equal to each other, so
    // updates that replace an older version of the prediction with a newer version
    // would be incorrectly omitted (in fact, this occurred in bouncy_circles)
    /*match accessor.query (handle, &GetVarying) {
      Some((time, data)) =>
        if let Some (new_data) = modification.as_ref() {
          if &time == accessor.extended_now() && &data == new_data {
            do_modify = false;
          }
        },
      None =>
        if modification.is_none() {do_modify = false;}
    };*/
    if do_modify {
      accessor.peek_mut(handle).remove_future (accessor, false);
    }
  }
  if do_modify {
    accessor.modify (handle, move |timeline| {
      timeline.modify(modification, accessor);
    });
  }

  //#[cfg (debug_assertions)]
  //debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm1);
  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying) == confirm2);
}
pub fn unset <VaryingData: QueryResult + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: FutureCleanupAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>) {
  //#[cfg (debug_assertions)]
  //let confirm = accessor.query (handle, &GetVarying, QueryOffset::Before);

  let mut guard = accessor.peek_mut(handle);
  if guard.search_changes(accessor.extended_now()).is_ok() {
    guard.remove_future (accessor, true);
  }

  //#[cfg (debug_assertions)]
  //debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm);
  //#[cfg (debug_assertions)]
  //debug_assert! (accessor.query (handle, &GetVarying) == confirm);
}

pub fn destroy <VaryingData: QueryResult + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>) {
  if let Some(accessor) = accessor.future_cleanup() {
    accessor.peek_mut(handle).remove_future (accessor, false);
  }
  accessor.modify (handle, move |timeline| {
    timeline.destroyer = Some(accessor.handle().clone());
  });
}

/// You're supposed to destroy a SimpleTimeline when there are no more handles to it in the simulation state. In that situation, there might be some handles left on the stack. As a convenience, we provide this way of querying whether a handle is in that state, so that you don't have to keep track of it yourself.
///
/// Note that this will still panic if you check on a timeline in a later event after it's been destroyed.
pub fn just_destroyed <VaryingData: QueryResult, Steward: TimeSteward, A: Accessor <Steward = Steward>> (accessor: & A, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->bool {
  accessor.query (handle, & JustDestroyed)
}

} //mod

  };
}

<commit_msg>Fixed SimpleTimeline snapshots unnecessarily including old values now that QueryOffset::Before is gone<commit_after>#[doc (hidden)]
#[macro_export]
macro_rules! time_steward_define_simple_timeline {
  () => {
pub mod simple_timeline {
use std::collections::{BTreeSet, VecDeque};
use std::mem;

use super::super::super::api::*;
use super::*;
use implementation_support::common::{split_off_greater_set};

#[derive (Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
pub struct GetVarying;
impl PersistentlyIdentifiedType for GetVarying {
  const ID: PersistentTypeId = PersistentTypeId(0x8912fbb263c46434);
}

#[derive (Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
pub struct JustDestroyed;
impl PersistentlyIdentifiedType for JustDestroyed {
  const ID: PersistentTypeId = PersistentTypeId(0x4ee4ba51f56f884d);
}

pub trait IterateUniquelyOwnedPredictions <Steward: TimeSteward> {
  fn iterate_predictions <F: FnMut (& Steward::EventHandle)> (&self, _callback: &mut F) {}
}

#[serde(bound = "")]
#[derive (Serialize, Deserialize, Derivative)]
#[derivative (Clone (bound=""), Debug (bound=""))]
pub struct SimpleTimeline <VaryingData: QueryResult, Steward: TimeSteward> {
  // Hacky workaround for https://github.com/rust-lang/rust/issues/41617 (see https://github.com/serde-rs/serde/issues/943)
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  changes: VecDeque<(<Steward as TimeSteward>::EventHandle, VaryingData)>,
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  destroyer: Option<<Steward as TimeSteward>::EventHandle>,
  #[serde(deserialize_with = "::serde::Deserialize::deserialize")]
  other_dependent_events: BTreeSet<<Steward as TimeSteward>::EventHandle>,
}

impl <VaryingData: QueryResult, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  pub fn new ()->Self {
    SimpleTimeline {
      changes: VecDeque::new(),
      destroyer: None,
      other_dependent_events: BTreeSet::new(),
    }
  }

  fn search_changes (&self, time: &ExtendedTime <Steward::Basics>) -> Result <usize, usize> {
    // search at the end first, because we are usually in the present.

    match self.changes.back() {
      None => return Err(0),
      Some (&(ref event, _)) => {
        match event.extended_time().cmp(time) {
          Ordering::Greater => (),
          Ordering::Equal => return Ok(self.changes.len()-1),
          Ordering::Less => return Err(self.changes.len()),
        }
      },
    }

    let mut drop = 2;
    let mut max = self.changes.len()-1;
    let mut min;
    loop {
      if let Some(further) = self.changes.len().checked_sub (drop) {
        let change = self.changes.get (further).unwrap();
        match change.0.extended_time().cmp(time) {
          Ordering::Greater => {
            max = further;
            drop *= 2;
          },
          Ordering::Equal => return Ok(further),
          Ordering::Less => {
            min = further;
            break;
          },
        }
      }
      else {
        min = 0;
        break;
      }
    }
    while max >= min+2 {
      let mid = (max + min) >> 1;
      let change = self.changes.get (mid).unwrap();
      match change.0.extended_time().cmp(time) {
        Ordering::Greater => max = mid,
        Ordering::Equal => return Ok(mid),
        Ordering::Less => min = mid,
      }
    }

    if self.changes.get (min).unwrap().0.extended_time() > time {
      return Err (min)
    }
    Err(max)
  }
}
impl <VaryingData: QueryResult + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward> SimpleTimeline <VaryingData, Steward> {
  fn remove_future <Accessor: FutureCleanupAccessor<Steward = Steward>> (&mut self, accessor: &Accessor, also_present: bool) {
    if self.destroyer.as_ref().map_or(false, |event| {
        let ordering = event.extended_time().cmp(accessor.extended_now());
        ordering == Ordering::Greater || (!also_present && ordering == Ordering::Equal)
      }) {
      self.destroyer = None;
    }
    let removed = split_off_greater_set (&mut self.other_dependent_events, accessor.extended_now());
    for event in removed {
      accessor.invalidate_execution(&event);
    }
    while let Some (change) = self.changes.pop_back() {
      let ordering = change.0.extended_time().cmp(accessor.extended_now());
      if ordering == Ordering::Less || (!also_present && ordering == Ordering::Equal) {
        IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (&change.1, &mut | prediction | {
          if also_present || accessor.get_prediction_destroyer (prediction).map_or (true, | destroyer | &destroyer > accessor.handle()) {
            accessor.change_prediction_destroyer (prediction, None);
          }
        });
        self.changes.push_back (change);
        break
      }
      // if we are actually discarding the event, we need to clean up some stuff about it
      IterateUniquelyOwnedPredictions::<Steward>::iterate_predictions (&change.1, &mut | prediction | accessor.change_prediction_destroyer (prediction, Some(& change.0)));

      // except don't re-invalidate the event we are currently in
      if ordering == Ordering::Greater {
        accessor.invalidate_execution(&change.0);
      }
    }
  }

  fn modify <Accessor: EventAccessor<Steward = Steward>> (&mut self, modification: VaryingData, accessor: &Accessor){
    if self.destroyer.as_ref().map_or(false, |event| event.extended_time() <= accessor.extended_now()) {
      panic!("Tried to modify a SimpleTimeline after it was destroyed")
    }
    let mut pop = false;
    if let Some(last) = self.changes.back() {
      assert!(& last.0 <= accessor.handle(), "All future changes should have been cleared before calling modify() ");
      if &last.0 == accessor.handle() {
        pop = true;
      }
    }
    if pop {self.changes.pop_back();}
    // we don't need to create incoming predictions, because they can't be incoming unless they were already created
    self.changes.push_back ((accessor.handle().clone(), modification));
  }
}

impl <VaryingData: QueryResult, Steward: TimeSteward> DataTimeline for SimpleTimeline <VaryingData, Steward> {
  type Basics = Steward::Basics;

  fn clone_for_snapshot (&self, time: &ExtendedTime <Self::Basics>)->Self {
    let mut changes = VecDeque::new();
    match self.search_changes(&time) {
      Ok(index) => changes.push_back (self.changes [index].clone()),
      Err (index) => if let Some(previous) = index.checked_sub (1) {changes.push_back (self.changes [previous].clone());},
    };
    SimpleTimeline {
      changes: changes,
      destroyer: self.destroyer.clone(),
      other_dependent_events: BTreeSet::new(),
    }
  }

  fn forget_before (&mut self, time: &ExtendedTime <Self::Basics>) {
    let retained = self.other_dependent_events.split_off (time);
    mem::replace (&mut self.other_dependent_events, retained);

    while self.changes.get(1).map_or (false, | change | change.0.extended_time() < time) {
      self.changes.pop_front ();
    }
  }
}
impl <VaryingData: QueryResult, Steward: TimeSteward> DataTimelineQueriableWith<GetVarying> for SimpleTimeline <VaryingData, Steward> {
  type QueryResult = VaryingData;

  fn query (&self, _: &GetVarying, time: &ExtendedTime <Self::Basics>)->Self::QueryResult {
    if self.destroyer.as_ref().map_or(false, |event| event.extended_time() <= time) {
      panic!("Tried to query a SimpleTimeline after it was destroyed")
    }
    let previous_change_index = match self.search_changes(&time) {
      Ok(index) => index,
      Err (index) => index.wrapping_sub (1),
    };
    self.changes.get (previous_change_index).expect("Tried to query a SimpleTimeline before it was first set").1.clone()
  }
}
impl <VaryingData: QueryResult, Steward: TimeSteward> DataTimelineQueryRefableWith<GetVarying> for SimpleTimeline <VaryingData, Steward> {
  fn query_ref (&self, _: &GetVarying, time: &ExtendedTime <Self::Basics>)->&Self::QueryResult {
    if self.destroyer.as_ref().map_or(false, |event| event.extended_time() <= time) {
      panic!("Tried to query a SimpleTimeline after it was destroyed")
    }
    let previous_change_index = match self.search_changes(&time) {
      Ok(index) => index,
      Err (index) => index.wrapping_sub (1),
    };
    &self.changes.get (previous_change_index).expect("Tried to query a SimpleTimeline before it was first set").1
  }
}
impl <VaryingData: QueryResult, Steward: TimeSteward> DataTimelineQueriableWith<JustDestroyed> for SimpleTimeline <VaryingData, Steward> {
  type QueryResult = bool;

  fn query (&self, _: &JustDestroyed, time: &ExtendedTime <Self::Basics>)->Self::QueryResult {
    match self.destroyer.as_ref().map_or(Ordering::Greater, |event| event.extended_time().cmp(time)) {
      Ordering::Greater => false,
      Ordering::Equal => true,
      Ordering::Less => panic!("Tried to query a SimpleTimeline after it was destroyed"),
    }
  }
}

pub fn query <VaryingData: QueryResult, Steward: TimeSteward, A: Accessor <Steward = Steward>> (accessor: & A, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->VaryingData {
  accessor.query (handle, &GetVarying)
}
pub fn tracking_query <VaryingData: QueryResult, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->VaryingData {
  accessor.modify (handle, |timeline| {
    timeline.other_dependent_events.insert (accessor.handle().clone());
  });
  query (accessor, handle)
}
pub fn query_ref <'timeline, VaryingData: QueryResult, Steward: TimeSteward, A: Accessor <Steward = Steward>> (accessor: &'timeline A, handle: &'timeline DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->DataTimelineCellReadGuard<'timeline, VaryingData> {
  accessor.query_ref (handle, &GetVarying)
}
pub fn tracking_query_ref <'timeline, VaryingData: QueryResult, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: &'timeline Accessor, handle: &'timeline DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->DataTimelineCellReadGuard<'timeline, VaryingData> {
  accessor.modify (handle, |timeline| {
    timeline.other_dependent_events.insert (accessor.handle().clone());
  });
  query_ref (accessor, handle)
}
pub fn set <VaryingData: QueryResult + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>, modification: VaryingData) {
  //#[cfg (debug_assertions)]
  //let confirm1 = accessor.query (handle, &GetVarying, QueryOffset::Before);
  #[cfg (debug_assertions)]
  let confirm2 = modification.clone();

  let mut do_modify = true;
  if let Some(accessor) = accessor.future_cleanup() {
    // currently, we can't do this culling because
    // distinct predictions at the same time compare equal to each other, so
    // updates that replace an older version of the prediction with a newer version
    // would be incorrectly omitted (in fact, this occurred in bouncy_circles)
    /*match accessor.query (handle, &GetVarying) {
      Some((time, data)) =>
        if let Some (new_data) = modification.as_ref() {
          if &time == accessor.extended_now() && &data == new_data {
            do_modify = false;
          }
        },
      None =>
        if modification.is_none() {do_modify = false;}
    };*/
    if do_modify {
      accessor.peek_mut(handle).remove_future (accessor, false);
    }
  }
  if do_modify {
    accessor.modify (handle, move |timeline| {
      timeline.modify(modification, accessor);
    });
  }

  //#[cfg (debug_assertions)]
  //debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm1);
  #[cfg (debug_assertions)]
  debug_assert! (accessor.query (handle, &GetVarying) == confirm2);
}
pub fn unset <VaryingData: QueryResult + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: FutureCleanupAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>) {
  //#[cfg (debug_assertions)]
  //let confirm = accessor.query (handle, &GetVarying, QueryOffset::Before);

  let mut guard = accessor.peek_mut(handle);
  if guard.search_changes(accessor.extended_now()).is_ok() {
    guard.remove_future (accessor, true);
  }

  //#[cfg (debug_assertions)]
  //debug_assert! (accessor.query (handle, &GetVarying, QueryOffset::Before) == confirm);
  //#[cfg (debug_assertions)]
  //debug_assert! (accessor.query (handle, &GetVarying) == confirm);
}

pub fn destroy <VaryingData: QueryResult + IterateUniquelyOwnedPredictions <Steward>, Steward: TimeSteward, Accessor: EventAccessor <Steward = Steward>> (accessor: & Accessor, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>) {
  if let Some(accessor) = accessor.future_cleanup() {
    accessor.peek_mut(handle).remove_future (accessor, false);
  }
  accessor.modify (handle, move |timeline| {
    timeline.destroyer = Some(accessor.handle().clone());
  });
}

/// You're supposed to destroy a SimpleTimeline when there are no more handles to it in the simulation state. In that situation, there might be some handles left on the stack. As a convenience, we provide this way of querying whether a handle is in that state, so that you don't have to keep track of it yourself.
///
/// Note that this will still panic if you check on a timeline in a later event after it's been destroyed.
pub fn just_destroyed <VaryingData: QueryResult, Steward: TimeSteward, A: Accessor <Steward = Steward>> (accessor: & A, handle: & DataTimelineCell <SimpleTimeline <VaryingData, Steward>>)->bool {
  accessor.query (handle, & JustDestroyed)
}

} //mod

  };
}

<|endoftext|>


<commit_before>// Copyright 2014, 2015 Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
// Copyright 2012 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.

#![allow(unstable_features)]

#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(libc)]
#![feature(std_misc)]
#![feature(test)]

#[macro_use]
extern crate c_string;

extern crate test;
extern crate libc;

use std::error::FromError;
use std::ffi::CStr;
use std::io::Error as IoError;
use std::io::ErrorKind::InvalidInput;
use std::iter::Iterator;
use std::ptr;

use c_string::{CStrBuf, OwnedCString, CChars};
use c_string::{libc_free, parse_c_multistring};

pub fn check_c_str(c_str: &CStr, expected: &[u8]) {
    let buf = c_str.as_ptr();
    let len = expected.len();
    for i in (0 .. len) {
        let byte = unsafe { *buf.offset(i as isize) as u8 };
        assert_eq!(byte, expected[i]);
    }
    let term = unsafe { *buf.offset(len as isize) as u8 };
    assert_eq!(term, 0);
}

unsafe fn bytes_dup_raw(s: &[u8]) -> *const libc::c_char {
    let len = s.len();
    let dup = libc::malloc((len + 1) as libc::size_t) as *mut u8;
    ptr::copy_nonoverlapping_memory(dup, s.as_ptr(), len);
    *dup.offset(len as isize) = 0;
    dup as *const libc::c_char
}

fn bytes_dup(s: &[u8]) -> OwnedCString {
    unsafe {
        OwnedCString::new(bytes_dup_raw(s), libc_free)
    }
}

fn str_dup(s: &str) -> OwnedCString {
    bytes_dup(s.as_bytes())
}

#[test]
fn test_parse_c_multistring() {
    unsafe {
        let input = b"zero\0one\0\0";
        let ptr = input.as_ptr();
        let expected = ["zero", "one"];
        let mut it = expected.iter();
        let result = parse_c_multistring(ptr as *const libc::c_char, None,
            |cbytes| {
                assert_eq!(cbytes, it.next().unwrap().as_bytes());
            });
        assert_eq!(result, 2);
        assert!(it.next().is_none());
    }
}

#[test]
fn test_c_str_macro() {
    let c_str = c_str!("hello");
    check_c_str(c_str, b"hello");
}

#[test]
fn test_owned_c_string_deref() {
    let c_str = str_dup("hello");
    check_c_str(&c_str, b"hello");
}

#[test]
fn test_owned_c_string_as_ptr() {
    let c_str = str_dup("hello");
    let len = unsafe { libc::strlen(c_str.as_ptr()) };
    assert_eq!(len, 5);
}

#[test]
fn test_iterator() {
    let c_string = str_dup("");
    let mut iter = CChars::from_c_str(&c_string);
    assert_eq!(iter.next(), None);

    let c_string = str_dup("hello");
    let mut iter = CChars::from_c_str(&c_string);
    assert_eq!(iter.next(), Some('h' as libc::c_char));
    assert_eq!(iter.next(), Some('e' as libc::c_char));
    assert_eq!(iter.next(), Some('l' as libc::c_char));
    assert_eq!(iter.next(), Some('l' as libc::c_char));
    assert_eq!(iter.next(), Some('o' as libc::c_char));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_c_str_buf_from_iter() {
    let test_strings = [
        b"",
        b"foo\xFF",
        b"Mary had a little \xD0\x0D, Little \xD0\x0D"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
        check_c_str(&c_str, bytes);
    }

    let test_strings = [
        b"got\0nul",
        b"Mary had a little lamb, Little \0"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let res = CStrBuf::from_iter(bytes.iter().cloned());
        let err = res.err().unwrap();
        assert_eq!(err.nul_position(), bytes.position_elem(&0u8).unwrap());
        let vec = err.into_bytes();
        assert_eq!(&vec, bytes);
    }
}

#[test]
fn test_c_str_buf_from_str() {
    let c_str = CStrBuf::from_str("").unwrap();
    check_c_str(&c_str, b"");

    let c_str = CStrBuf::from_str("hello").unwrap();
    check_c_str(&c_str, b"hello");

    // Owned variant
    let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
    check_c_str(&c_str, b"Mary had a little lamb, Little lamb");

    let res = CStrBuf::from_str("got\0nul");
    let err = res.err().unwrap();
    assert_eq!(err.nul_position(), 3);
    let bytes = err.into_bytes();
    assert_eq!(bytes, b"got\0nul");
}

#[test]
fn test_io_error_from_nul_error() {
    let res = CStrBuf::from_str("got\0nul");
    let err = res.err().unwrap();
    let io_err: IoError = FromError::from_error(err);
    assert_eq!(io_err.kind(), InvalidInput);
    assert!(io_err.detail().is_some());
}

#[test]
fn test_c_str_buf_from_vec() {
    let test_strings = [
        b"",
        b"foo\xFF",
        b"Mary had a little \xD0\x0D, Little \xD0\x0D"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let c_str = CStrBuf::from_vec(bytes.to_vec()).unwrap();
        check_c_str(&c_str, bytes);
    }

    let test_strings = [
        b"got\0nul",
        b"Mary had a little lamb, Little \0"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let res = CStrBuf::from_vec(bytes.to_vec());
        let err = res.err().unwrap();
        assert_eq!(err.nul_position(), bytes.position_elem(&0u8).unwrap());
        let vec = err.into_bytes();
        assert_eq!(&vec, bytes);
    }
}

#[test]
fn test_io_error_from_into_c_str_error() {
    let res = CStrBuf::from_vec(b"got\0nul".to_vec());
    let err = res.err().unwrap();
    let io_err: IoError = FromError::from_error(err);
    assert_eq!(io_err.kind(), InvalidInput);
    assert!(io_err.detail().is_some());
}

#[test]
fn test_c_str_buf_into_vec() {
    let c_str = CStrBuf::from_str("").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"");
    let c_str = CStrBuf::from_str("hello").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"hello");
    let bytes = b"foo\xFF";
    let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], bytes);

    // Owned variant
    let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"Mary had a little lamb, Little lamb");
    let bytes = b"Mary had a little \xD0\x0D, Little \xD0\x0D";
    let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], bytes);
}

#[test]
fn test_owned_c_string_to_bytes() {
    let c_str = str_dup("hello");
    assert_eq!(c_str.to_bytes(), b"hello");
    let c_str = str_dup("");
    assert_eq!(c_str.to_bytes(), b"");
    let c_str = bytes_dup(b"foo\xFF");
    assert_eq!(c_str.to_bytes(), b"foo\xFF");
}

#[test]
fn test_owned_c_string_debug() {
    let c_str = str_dup("hello");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, "\"hello\"");
    let c_str = str_dup("");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, "\"\"");
    let c_str = bytes_dup(b"foo\xFF");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, r#""foo\xff""#);
}

#[test]
#[should_fail]
fn test_c_string_new_fail() {
    let _c_str: OwnedCString = unsafe {
        OwnedCString::new(ptr::null(), libc_free)
    };
}
<commit_msg>Use copy_nonoverlapping<commit_after>// Copyright 2014, 2015 Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
// Copyright 2012 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.

#![allow(unstable_features)]

#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(libc)]
#![feature(std_misc)]
#![feature(test)]

#[macro_use]
extern crate c_string;

extern crate test;
extern crate libc;

use std::error::FromError;
use std::ffi::CStr;
use std::io::Error as IoError;
use std::io::ErrorKind::InvalidInput;
use std::iter::Iterator;
use std::ptr;

use c_string::{CStrBuf, OwnedCString, CChars};
use c_string::{libc_free, parse_c_multistring};

pub fn check_c_str(c_str: &CStr, expected: &[u8]) {
    let buf = c_str.as_ptr();
    let len = expected.len();
    for i in (0 .. len) {
        let byte = unsafe { *buf.offset(i as isize) as u8 };
        assert_eq!(byte, expected[i]);
    }
    let term = unsafe { *buf.offset(len as isize) as u8 };
    assert_eq!(term, 0);
}

unsafe fn bytes_dup_raw(s: &[u8]) -> *const libc::c_char {
    let len = s.len();
    let dup = libc::malloc((len + 1) as libc::size_t) as *mut u8;
    ptr::copy_nonoverlapping(dup, s.as_ptr(), len);
    *dup.offset(len as isize) = 0;
    dup as *const libc::c_char
}

fn bytes_dup(s: &[u8]) -> OwnedCString {
    unsafe {
        OwnedCString::new(bytes_dup_raw(s), libc_free)
    }
}

fn str_dup(s: &str) -> OwnedCString {
    bytes_dup(s.as_bytes())
}

#[test]
fn test_parse_c_multistring() {
    unsafe {
        let input = b"zero\0one\0\0";
        let ptr = input.as_ptr();
        let expected = ["zero", "one"];
        let mut it = expected.iter();
        let result = parse_c_multistring(ptr as *const libc::c_char, None,
            |cbytes| {
                assert_eq!(cbytes, it.next().unwrap().as_bytes());
            });
        assert_eq!(result, 2);
        assert!(it.next().is_none());
    }
}

#[test]
fn test_c_str_macro() {
    let c_str = c_str!("hello");
    check_c_str(c_str, b"hello");
}

#[test]
fn test_owned_c_string_deref() {
    let c_str = str_dup("hello");
    check_c_str(&c_str, b"hello");
}

#[test]
fn test_owned_c_string_as_ptr() {
    let c_str = str_dup("hello");
    let len = unsafe { libc::strlen(c_str.as_ptr()) };
    assert_eq!(len, 5);
}

#[test]
fn test_iterator() {
    let c_string = str_dup("");
    let mut iter = CChars::from_c_str(&c_string);
    assert_eq!(iter.next(), None);

    let c_string = str_dup("hello");
    let mut iter = CChars::from_c_str(&c_string);
    assert_eq!(iter.next(), Some('h' as libc::c_char));
    assert_eq!(iter.next(), Some('e' as libc::c_char));
    assert_eq!(iter.next(), Some('l' as libc::c_char));
    assert_eq!(iter.next(), Some('l' as libc::c_char));
    assert_eq!(iter.next(), Some('o' as libc::c_char));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_c_str_buf_from_iter() {
    let test_strings = [
        b"",
        b"foo\xFF",
        b"Mary had a little \xD0\x0D, Little \xD0\x0D"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
        check_c_str(&c_str, bytes);
    }

    let test_strings = [
        b"got\0nul",
        b"Mary had a little lamb, Little \0"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let res = CStrBuf::from_iter(bytes.iter().cloned());
        let err = res.err().unwrap();
        assert_eq!(err.nul_position(), bytes.position_elem(&0u8).unwrap());
        let vec = err.into_bytes();
        assert_eq!(&vec, bytes);
    }
}

#[test]
fn test_c_str_buf_from_str() {
    let c_str = CStrBuf::from_str("").unwrap();
    check_c_str(&c_str, b"");

    let c_str = CStrBuf::from_str("hello").unwrap();
    check_c_str(&c_str, b"hello");

    // Owned variant
    let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
    check_c_str(&c_str, b"Mary had a little lamb, Little lamb");

    let res = CStrBuf::from_str("got\0nul");
    let err = res.err().unwrap();
    assert_eq!(err.nul_position(), 3);
    let bytes = err.into_bytes();
    assert_eq!(bytes, b"got\0nul");
}

#[test]
fn test_io_error_from_nul_error() {
    let res = CStrBuf::from_str("got\0nul");
    let err = res.err().unwrap();
    let io_err: IoError = FromError::from_error(err);
    assert_eq!(io_err.kind(), InvalidInput);
    assert!(io_err.detail().is_some());
}

#[test]
fn test_c_str_buf_from_vec() {
    let test_strings = [
        b"",
        b"foo\xFF",
        b"Mary had a little \xD0\x0D, Little \xD0\x0D"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let c_str = CStrBuf::from_vec(bytes.to_vec()).unwrap();
        check_c_str(&c_str, bytes);
    }

    let test_strings = [
        b"got\0nul",
        b"Mary had a little lamb, Little \0"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let res = CStrBuf::from_vec(bytes.to_vec());
        let err = res.err().unwrap();
        assert_eq!(err.nul_position(), bytes.position_elem(&0u8).unwrap());
        let vec = err.into_bytes();
        assert_eq!(&vec, bytes);
    }
}

#[test]
fn test_io_error_from_into_c_str_error() {
    let res = CStrBuf::from_vec(b"got\0nul".to_vec());
    let err = res.err().unwrap();
    let io_err: IoError = FromError::from_error(err);
    assert_eq!(io_err.kind(), InvalidInput);
    assert!(io_err.detail().is_some());
}

#[test]
fn test_c_str_buf_into_vec() {
    let c_str = CStrBuf::from_str("").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"");
    let c_str = CStrBuf::from_str("hello").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"hello");
    let bytes = b"foo\xFF";
    let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], bytes);

    // Owned variant
    let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"Mary had a little lamb, Little lamb");
    let bytes = b"Mary had a little \xD0\x0D, Little \xD0\x0D";
    let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], bytes);
}

#[test]
fn test_owned_c_string_to_bytes() {
    let c_str = str_dup("hello");
    assert_eq!(c_str.to_bytes(), b"hello");
    let c_str = str_dup("");
    assert_eq!(c_str.to_bytes(), b"");
    let c_str = bytes_dup(b"foo\xFF");
    assert_eq!(c_str.to_bytes(), b"foo\xFF");
}

#[test]
fn test_owned_c_string_debug() {
    let c_str = str_dup("hello");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, "\"hello\"");
    let c_str = str_dup("");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, "\"\"");
    let c_str = bytes_dup(b"foo\xFF");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, r#""foo\xff""#);
}

#[test]
#[should_fail]
fn test_c_string_new_fail() {
    let _c_str: OwnedCString = unsafe {
        OwnedCString::new(ptr::null(), libc_free)
    };
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use about_loader;
use mime_classifier::MIMEClassifier;
use mime_guess::guess_mime_type;
use net_traits::ProgressMsg::{Done, Payload};
use net_traits::{LoadConsumer, LoadData, Metadata};
use resource_thread::{CancellationListener, ProgressSender};
use resource_thread::{send_error, start_sending_sniffed, start_sending_sniffed_opt};
use std::borrow::ToOwned;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use url::Url;
use util::thread::spawn_named;

static READ_SIZE: usize = 8192;

enum ReadStatus {
    Partial(Vec<u8>),
    EOF,
}

enum LoadResult {
    Cancelled,
    Finished,
}

fn read_block(reader: &mut File) -> Result<ReadStatus, String> {
    let mut buf = vec![0; READ_SIZE];
    match reader.read(&mut buf) {
        Ok(0) => Ok(ReadStatus::EOF),
        Ok(n) => {
            buf.truncate(n);
            Ok(ReadStatus::Partial(buf))
        }
        Err(e) => Err(e.description().to_owned()),
    }
}

fn read_all(reader: &mut File, progress_chan: &ProgressSender, cancel_listener: &CancellationListener)
            -> Result<LoadResult, String> {
    loop {
        if cancel_listener.is_cancelled() {
            return Ok(LoadResult::Cancelled);
        }

        match try!(read_block(reader)) {
            ReadStatus::Partial(buf) => progress_chan.send(Payload(buf)).unwrap(),
            ReadStatus::EOF => return Ok(LoadResult::Finished),
        }
    }
}

pub fn factory(load_data: LoadData,
               senders: LoadConsumer,
               classifier: Arc<MIMEClassifier>,
               cancel_listener: CancellationListener) {
    let url = load_data.url;
    let context = load_data.context;
    assert!(&*url.scheme == "file");
    spawn_named("file_loader".to_owned(), move || {
        let file_path: Result<PathBuf, ()> = url.to_file_path();
        match file_path {
            Ok(file_path) => {
                match File::open(&file_path) {
                    Ok(ref mut reader) => {
                        if cancel_listener.is_cancelled() {
                            return;
                        }
                        match read_block(reader) {
                            Ok(ReadStatus::Partial(buf)) => {
                                let mut metadata = Metadata::default(url);
                                let mime_type = guess_mime_type(file_path.as_path());
                                metadata.set_content_type(Some(&mime_type));
                                let progress_chan = start_sending_sniffed(senders, metadata,
                                                                          classifier, &buf, context);
                                progress_chan.send(Payload(buf)).unwrap();
                                let read_result = read_all(reader, &progress_chan, &cancel_listener);
                                if let Ok(load_result) = read_result {
                                    match load_result {
                                        LoadResult::Cancelled => return,
                                        LoadResult::Finished => progress_chan.send(Done(Ok(()))).unwrap(),
                                    }
                                }
                            }
                            Ok(ReadStatus::EOF) => {
                                let mut metadata = Metadata::default(url);
                                let mime_type = guess_mime_type(file_path.as_path());
                                metadata.set_content_type(Some(&mime_type));
                                if let Ok(chan) = start_sending_sniffed_opt(senders,
                                                                            metadata,
                                                                            classifier,
                                                                            &[],
                                                                            context) {
                                    let _ = chan.send(Done(Ok(())));
                                }
                            }
                            Err(e) => {
                                send_error(url, e, senders);
                            }
                        };
                    }
                    Err(_) => {
                        // this should be one of the three errors listed in
                        // http://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open
                        // but, we'll go for a "file not found!"
                        let url = Url::parse("about:not-found").unwrap();
                        let load_data_404 = LoadData::new(context, url, None);
                        about_loader::factory(load_data_404, senders, classifier, cancel_listener)
                    }
                }
            }
            Err(_) => {
                send_error(url, "Could not parse path".to_owned(), senders);
            }
        }
    });
}
<commit_msg>Issue #9095: Send a notification when a file load is cancelled.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use about_loader;
use mime_classifier::MIMEClassifier;
use mime_guess::guess_mime_type;
use net_traits::ProgressMsg::{Done, Payload};
use net_traits::{LoadConsumer, LoadData, Metadata};
use resource_thread::{CancellationListener, ProgressSender};
use resource_thread::{send_error, start_sending_sniffed_opt};
use std::borrow::ToOwned;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use url::Url;
use util::thread::spawn_named;

static READ_SIZE: usize = 8192;

enum ReadStatus {
    Partial(Vec<u8>),
    EOF,
}

enum LoadResult {
    Cancelled,
    Finished,
}

fn read_block(reader: &mut File) -> Result<ReadStatus, String> {
    let mut buf = vec![0; READ_SIZE];
    match reader.read(&mut buf) {
        Ok(0) => Ok(ReadStatus::EOF),
        Ok(n) => {
            buf.truncate(n);
            Ok(ReadStatus::Partial(buf))
        }
        Err(e) => Err(e.description().to_owned()),
    }
}

fn read_all(reader: &mut File, progress_chan: &ProgressSender, cancel_listener: &CancellationListener)
            -> Result<LoadResult, String> {
    loop {
        if cancel_listener.is_cancelled() {
            let _ = progress_chan.send(Done(Err("load cancelled".to_owned())));
            return Ok(LoadResult::Cancelled);
        }

        match try!(read_block(reader)) {
            ReadStatus::Partial(buf) => progress_chan.send(Payload(buf)).unwrap(),
            ReadStatus::EOF => return Ok(LoadResult::Finished),
        }
    }
}

fn get_progress_chan(load_data: LoadData, file_path: PathBuf,
                     senders: LoadConsumer, classifier: Arc<MIMEClassifier>, buf: &[u8])
                     -> Result<ProgressSender, ()> {
    let mut metadata = Metadata::default(load_data.url);
    let mime_type = guess_mime_type(file_path.as_path());
    metadata.set_content_type(Some(&mime_type));
    return start_sending_sniffed_opt(senders, metadata, classifier, buf, load_data.context);
}

pub fn factory(load_data: LoadData,
               senders: LoadConsumer,
               classifier: Arc<MIMEClassifier>,
               cancel_listener: CancellationListener) {
    assert!(&*load_data.url.scheme == "file");
    spawn_named("file_loader".to_owned(), move || {
        let file_path: Result<PathBuf, ()> = load_data.url.to_file_path();
        match file_path {
            Ok(file_path) => {
                match File::open(&file_path) {
                    Ok(ref mut reader) => {
                        if cancel_listener.is_cancelled() {
                            if let Ok(progress_chan) = get_progress_chan(load_data, file_path,
                                                                         senders, classifier, &[]) {
                                let _ = progress_chan.send(Done(Err("load cancelled".to_owned())));
                            }
                            return;
                        }
                        match read_block(reader) {
                            Ok(ReadStatus::Partial(buf)) => {
                                let progress_chan = get_progress_chan(load_data, file_path,
                                                                      senders, classifier, &buf).ok().unwrap();
                                progress_chan.send(Payload(buf)).unwrap();
                                let read_result = read_all(reader, &progress_chan, &cancel_listener);
                                if let Ok(load_result) = read_result {
                                    match load_result {
                                        LoadResult::Cancelled => return,
                                        LoadResult::Finished => progress_chan.send(Done(Ok(()))).unwrap(),
                                    }
                                }
                            }
                            Ok(ReadStatus::EOF) => {
                                if let Ok(chan) = get_progress_chan(load_data, file_path,
                                                                    senders, classifier, &[]) {
                                    let _ = chan.send(Done(Ok(())));
                                }
                            }
                            Err(e) => {
                                send_error(load_data.url, e, senders);
                            }
                        };
                    }
                    Err(_) => {
                        // this should be one of the three errors listed in
                        // http://doc.rust-lang.org/std/fs/struct.OpenOptions.html#method.open
                        // but, we'll go for a "file not found!"
                        let url = Url::parse("about:not-found").unwrap();
                        let load_data_404 = LoadData::new(load_data.context, url, None);
                        about_loader::factory(load_data_404, senders, classifier, cancel_listener)
                    }
                }
            }
            Err(_) => {
                send_error(load_data.url, "Could not parse path".to_owned(), senders);
            }
        }
    });
}
<|endoftext|>


<commit_before>//! Helper to crudely rewrite types from the spec's format to our own.
//!
//! This reads a file containing table and record descriptions (from the spec)
//! and converts them to the form that we use, writing the result to stdout.
//!
//! Input should be in the format:
//!
//!
//! ```
//! Gpos1_0
//! uint16      majorVersion       Major version of the GPOS table, = 1
//! uint16      minorVersion       Minor version of the GPOS table, = 0
//! Offset16    scriptListOffset   Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset  Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset   Offset to LookupList table, from beginning of GPOS table
//!
//! Gpos1_1
//! uint16      majorVersion            Major version of the GPOS table, = 1
//! uint16      minorVersion            Minor version of the GPOS table, = 1
//! Offset16    scriptListOffset        Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset       Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset        Offset to LookupList table, from beginning of GPOS table
//! Offset32    featureVariationsOffset Offset to FeatureVariations table, from beginning of GPOS table (may be NULL)
//! ```
//!
//! - different records/tables are separated by newlines.
//! - the first line should be a single word, used as the name of the type
//! - other lines are just copy pasted
//!
//! *limitations:* this doesn't handle lifetimes, and doesn't generate annotations.
//! You will need to clean up the output.

use std::fmt::Write;

macro_rules! exit_with_msg {
    ($disp:expr) => {{
        eprintln!("ERROR: {}", $disp);
        std::process::exit(1);
    }};
}

static MACRO_CALL: &str = "toy_table_macro::tables!";

fn main() {
    let in_path = std::env::args().nth(1).expect("expected path argument");
    let input = std::fs::read_to_string(in_path).expect("failed to read path");
    let mut lines = input.lines().map(str::trim).filter(|l| !l.starts_with('#'));
    println!("{} {{", MACRO_CALL);
    while let Some(item) = generate_one_item(&mut lines) {
        println!("{}", item);
    }
    println!("}}");
}

/// parse a single table or record.
///
/// Returns `Some` on success, `None` if there are no more items, and terminates
/// if something goes wrong.
fn generate_one_item<'a>(lines: impl Iterator<Item = &'a str>) -> Option<String> {
    let mut lines = lines.skip_while(|line| line.is_empty());

    let name = match lines.next() {
        Some(line) if line.split_whitespace().nth(1).is_none() => line,
        Some(line) => exit_with_msg!(format!("expected table or record name, found '{}'", line)),
        _ => return None,
    };

    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let lifetime_str = if fields.iter().any(|x| x.maybe_count.is_some()) {
        "<'a>"
    } else {
        ""
    };
    let mut result = format!("{}{} {{\n", name, lifetime_str);
    for line in &fields {
        writeln!(&mut result, "{}", line).unwrap();
    }
    result.push_str("}\n");
    Some(result)
}

struct Field<'a> {
    name: String,
    maybe_count: Option<String>,
    typ: &'a str,
    comment: &'a str,
}

impl<'a> std::fmt::Display for Field<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        format_comment(f, "    ", self.comment)?;
        if self.name.contains("reserved") {
            writeln!(f, "    #[hidden]")?;
        }
        if let Some(count) = &self.maybe_count {
            writeln!(f, "    #[count({})]", count)?;
            write!(f, "    {}: [{}],", self.name, self.typ)?;
        } else {
            write!(f, "    {}: {},", self.name, self.typ)?;
        }
        Ok(())
    }
}

fn parse_field(line: &str) -> Option<Field> {
    if line.is_empty() {
        return None;
    }
    let mut iter = line.splitn(3, |c: char| c.is_ascii_whitespace());
    let (typ, ident, comment) = match (iter.next(), iter.next(), iter.next()) {
        (Some(a), Some(b), Some(c)) => (a, b, c),
        _ => exit_with_msg!(format!(
            "line could not be parsed as type/name/comment: '{}'",
            line
        )),
    };
    let typ = normalize_type(typ);
    let (name, maybe_count) = split_ident(ident);
    let name = decamalize(name);
    let maybe_count = maybe_count.map(decamalize);
    Some(Field {
        name,
        maybe_count,
        typ,
        comment,
    })
}

/// takes an ident and splits it into the name and an optional count (if the item
/// is an array)
fn split_ident(input: &str) -> (&str, Option<&str>) {
    match input.split_once('[') {
        Some((front, back)) => (front, Some(back.trim_end_matches(']'))),
        None => (input, None),
    }
}

fn normalize_type(input: &str) -> &str {
    match input {
        "uint8" => "Uint8",
        "uint16" => "Uint16",
        "uint24" => "Uint24",
        "uint32" => "Uint32",
        "int8" => "Int8",
        "int16" => "Int16",
        "int32" => "Int32",
        "FWORD" => "FWord",
        "UFWORD" => "UfWord",
        "F2DOT14" => "F2Dot14",
        "LONGDATETIME" => "LongDateTime",
        other => other,
    }
}

fn decamalize(input: &str) -> String {
    //taken from serde: https://github.com/serde-rs/serde/blob/7e19ae8c9486a3bbbe51f1befb05edee94c454f9/serde_derive/src/internals/case.rs#L69-L76
    let mut snake = String::new();
    for (i, ch) in input.char_indices() {
        if i > 0 && ch.is_uppercase() {
            snake.push('_');
        }
        snake.push(ch.to_ascii_lowercase());
    }
    snake
}

fn format_comment(
    f: &mut std::fmt::Formatter<'_>,
    whitespace: &str,
    input: &str,
) -> std::fmt::Result {
    const LINE_LEN: usize = 72;

    let mut cur_len = 0;

    for token in input.split_inclusive(' ') {
        if cur_len == 0 || cur_len + token.len() > LINE_LEN {
            if cur_len > 0 {
                writeln!(f)?;
            }
            write!(f, "{}/// ", whitespace)?;
            cur_len = whitespace.len() + 4;
        }
        write!(f, "{}", token)?;
        cur_len += token.len();
    }
    if cur_len > 0 {
        writeln!(f)?;
    }
    Ok(())
}
<commit_msg>Update codegen tool<commit_after>//! Helper to crudely rewrite types from the spec's format to our own.
//!
//! This reads a file containing table and record descriptions (from the spec)
//! and converts them to the form that we use, writing the result to stdout.
//!
//! Input should be in the format:
//!
//!
//! ```
//! { // this is a 'group'
//! @Gpos1_0
//! uint16      majorVersion       Major version of the GPOS table, = 1
//! uint16      minorVersion       Minor version of the GPOS table, = 0
//! Offset16    scriptListOffset   Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset  Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset   Offset to LookupList table, from beginning of GPOS table
//!
//! @Gpos1_1
//! uint16      majorVersion            Major version of the GPOS table, = 1
//! uint16      minorVersion            Minor version of the GPOS table, = 1
//! Offset16    scriptListOffset        Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset       Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset        Offset to LookupList table, from beginning of GPOS table
//! Offset32    featureVariationsOffset Offset to FeatureVariations table, from beginning of GPOS table (may be NULL)
//! }
//! ```
//!
//! - different records/tables are separated by newlines.
//! - the first line should be a single word, used as the name of the type
//! - other lines are just copy pasted
//!
//! *limitations:* this doesn't handle lifetimes, and doesn't generate annotations.
//! You will need to clean up the output.

use std::{fmt::Write, ops::Deref};

macro_rules! exit_with_msg {
    ($disp:expr, $line:expr) => {{
        eprintln!("ERROR: {}", $disp);
        eprintln!("Line {}: '{}'", 1 + $line.number, $line.text);
        std::process::exit(1);
    }};
}

static MACRO_CALL: &str = "font_types::tables!";

/// a wrapper around a line, so we can report errors with line numbers
struct Line<'a> {
    text: &'a str,
    number: usize,
}

impl Deref for Line<'_> {
    type Target = str;
    fn deref(&self) -> &<Self as Deref>::Target {
        self.text
    }
}

fn main() {
    let in_path = std::env::args().nth(1).expect("expected path argument");
    let input = std::fs::read_to_string(in_path).expect("failed to read path");
    let mut lines = input
        .lines()
        .enumerate()
        .map(|(number, text)| Line {
            text: text.trim(),
            number,
        })
        .filter(|l| !l.starts_with('#'));

    while let Some(group) = generate_group(&mut lines) {
        println!("{} {{", MACRO_CALL);
        println!("{}", group);
        println!("}}");
    }
}

/// Generate a group of items. This is multiple items within a pair of brackets,
/// which will share a single macro invocation.
fn generate_group<'a>(lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let mut lines = lines.skip_while(|s| s.is_empty()).peekable();
    let brace = lines.next()?;

    let mut result = String::new();

    if !brace.starts_with('{') {
        exit_with_msg!("expected opening brace", brace);
    }

    let mut lines = lines.take_while(|line| !line.starts_with('}'));

    while let Some(item) = generate_one_item(&mut lines) {
        if !result.is_empty() {
            result.push('\n');
        }
        result.push_str(&item);
    }
    Some(result)
}

/// parse a single table or record.
///
/// Returns `Some` on success, `None` if there are no more items, and terminates
/// if something goes wrong.
fn generate_one_item<'a>(lines: impl Iterator<Item = Line<'a>>) -> Option<String> {
    let mut lines = lines.skip_while(|line| line.is_empty());

    let decl_line = match lines.next() {
        Some(line) if line.starts_with('@') => line,
        Some(line) => exit_with_msg!("expected table or record name", line),
        None => return None,
    };

    let name = decl_line.trim_matches('@');
    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let lifetime_str = if fields.iter().any(|x| x.maybe_count.is_some()) {
        "<'a>"
    } else {
        ""
    };
    let mut result = format!("{}{} {{\n", name, lifetime_str);
    for line in &fields {
        writeln!(&mut result, "{}", line).unwrap();
    }
    result.push('}');
    Some(result)
}

struct Field<'a> {
    name: String,
    maybe_count: Option<String>,
    typ: &'a str,
    comment: &'a str,
}

impl<'a> std::fmt::Display for Field<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        format_comment(f, "    ", self.comment)?;
        if self.name.contains("reserved") {
            writeln!(f, "    #[hidden]")?;
        }
        if let Some(count) = &self.maybe_count {
            writeln!(f, "    #[count({})]", count)?;
            write!(f, "    {}: [{}],", self.name, self.typ)?;
        } else {
            write!(f, "    {}: {},", self.name, self.typ)?;
        }
        Ok(())
    }
}

fn parse_field(line: Line) -> Option<Field> {
    if line.is_empty() {
        return None;
    }
    let mut iter = line.text.splitn(3, |c: char| c.is_ascii_whitespace());
    let (typ, ident, comment) = match (iter.next(), iter.next(), iter.next()) {
        (Some(a), Some(b), Some(c)) => (a, b, c),
        _ => exit_with_msg!("line could not be parsed as type/name/comment", line),
    };
    let typ = normalize_type(typ);
    let (name, maybe_count) = split_ident(ident);
    let name = decamalize(name);
    let maybe_count = maybe_count.map(decamalize);
    Some(Field {
        name,
        maybe_count,
        typ,
        comment,
    })
}

/// takes an ident and splits it into the name and an optional count (if the item
/// is an array)
fn split_ident(input: &str) -> (&str, Option<&str>) {
    match input.split_once('[') {
        Some((front, back)) => (front, Some(back.trim_end_matches(']'))),
        None => (input, None),
    }
}

fn normalize_type(input: &str) -> &str {
    match input {
        "uint8" => "BigEndian<u8>",
        "uint16" => "BigEndian<u16>",
        "uint24" => "BigEndian<Uint24>",
        "uint32" => "BigEndian<u32>",
        "int8" => "BigEndian<i8>",
        "int16" => "BigEndian<i16>",
        "int32" => "BigEndian<i32>",
        "FWORD" => "BigEndian<FWord>",
        "UFWORD" => "BigEndian<UfWord>",
        "F2DOT14" => "BigEndian<F2Dot14>",
        "LONGDATETIME" => "BigEndian<LongDateTime>",
        "Version16Dot16" => "BigEndian<Version16Dot16>",
        "Fixed" => "BigEndian<Fixed>",
        "Tag" => "BigEndian<Tag>",
        "Offset16" => "BigEndian<Offset16>",
        "Offset24" => "BigEndian<Offset24>",
        "Offset32" => "BigEndian<Offset32>",
        other => other,
    }
}

fn decamalize(input: &str) -> String {
    //taken from serde: https://github.com/serde-rs/serde/blob/7e19ae8c9486a3bbbe51f1befb05edee94c454f9/serde_derive/src/internals/case.rs#L69-L76
    let mut snake = String::new();
    for (i, ch) in input.char_indices() {
        if i > 0 && ch.is_uppercase() {
            snake.push('_');
        }
        snake.push(ch.to_ascii_lowercase());
    }
    snake
}

fn format_comment(
    f: &mut std::fmt::Formatter<'_>,
    whitespace: &str,
    input: &str,
) -> std::fmt::Result {
    const LINE_LEN: usize = 72;

    let mut cur_len = 0;

    for token in input.split_inclusive(' ') {
        if cur_len == 0 || cur_len + token.len() > LINE_LEN {
            if cur_len > 0 {
                writeln!(f)?;
            }
            write!(f, "{}/// ", whitespace)?;
            cur_len = whitespace.len() + 4;
        }
        write!(f, "{}", token)?;
        cur_len += token.len();
    }
    if cur_len > 0 {
        writeln!(f)?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::env;
use std::time::{Duration, Instant};

use futures::StreamExt;
use telegram_bot::*;
use tokio::timer::delay;

async fn test(api: Api, message: Message) -> Result<(), Error> {
    let when = Instant::now() + Duration::from_secs(2);

    let mut reply = message.location_reply(0.0, 0.0);
    api.send(reply.live_period(60)).await?;
    delay(when).await;

    api.send(message.edit_live_location(10.0, 10.0)).await?;
    delay(when).await;

    api.send(message.edit_live_location(20.0, 20.0)).await?;
    delay(when).await;

    api.send(message.edit_live_location(30.0, 30.0)).await?;
    delay(when).await;

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let token = env::var("TELEGRAM_BOT_TOKEN").expect("TELEGRAM_BOT_TOKEN not set");

    let api = Api::new(token);
    let mut stream = api.stream();

    while let Some(update) = stream.next().await {
        let update = update?;
        if let UpdateKind::Message(message) = update.kind {
            if let MessageKind::Text { ref data, .. } = message.kind {
                match data.as_str() {
                    "/livelocation" => test(api.clone(), message.clone()).await?,
                    _ => (),
                }
            }
        }
    }
    Ok(())
}
<commit_msg>docs: fix live_location example<commit_after>use std::env;
use std::time::Duration;

use futures::StreamExt;
use telegram_bot::*;
use tokio::timer::delay_for;

const DELAY_DURATION: Duration = Duration::from_secs(2);

async fn test(api: Api, message: Message) -> Result<(), Error> {
    let reply = api
        .send(message.location_reply(0.0, 0.0).live_period(60))
        .await?;

    delay_for(DELAY_DURATION).await;
    api.send(reply.edit_live_location(10.0, 10.0)).await?;

    delay_for(DELAY_DURATION).await;
    api.send(reply.edit_live_location(20.0, 20.0)).await?;

    delay_for(DELAY_DURATION).await;
    api.send(reply.edit_live_location(30.0, 30.0)).await?;

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let token = env::var("TELEGRAM_BOT_TOKEN").expect("TELEGRAM_BOT_TOKEN not set");

    let api = Api::new(token);
    let mut stream = api.stream();

    while let Some(update) = stream.next().await {
        let update = update?;
        if let UpdateKind::Message(message) = update.kind {
            if let MessageKind::Text { ref data, .. } = message.kind {
                match data.as_str() {
                    "/livelocation" => test(api.clone(), message.clone()).await?,
                    _ => (),
                }
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

// compile-flags: -O -C no-prepopulate-passes

#![crate_type = "lib"]
#![feature(rustc_attrs)]

// CHECK-LABEL: @test
#[no_mangle]
#[rustc_mir] // FIXME #27840 MIR has different codegen.
pub fn test() {
    let a = 0;
    &a; // keep variable in an alloca

// CHECK: [[S_a:%[0-9]+]] = bitcast i32* %a to i8*
// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_a]])

    {
        let b = &Some(a);
        &b; // keep variable in an alloca

// CHECK: [[S_b:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"** %b to i8*
// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_b]])

// CHECK: [[S__5:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"* %_5 to i8*
// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]])

// CHECK: [[E__5:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"* %_5 to i8*
// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]])

// CHECK: [[E_b:%[0-9]+]] = bitcast %"2.std::option::Option<i32>"** %b to i8*
// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]])
    }

    let c = 1;
    &c; // keep variable in an alloca

// CHECK: [[S_c:%[0-9]+]] = bitcast i32* %c to i8*
// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_c]])

// CHECK: [[E_c:%[0-9]+]] = bitcast i32* %c to i8*
// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_c]])

// CHECK: [[E_a:%[0-9]+]] = bitcast i32* %a to i8*
// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_a]])
}
<commit_msg>Fix codegen test after change of llvm type naming scheme<commit_after>// Copyright 2016 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.

// compile-flags: -O -C no-prepopulate-passes

#![crate_type = "lib"]
#![feature(rustc_attrs)]

// CHECK-LABEL: @test
#[no_mangle]
#[rustc_mir] // FIXME #27840 MIR has different codegen.
pub fn test() {
    let a = 0;
    &a; // keep variable in an alloca

// CHECK: [[S_a:%[0-9]+]] = bitcast i32* %a to i8*
// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_a]])

    {
        let b = &Some(a);
        &b; // keep variable in an alloca

// CHECK: [[S_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8*
// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_b]])

// CHECK: [[S__5:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_5 to i8*
// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]])

// CHECK: [[E__5:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_5 to i8*
// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]])

// CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8*
// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]])
    }

    let c = 1;
    &c; // keep variable in an alloca

// CHECK: [[S_c:%[0-9]+]] = bitcast i32* %c to i8*
// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_c]])

// CHECK: [[E_c:%[0-9]+]] = bitcast i32* %c to i8*
// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_c]])

// CHECK: [[E_a:%[0-9]+]] = bitcast i32* %a to i8*
// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_a]])
}
<|endoftext|>