<commit_before>///
///
///

use alloc::heap;
use std::marker::PhantomData;
use std::mem;
use std::slice;

use common::constant::VECTOR_SIZE;
use common::err::*;
use exec::Executor;
use io::stream::*;
use schema::Schema;
use rows::RowBlock;
use types::*;
use util::str::StrSlice;

const BUF_SIZE: usize = 65536;

pub struct DelimTextScanner<'a> {
  data_schema : Schema,
  read_fields : Option<Schema>,
  line_delim  : u8,
  field_delim : u8,
  reader      : Box<StreamReader>,
  marker      : PhantomData<&'a ()>,

  // variable
  readbuf_ptr: *mut u8,
  should_parse_line: bool, // parse lines from read buffer
  read_line_num: usize,    // number of read lines for each next
  line_slices_ptr: *mut StrSlice,
  line_slices: &'a mut [StrSlice],
  fields_slices_ptr: *mut StrSlice,
  fields_slices: &'a mut [StrSlice],
  last_read_len: usize,

}

impl<'a> DelimTextScanner<'a> {
  pub fn new(
        data_schema: Schema,
        read_fields: Option<Schema>,
        stream: Box<StreamReader>,
        field_delim: u8) -> DelimTextScanner<'a> {

    let mut line_slices_ptr = unsafe {
      heap::allocate(mem::size_of::<StrSlice>() * 1024, mem::min_align_of::<StrSlice>())
    } as *mut StrSlice;

    let mut line_slices: &mut [StrSlice] = unsafe {
      slice::from_raw_parts_mut(line_slices_ptr as *mut StrSlice, 1024)
    };

    let mut fields_slices_ptr = unsafe {
      heap::allocate(
        mem::size_of::<StrSlice>() * data_schema.size(),
        mem::min_align_of::<StrSlice>()
      )
    } as *mut StrSlice;

    let mut fields_slices: &mut [StrSlice] = unsafe {
      slice::from_raw_parts_mut(fields_slices_ptr as *mut StrSlice, data_schema.size())
    };

    DelimTextScanner {
      data_schema: data_schema,
      read_fields: read_fields,

      line_delim: '\n' as u8,
      field_delim: field_delim,

      reader: stream,
      marker: PhantomData,

      readbuf_ptr: unsafe { heap::allocate(BUF_SIZE, 16) },
      should_parse_line: true,
      read_line_num: 0,
      line_slices_ptr: line_slices_ptr,
      line_slices: line_slices,
      fields_slices_ptr: fields_slices_ptr,
      fields_slices: fields_slices,
      last_read_len: 0
    }
  }

  fn read_line_num(&self) -> usize {
    self.read_line_num
  }

  fn line_slices(&self) -> &[StrSlice] {
    self.line_slices
  }

  fn find_first_record_index(&self, bytes: &[u8]) -> Option<usize> {
    //let bytes : &[u8] = unsafe { mem::transmute(text) };

    let mut pos : usize = 0;
    let mut found : bool = false;

    for c in bytes {
      if self.line_delim == *c {
        found = true;
        break;
      }

      pos = pos + 1;
    }

    match found {
      true => Some(pos + 1),
      false => None
    }
  }

  /// Return the last index of fields, which will be used for the following call.
  /// It will return a tuple consisting of found line number and last delim index.
  fn read_line_batch(&mut self) -> usize {

    self.read_line_num      = 0; // read line counter
    let mut last_pos: usize = 0; // keep the start offset
    let mut cur_pos : usize = 0; // the current offset

    while (cur_pos < BUF_SIZE && self.read_line_num < VECTOR_SIZE) {
      // for each character
      let c: u8  = unsafe { *self.readbuf_ptr.offset(cur_pos as isize) };

      // check if the character is line delimiter
      if c == self.line_delim {

        // if found, set each StrSlice with the start offset and the current position
        self.line_slices[self.read_line_num].set_ptr(unsafe {self.readbuf_ptr.offset(last_pos as isize)});
        self.line_slices[self.read_line_num].set_len((cur_pos - last_pos) as i32);

        last_pos = cur_pos + 1; // to skip the delimiter character
        self.read_line_num = self.read_line_num + 1; // increase the line number
      }

      cur_pos = cur_pos + 1;
    }

    (last_pos - 1)
  }

  #[inline]
  fn parse_fields(&mut self, line_idx: usize) {
    let mut last_pos: usize = 0; // keep the start offset
    let mut cur_pos : usize = 0; // the current offset
    let mut field_idx: usize = 0;

    let slice = self.line_slices[line_idx];
    let line_len = slice.len() as usize;

    while (cur_pos < line_len && field_idx < self.data_schema.size()) {
      let c: u8 = unsafe { *slice.as_ptr().offset(cur_pos as isize) };

      // check if the character is line delimiter
      if c == self.field_delim {
        self.fields_slices[field_idx].set_ptr(unsafe {slice.as_ptr().offset(last_pos as isize)});
        self.fields_slices[field_idx].set_len((cur_pos - last_pos) as i32);

        last_pos = cur_pos + 1;
        field_idx = field_idx + 1;
      }

      cur_pos = cur_pos + 1;
    }
  }

  fn fill_vector() {

  }
}

impl<'a> Executor for DelimTextScanner<'a> {

  fn init(&mut self) -> Void {
    self.reader.read(
      unsafe {slice::from_raw_parts_mut(self.readbuf_ptr, BUF_SIZE)}
    );

    void_ok()
  }

  fn next(&mut self, rowblock: &mut RowBlock) -> Void {

    let mut row_idx: usize = 0;
    let mut r: usize;
    loop {

      if self.should_parse_line {
        r = self.read_line_batch();
      }

      // self.reader.read(
      //   unsafe {slice::from_raw_parts_mut(self.readbuf_ptr, BUF_SIZE)}
      // );
    }

    void_ok()
  }

  fn close(&mut self) -> Void {
    void_ok()
  }

  fn in_schema(&self) -> &Schema {
    &self.data_schema
  }

  fn out_schema(&self) -> &Schema {
    match self.read_fields {
      Some(ref s) => s,
      None => &self.data_schema
    }
  }
}

#[test]
fn test_find_first_record_index() {
  let mut s = Schema::new();
  s.add_column("c1", *TEXT_TY);
  s.add_column("c2", *TEXT_TY);

  let fin = Box::new(FileInputStream::new("/home/hyunsik/tpch/lineitem/lineitem.tbl".to_string()));
  let s = DelimTextScanner::new(s, None, fin, '\n' as u8);

  assert_eq!(4, s.find_first_record_index("abc\nbb".as_bytes()).unwrap());
  assert_eq!(1, s.find_first_record_index("\nabc\nbb".as_bytes()).unwrap());
  assert_eq!(2, s.find_first_record_index("\r\nabc\nbb".as_bytes()).unwrap());
  assert!(s.find_first_record_index("aaaaabcabbb".as_bytes()).is_none());

}

#[test]
fn test_str_array() {
  let a: [&str;1024];

  //let mut slices: Vec<&str> = Vec::with_capacity(12);
  //unsafe { slices.set_len(12) };
  //slices.get_unchecked_mut(x)
  //slices[1] = "abc";

  let mut ptr: *mut &str = unsafe {
    heap::allocate(
      mem::size_of::<&str>() * 1024,
      mem::min_align_of::<&str>()
    ) as *mut &str
  };

  let mut slices: &mut [&str] = unsafe {
    slice::from_raw_parts_mut(ptr as *mut &str, 1024)
  };

  slices[0] = "abc";

  //slices[0] = "abc";
}

#[test]
fn test_read_line_batch() {
  let mut schema = Schema::new();
  schema.add_column("c1", *TEXT_TY);
  schema.add_column("c2", *TEXT_TY);

  let mut fin = Box::new(FileInputStream::new("/Users/hyunsik/tpch/lineitem/lineitem.tbl".to_string()));
  assert!(fin.open().is_ok());
  let mut s = DelimTextScanner::new(schema, None, fin, '\n' as u8);
  assert!(s.init().is_ok());
  let res = s.read_line_batch();
}
  // let mut delim_indexes:Vec<usize> = Vec::new();
  // let r1 =
  //   s.next_line_indexes("abc\nbb\nabcdef\nabcd".as_ptr(), &mut delim_indexes);
  // assert_eq!(3, r1.0);
  // assert_eq!(13, r1.1);

//   delim_indexes.clear();

//   let r2 =
//     s.next_line_indexes("a\nb\nabcde\n".as_ptr(), &mut delim_indexes);
//   assert_eq!(3, r2.0);
//   assert_eq!(9, r2.1);
// }<commit_msg>Implement DelimTextScanner::refill_readbuf.<commit_after>///
///
///

use alloc::heap;
use std::marker::PhantomData;
use std::mem;
use std::ptr::copy_nonoverlapping;
use std::slice;

use common::constant::VECTOR_SIZE;
use common::err::*;
use exec::Executor;
use io::stream::*;
use schema::Schema;
use rows::RowBlock;
use types::*;
use util::str::{StrSlice,split_str_slice};

const BUF_SIZE: usize = 65536;

pub struct DelimTextScanner<'a> {
  data_schema : Schema,
  read_fields : Option<Schema>,
  line_delim  : u8,
  field_delim : u8,
  reader      : Box<StreamReader>,
  marker      : PhantomData<&'a ()>,

  // variable
  readbuf_ptr: *mut u8,
  should_parse_line: bool, // parse lines from read buffer
  read_line_num: usize,    // number of read lines for each next
  line_slices_ptr: *mut StrSlice,
  line_slices: &'a mut [StrSlice],
  fields_slices_ptr: *mut StrSlice,
  fields_slices: &'a mut [StrSlice],
  parsed_batch_len: usize,
  read_len: usize,
}

impl<'a> DelimTextScanner<'a> {
  pub fn new(
        data_schema: Schema,
        read_fields: Option<Schema>,
        stream: Box<StreamReader>,
        field_delim: u8) -> DelimTextScanner<'a> {

    let mut line_slices_ptr = unsafe {
      heap::allocate(mem::size_of::<StrSlice>() * 1024, mem::min_align_of::<StrSlice>())
    } as *mut StrSlice;

    let mut line_slices: &mut [StrSlice] = unsafe {
      slice::from_raw_parts_mut(line_slices_ptr as *mut StrSlice, 1024)
    };

    let mut fields_slices_ptr = unsafe {
      heap::allocate(
        mem::size_of::<StrSlice>() * data_schema.size(),
        mem::min_align_of::<StrSlice>()
      )
    } as *mut StrSlice;

    let mut fields_slices: &mut [StrSlice] = unsafe {
      slice::from_raw_parts_mut(fields_slices_ptr as *mut StrSlice, data_schema.size())
    };

    DelimTextScanner {
      data_schema: data_schema,
      read_fields: read_fields,

      line_delim: '\n' as u8,
      field_delim: field_delim,

      reader: stream,
      marker: PhantomData,

      readbuf_ptr: unsafe { heap::allocate(BUF_SIZE, 16) },
      should_parse_line: true,
      read_line_num: 0,
      line_slices_ptr: line_slices_ptr,
      line_slices: line_slices,
      fields_slices_ptr: fields_slices_ptr,
      fields_slices: fields_slices,
      parsed_batch_len: 0,
      read_len: 0
    }
  }

  fn read_line_num(&self) -> usize {
    self.read_line_num
  }

  fn line_slices(&self) -> &[StrSlice] {
    self.line_slices
  }

  fn find_first_record_index(&self, bytes: &[u8]) -> Option<usize> {
    //let bytes : &[u8] = unsafe { mem::transmute(text) };

    let mut pos : usize = 0;
    let mut found : bool = false;

    for c in bytes {
      if self.line_delim == *c {
        found = true;
        break;
      }

      pos = pos + 1;
    }

    match found {
      true => Some(pos + 1),
      false => None
    }
  }

  /// Return the last index of fields, which will be used for the following call.
  /// It will return a tuple consisting of found line number and last delim index.
  fn read_line_batch(&mut self) {

    self.read_line_num      = 0; // read line counter
    let mut last_pos: usize = 0; // keep the start offset
    let mut cur_pos : usize = 0; // the current offset

    while (cur_pos < BUF_SIZE && self.read_line_num < VECTOR_SIZE) {
      // for each character
      let c: u8  = unsafe { *self.readbuf_ptr.offset(cur_pos as isize) };

      // check if the character is line delimiter
      if c == self.line_delim {

        // if found, set each StrSlice with the start offset and the current position
        self.line_slices[self.read_line_num].set_ptr(unsafe {self.readbuf_ptr.offset(last_pos as isize)});
        self.line_slices[self.read_line_num].set_len((cur_pos - last_pos) as i32);

        last_pos = cur_pos + 1; // to skip the delimiter character
        self.read_line_num = self.read_line_num + 1; // increase the line number
      }

      cur_pos = cur_pos + 1;
    }

    self.parsed_batch_len = last_pos
  }

  fn fill_vector(&mut self, row_idx: usize, split_num: usize) {
  }

  fn refill_readbuf(&mut self) -> Void {

    let remain_len = self.read_len - self.parsed_batch_len;
    debug_assert!(remain_len >= 0, "remain length must be positive number.");

    // move the remain bytes into the head of the readbuf
    unsafe {
      copy_nonoverlapping(
        self.readbuf_ptr.offset(self.parsed_batch_len as isize),
        self.readbuf_ptr,
        remain_len);
    }

    // refill the readbuf
    self.read_len = try!(
      self.reader.read(
        unsafe {
          slice::from_raw_parts_mut(
            self.readbuf_ptr.offset(remain_len as isize),
            BUF_SIZE - remain_len
          )
        },
      )
    );

    self.read_len = self.read_len + remain_len;

    void_ok()
  }
}

impl<'a> Executor for DelimTextScanner<'a> {

  fn init(&mut self) -> Void {
    self.read_len = try!(self.reader.read(
      unsafe {slice::from_raw_parts_mut(self.readbuf_ptr, BUF_SIZE)}
    ));

    void_ok()
  }

  fn next(&mut self, rowblock: &mut RowBlock) -> Void {

    let mut row_num: usize = 0;
    let mut field_parse_res: (usize, usize);
    loop {

      // parse lines in batch
      if self.should_parse_line {
        self.read_line_batch();
        self.should_parse_line = false;
      }

      unsafe {
      for line_idx in 0..self.read_line_num {
          // parse each line slice into field slices
          field_parse_res = split_str_slice(
            &mut self.line_slices[line_idx],
            self.fields_slices,
            self.field_delim
          );

          self.fill_vector(row_num, field_parse_res.1);
          row_num = row_num + 1;
        }
      }

      if row_num < VECTOR_SIZE {
        // compact and fill read buffer
        self.refill_readbuf();
        self.should_parse_line = true;
      }
    } // outmost loop

    void_ok()
  }

  fn close(&mut self) -> Void {
    void_ok()
  }

  fn in_schema(&self) -> &Schema {
    &self.data_schema
  }

  fn out_schema(&self) -> &Schema {
    match self.read_fields {
      Some(ref s) => s,
      None => &self.data_schema
    }
  }
}

#[test]
fn test_find_first_record_index() {
  let mut s = Schema::new();
  s.add_column("c1", *TEXT_TY);
  s.add_column("c2", *TEXT_TY);

  let fin = Box::new(FileInputStream::new("/home/hyunsik/tpch/lineitem/lineitem.tbl".to_string()));
  let s = DelimTextScanner::new(s, None, fin, '\n' as u8);

  assert_eq!(4, s.find_first_record_index("abc\nbb".as_bytes()).unwrap());
  assert_eq!(1, s.find_first_record_index("\nabc\nbb".as_bytes()).unwrap());
  assert_eq!(2, s.find_first_record_index("\r\nabc\nbb".as_bytes()).unwrap());
  assert!(s.find_first_record_index("aaaaabcabbb".as_bytes()).is_none());

}

#[test]
fn test_str_array() {
  let a: [&str;1024];

  //let mut slices: Vec<&str> = Vec::with_capacity(12);
  //unsafe { slices.set_len(12) };
  //slices.get_unchecked_mut(x)
  //slices[1] = "abc";

  let mut ptr: *mut &str = unsafe {
    heap::allocate(
      mem::size_of::<&str>() * 1024,
      mem::min_align_of::<&str>()
    ) as *mut &str
  };

  let mut slices: &mut [&str] = unsafe {
    slice::from_raw_parts_mut(ptr as *mut &str, 1024)
  };

  slices[0] = "abc";

  //slices[0] = "abc";
}

#[test]
fn test_read_line_batch() {
  let mut schema = Schema::new();
  schema.add_column("c1", *TEXT_TY);
  schema.add_column("c2", *TEXT_TY);

  let mut fin = Box::new(FileInputStream::new("/Users/hyunsik/tpch/lineitem/lineitem.tbl".to_string()));
  assert!(fin.open().is_ok());
  let mut s = DelimTextScanner::new(schema, None, fin, '\n' as u8);
  assert!(s.init().is_ok());
  let res = s.read_line_batch();
}
  // let mut delim_indexes:Vec<usize> = Vec::new();
  // let r1 =
  //   s.next_line_indexes("abc\nbb\nabcdef\nabcd".as_ptr(), &mut delim_indexes);
  // assert_eq!(3, r1.0);
  // assert_eq!(13, r1.1);

//   delim_indexes.clear();

//   let r2 =
//     s.next_line_indexes("a\nb\nabcde\n".as_ptr(), &mut delim_indexes);
//   assert_eq!(3, r2.0);
//   assert_eq!(9, r2.1);
// }<|endoftext|>


<commit_before>use std::f32;

use automation::Automation;
use partial::Partial;
use phaser::PhaserCoeff;
use real::Real32;
use render::render_spec::{RenderSpec, RenderSpecFactory};
use render::reference::tree_renderer::TreeRenderer;
use tree::node::{ANode, YNode};
use tree::send::Send;
use tree::tree::Tree;

use super::approx_equal::assert_similar_audio;

/// Gate a 440 Hz wave by u(t)
/// u(t) is approximated via the fourier series of a square wave.
pub fn get_gate(render_spec: RenderSpec, n_samples : u32) -> Vec<f32> {
    let mut tree = TreeRenderer::new(render_spec);
    let exit_node = YNode::new_rc();
    tree.watch_nodes(&vec![exit_node.clone()]);

    // The tree looks like:
    // enter_ynode enter_gate_node
    //         \       /
    //         exit_node

    // create nodes for broadcasting the partials & automations
    let enter_ynode = YNode::new_rc();
    tree.add_send(
        Send::new_yysend(enter_ynode.clone(), exit_node.clone())
    );
    let enter_gate_anode = ANode::new_rc();
    tree.add_send(
        Send::new_aysend(enter_gate_anode.clone(), exit_node.clone())
    );

    // inject the automations
    // Note: for volume gating, we only use the c2 exp(i*wt*t) portion of the
    // automations
    // Note: first, add the 0.5 DC offset:
    tree.add_send(
        Send::new_asrcsend(
            Automation::new(PhaserCoeff::new_f32(0.5, 0.0), Real32::new(0.0), Real32::new(0.0)),
            enter_gate_anode.clone()
        )
    );
    for i in (1..400) {
        let harmonic = (2*i - 1) as f32;
        let amp = 0.25*4.0/f32::consts::PI/harmonic;
        let freq = 100.0*2.0*f32::consts::PI * harmonic;
        tree.add_send(
            Send::new_asrcsend(
                Automation::new(PhaserCoeff::new_f32(0.0, -amp), Real32::new(freq), Real32::new(0.0)),
                enter_gate_anode.clone()
            )
        );
        tree.add_send(
            Send::new_asrcsend(
                Automation::new(PhaserCoeff::new_f32(0.0, amp), Real32::new(-freq), Real32::new(0.0)),
                enter_gate_anode.clone()
            )
        );
    }

    // inject a 440Hz sine wave
    tree.add_send(
        Send::new_ysrcsend(
            Partial::new(PhaserCoeff::new_f32(0.0, -1.0), Real32::new(440.0*2.0*f32::consts::PI)),
            enter_ynode.clone()
        )
    );

    let mut samples = vec![];
    for _ in (0..n_samples) {
        samples.push(tree.step()[0]);
    }
    samples
}

#[test]
pub fn test_gate() {
    let render_spec = RenderSpecFactory::new().sample_rate(44100).finalize();
    let n_samples = 100;
    let actual = get_gate(render_spec, n_samples);
    let mut reference = vec![];

    let w_440 = 440.0*2.0*f32::consts::PI;

    for i in (0..n_samples) {
        let t = (i as f32) / 44100.0;
        reference.push((w_440*t).sin());
    }

    assert_similar_audio(&reference, &actual);
}

<commit_msg>test_gate function now actually gates the signal on AND off<commit_after>use std::f32;

use automation::Automation;
use partial::Partial;
use phaser::PhaserCoeff;
use real::Real32;
use render::render_spec::{RenderSpec, RenderSpecFactory};
use render::reference::tree_renderer::TreeRenderer;
use tree::node::{ANode, YNode};
use tree::send::Send;
use tree::tree::Tree;

use super::approx_equal::assert_similar_audio;

/// sinc math function: sin(pi x)/(pi x)
/// Often used in Sigma Approximation for Fourier series to make them converge
/// more rapidly.
fn sinc(x: f32) -> f32 {
    let pix = x * f32::consts::PI;
    pix.sin() / pix
}

/// Gate a 440 Hz wave by (u(t) - u(t-0.005))
/// u(t) is approximated via the fourier series of a square wave.
/// This version repeats every 0.010 sec. In actual usage, we would likely
/// require a longer duration (e.g. up to 1000 sec).
pub fn get_gate(render_spec: RenderSpec, n_samples : u32) -> Vec<f32> {
    let mut tree = TreeRenderer::new(render_spec);
    let exit_node = YNode::new_rc();
    tree.watch_nodes(&vec![exit_node.clone()]);

    // The tree looks like:
    // enter_ynode enter_gate_node
    //         \       /
    //         exit_node

    // create nodes for broadcasting the partials & automations
    let enter_ynode = YNode::new_rc();
    tree.add_send(
        Send::new_yysend(enter_ynode.clone(), exit_node.clone())
    );
    let enter_gate_anode = ANode::new_rc();
    tree.add_send(
        Send::new_aysend(enter_gate_anode.clone(), exit_node.clone())
    );

    // inject the automations
    // Note: for volume gating, we only use the c2 exp(i*wt*t) portion of the
    // automations
    // Note: first, add the 0.5 DC offset:
    tree.add_send(
        Send::new_asrcsend(
            Automation::new(PhaserCoeff::new_f32(0.5, 0.0), Real32::new(0.0), Real32::new(0.0)),
            enter_gate_anode.clone()
        )
    );
    for i in (1..401) {
        let harmonic = (2*i - 1) as f32;
        let amp = 0.25*sinc(harmonic/401.0)*4.0/f32::consts::PI/harmonic;
        let freq = 220.0*2.0*f32::consts::PI * harmonic;
        tree.add_send(
            Send::new_asrcsend(
                Automation::new(PhaserCoeff::new_f32(0.0, -amp), Real32::new(freq), Real32::new(0.0)),
                enter_gate_anode.clone()
            )
        );
        tree.add_send(
            Send::new_asrcsend(
                Automation::new(PhaserCoeff::new_f32(0.0, amp), Real32::new(-freq), Real32::new(0.0)),
                enter_gate_anode.clone()
            )
        );
    }

    // inject a 440Hz sine wave
    tree.add_send(
        Send::new_ysrcsend(
            Partial::new(PhaserCoeff::new_f32(0.0, -1.0), Real32::new(440.0*2.0*f32::consts::PI)),
            enter_ynode.clone()
        )
    );

    let mut samples = vec![];
    for _ in (0..n_samples) {
        samples.push(tree.step()[0]);
    }
    samples
}

#[test]
pub fn test_gate() {
    let render_spec = RenderSpecFactory::new().sample_rate(44100).finalize();
    let n_samples = 200;
    let actual = get_gate(render_spec, n_samples);
    let mut reference = vec![];

    let w_440 = 440.0*2.0*f32::consts::PI;

    for i in (0..n_samples) {
        let t = (i as f32) / 44100.0;
        reference.push(
            if t <= 0.5/220.0 {
                (w_440*t).sin()
            } else {
                0.0
            }
        );
    }

    assert_similar_audio(&reference, &actual);
}

<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::str::FromStr;

use filters::filter::Filter;

use libimagerror::trace::trace_error;
use libimagerror::trace::MapErrTrace;
use libimagerror::iter::TraceIterator;
use libimagstore::store::FileLockEntry;
use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagtimetrack::timetracking::TimeTracking;

use libimagrt::runtime::Runtime;

pub fn list(rt: &Runtime) -> i32 {
    let (_, cmd) = rt.cli().subcommand();
    let cmd = cmd.unwrap(); // checked in main()

    let start = match cmd.value_of("start-time").map(::chrono::naive::NaiveDateTime::from_str) {
        None         => None,
        Some(Ok(dt)) => Some(dt),
        Some(Err(e)) => {
            trace_error(&e);
            None
        }
    };
    let end = match cmd.value_of("end-time").map(::chrono::naive::NaiveDateTime::from_str) {
        None         => None,
        Some(Ok(dt)) => Some(dt),
        Some(Err(e)) => {
            trace_error(&e);
            None
        }
    };

    let list_not_ended = cmd.is_present("list-not-ended");

    let start_time_filter = |timetracking: &FileLockEntry| {
        start.map(|s| match timetracking.get_start_datetime() {
            Ok(Some(dt)) => dt >= s,
            Ok(None)     => {
                warn!("Funny things are happening: Timetracking has no start time");
                false
            }
            Err(e) => {
                trace_error(&e);
                false
            }
        })
        .unwrap_or(true)
    };

    let end_time_filter = |timetracking: &FileLockEntry| {
        start.map(|s| match timetracking.get_end_datetime() {
            Ok(Some(dt)) => dt <= s,
            Ok(None)     => list_not_ended,
            Err(e)       => {
                trace_error(&e);
                false
            }
        })
        .unwrap_or(true)
    };

    let filter = start_time_filter.and(end_time_filter);

    rt.store()
        .get_timetrackings()
        .and_then(|iter| {
            iter.trace_unwrap()
                .filter(|e| filter.filter(e))
                .fold(Ok(()), |acc, e| {
                    acc.and_then(|_| {
                        debug!("Processing {:?}", e.get_location());

                        let tag   = try!(e.get_timetrack_tag());
                        debug!(" -> tag = {:?}", tag);

                        let start = try!(e.get_start_datetime());
                        debug!(" -> start = {:?}", start);

                        let end   = try!(e.get_end_datetime());
                        debug!(" -> end = {:?}", end);

                        match (start, end) {
                            (None, _)          => println!("{} has no start time.", tag),
                            (Some(s), None)    => println!("{} | {} - ...", tag, s),
                            (Some(s), Some(e)) => println!("{} | {} - {}", tag, s, e),
                        }

                        Ok(())
                    })
                })
        })
        .map(|_| 0)
        .map_err_trace()
        .unwrap_or(1)
}

<commit_msg>Fix copy-paste bug<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::str::FromStr;

use filters::filter::Filter;

use libimagerror::trace::trace_error;
use libimagerror::trace::MapErrTrace;
use libimagerror::iter::TraceIterator;
use libimagstore::store::FileLockEntry;
use libimagtimetrack::timetrackingstore::TimeTrackStore;
use libimagtimetrack::timetracking::TimeTracking;

use libimagrt::runtime::Runtime;

pub fn list(rt: &Runtime) -> i32 {
    let (_, cmd) = rt.cli().subcommand();
    let cmd = cmd.unwrap(); // checked in main()

    let start = match cmd.value_of("start-time").map(::chrono::naive::NaiveDateTime::from_str) {
        None         => None,
        Some(Ok(dt)) => Some(dt),
        Some(Err(e)) => {
            trace_error(&e);
            None
        }
    };
    let end = match cmd.value_of("end-time").map(::chrono::naive::NaiveDateTime::from_str) {
        None         => None,
        Some(Ok(dt)) => Some(dt),
        Some(Err(e)) => {
            trace_error(&e);
            None
        }
    };

    let list_not_ended = cmd.is_present("list-not-ended");

    let start_time_filter = |timetracking: &FileLockEntry| {
        start.map(|s| match timetracking.get_start_datetime() {
            Ok(Some(dt)) => dt >= s,
            Ok(None)     => {
                warn!("Funny things are happening: Timetracking has no start time");
                false
            }
            Err(e) => {
                trace_error(&e);
                false
            }
        })
        .unwrap_or(true)
    };

    let end_time_filter = |timetracking: &FileLockEntry| {
        end.map(|s| match timetracking.get_end_datetime() {
            Ok(Some(dt)) => dt <= s,
            Ok(None)     => list_not_ended,
            Err(e)       => {
                trace_error(&e);
                false
            }
        })
        .unwrap_or(true)
    };

    let filter = start_time_filter.and(end_time_filter);

    rt.store()
        .get_timetrackings()
        .and_then(|iter| {
            iter.trace_unwrap()
                .filter(|e| filter.filter(e))
                .fold(Ok(()), |acc, e| {
                    acc.and_then(|_| {
                        debug!("Processing {:?}", e.get_location());

                        let tag   = try!(e.get_timetrack_tag());
                        debug!(" -> tag = {:?}", tag);

                        let start = try!(e.get_start_datetime());
                        debug!(" -> start = {:?}", start);

                        let end   = try!(e.get_end_datetime());
                        debug!(" -> end = {:?}", end);

                        match (start, end) {
                            (None, _)          => println!("{} has no start time.", tag),
                            (Some(s), None)    => println!("{} | {} - ...", tag, s),
                            (Some(s), Some(e)) => println!("{} | {} - {}", tag, s, e),
                        }

                        Ok(())
                    })
                })
        })
        .map(|_| 0)
        .map_err_trace()
        .unwrap_or(1)
}

<|endoftext|>


<commit_before><commit_msg>Make `test_reloc_iterator` work on non-64-bit systems.<commit_after><|endoftext|>


<commit_before>fn main() {
    // basic arithmetic
    assert_eq!(6.0_f32*6.0_f32, 36.0_f32);
    assert_eq!(6.0_f64*6.0_f64, 36.0_f64);
    assert_eq!(-{5.0_f32}, -5.0_f32);
    assert_eq!(-{5.0_f64}, -5.0_f64);
    // infinities, NaN
    assert!((5.0_f32/0.0).is_infinite());
    assert!((5.0_f64/0.0).is_infinite());
    assert!((-5.0_f32).sqrt().is_nan());
    assert!((-5.0_f64).sqrt().is_nan());
    // byte-level transmute
    let x: u64 = unsafe { std::mem::transmute(42.0_f64) };
    let y: f64 = unsafe { std::mem::transmute(x) };
    assert_eq!(y, 42.0_f64);
    let x: u32 = unsafe { std::mem::transmute(42.0_f32) };
    let y: f32 = unsafe { std::mem::transmute(x) };
    assert_eq!(y, 42.0_f32);

    // f32-to-int casts
    assert_eq!(5.0f32 as u32, 5);
    assert_eq!(-5.0f32 as u32, 0);
    assert_eq!(5.0f32 as i32, 5);
    assert_eq!(-5.0f32 as i32, -5);
    assert_eq!(std::f32::MAX as i32, i32::MAX);
    assert_eq!(std::f32::INFINITY as i32, i32::MAX);
    assert_eq!(std::f32::MAX as u32, u32::MAX);
    assert_eq!(std::f32::INFINITY as u32, u32::MAX);
    assert_eq!(std::f32::MIN as i32, i32::MIN);
    assert_eq!(std::f32::NEG_INFINITY as i32, i32::MIN);
    assert_eq!(std::f32::MIN as u32, 0);
    assert_eq!(std::f32::NEG_INFINITY as u32, 0);
    assert_eq!(std::f32::NAN as i32, 0);
    assert_eq!(std::f32::NAN as u32, 0);
    assert_eq!(u128::MAX as f32, std::f32::INFINITY);
    assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss
    assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss

    // f64-to-int casts
    assert_eq!(5.0f64 as u64, 5);
    assert_eq!(-5.0f64 as u64, 0);
    assert_eq!(5.0f64 as i64, 5);
    assert_eq!(-5.0f64 as i64, -5);
    assert_eq!(std::f64::MAX as i64, i64::MAX);
    assert_eq!(std::f64::INFINITY as i64, i64::MAX);
    assert_eq!(std::f64::MAX as u64, u64::MAX);
    assert_eq!(std::f64::INFINITY as u64, u64::MAX);
    assert_eq!(std::f64::MIN as i64, i64::MIN);
    assert_eq!(std::f64::NEG_INFINITY as i64, i64::MIN);
    assert_eq!(std::f64::MIN as u64, 0);
    assert_eq!(std::f64::NEG_INFINITY as u64, 0);
    assert_eq!(std::f64::NAN as i64, 0);
    assert_eq!(std::f64::NAN as u64, 0);
    assert_eq!(u128::MAX as f64 as u128, u128::MAX);
    assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss
    assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss

    // f32 <-> f64 casts
    assert_eq!(5.0f64 as f32, 5.0f32);
    assert_eq!(5.0f32 as f64, 5.0f64);
    assert_eq!(std::f64::MAX as f32, std::f32::INFINITY);
    assert_eq!(std::f64::MIN as f32, std::f32::NEG_INFINITY);
    assert_eq!(std::f32::INFINITY as f64, std::f64::INFINITY);
    assert_eq!(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY);

    // f32 min/max
    assert_eq!((1.0 as f32).max(-1.0), 1.0);
    assert_eq!((1.0 as f32).min(-1.0), -1.0);
    assert_eq!(std::f32::NAN.min(9.0), 9.0);
    assert_eq!(std::f32::NAN.max(-9.0), -9.0);
    assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0);
    assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0);

    // f64 min/max
    assert_eq!((1.0 as f64).max(-1.0), 1.0);
    assert_eq!((1.0 as f64).min(-1.0), -1.0);
    assert_eq!(std::f64::NAN.min(9.0), 9.0);
    assert_eq!(std::f64::NAN.max(-9.0), -9.0);
    assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0);
    assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0);

    // f32 copysign
    assert_eq!(3.5_f32.copysign(0.42), 3.5_f32);
    assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32);
    assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32);
    assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32);
    assert!(std::f32::NAN.copysign(1.0).is_nan());

    // f64 copysign
    assert_eq!(3.5_f64.copysign(0.42), 3.5_f64);
    assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64);
    assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64);
    assert_eq!((-3.5_f64).copysign(-0.42), -3.5_f64);
    assert!(std::f64::NAN.copysign(1.0).is_nan());
}
<commit_msg>avoid promotion so this can be compared with rustc<commit_after>#![feature(track_caller)]
use std::fmt::Debug;

// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE.
// Doesn't make a big difference when running this in Miri, but when running this in
// rustc (with -Zmir-opt-level=0) for comparison it means we use LLVM casts.
#[track_caller]
#[inline(never)]
fn assert_eq<T: PartialEq + Debug>(x: T, y: T) {
    assert_eq!(x, y);
}

fn main() {
    // basic arithmetic
    assert_eq(6.0_f32*6.0_f32, 36.0_f32);
    assert_eq(6.0_f64*6.0_f64, 36.0_f64);
    assert_eq(-{5.0_f32}, -5.0_f32);
    assert_eq(-{5.0_f64}, -5.0_f64);
    // infinities, NaN
    assert!((5.0_f32/0.0).is_infinite());
    assert!((5.0_f64/0.0).is_infinite());
    assert!((-5.0_f32).sqrt().is_nan());
    assert!((-5.0_f64).sqrt().is_nan());
    // byte-level transmute
    let x: u64 = unsafe { std::mem::transmute(42.0_f64) };
    let y: f64 = unsafe { std::mem::transmute(x) };
    assert_eq(y, 42.0_f64);
    let x: u32 = unsafe { std::mem::transmute(42.0_f32) };
    let y: f32 = unsafe { std::mem::transmute(x) };
    assert_eq(y, 42.0_f32);

    // f32-to-int casts
    assert_eq(5.0f32 as u32, 5);
    assert_eq(-5.0f32 as u32, 0);
    assert_eq(5.0f32 as i32, 5);
    assert_eq(-5.0f32 as i32, -5);
    assert_eq(std::f32::MAX as i32, i32::MAX);
    assert_eq(std::f32::INFINITY as i32, i32::MAX);
    assert_eq(std::f32::MAX as u32, u32::MAX);
    assert_eq(std::f32::INFINITY as u32, u32::MAX);
    assert_eq(std::f32::MIN as i32, i32::MIN);
    assert_eq(std::f32::NEG_INFINITY as i32, i32::MIN);
    assert_eq(std::f32::MIN as u32, 0);
    assert_eq(std::f32::NEG_INFINITY as u32, 0);
    assert_eq(std::f32::NAN as i32, 0);
    assert_eq(std::f32::NAN as u32, 0);
    assert_eq(u128::MAX as f32, std::f32::INFINITY);
    assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss
    assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss

    // f64-to-int casts
    assert_eq(5.0f64 as u64, 5);
    assert_eq(-5.0f64 as u64, 0);
    assert_eq(5.0f64 as i64, 5);
    assert_eq(-5.0f64 as i64, -5);
    assert_eq(std::f64::MAX as i64, i64::MAX);
    assert_eq(std::f64::INFINITY as i64, i64::MAX);
    assert_eq(std::f64::MAX as u64, u64::MAX);
    assert_eq(std::f64::INFINITY as u64, u64::MAX);
    assert_eq(std::f64::MIN as i64, i64::MIN);
    assert_eq(std::f64::NEG_INFINITY as i64, i64::MIN);
    assert_eq(std::f64::MIN as u64, 0);
    assert_eq(std::f64::NEG_INFINITY as u64, 0);
    assert_eq(std::f64::NAN as i64, 0);
    assert_eq(std::f64::NAN as u64, 0);
    assert_eq(u128::MAX as f64 as u128, u128::MAX);
    assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss
    assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss

    // f32 <-> f64 casts
    assert_eq(5.0f64 as f32, 5.0f32);
    assert_eq(5.0f32 as f64, 5.0f64);
    assert_eq(std::f64::MAX as f32, std::f32::INFINITY);
    assert_eq(std::f64::MIN as f32, std::f32::NEG_INFINITY);
    assert_eq(std::f32::INFINITY as f64, std::f64::INFINITY);
    assert_eq(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY);

    // f32 min/max
    assert_eq((1.0 as f32).max(-1.0), 1.0);
    assert_eq((1.0 as f32).min(-1.0), -1.0);
    assert_eq(std::f32::NAN.min(9.0), 9.0);
    assert_eq(std::f32::NAN.max(-9.0), -9.0);
    assert_eq((9.0 as f32).min(std::f32::NAN), 9.0);
    assert_eq((-9.0 as f32).max(std::f32::NAN), -9.0);

    // f64 min/max
    assert_eq((1.0 as f64).max(-1.0), 1.0);
    assert_eq((1.0 as f64).min(-1.0), -1.0);
    assert_eq(std::f64::NAN.min(9.0), 9.0);
    assert_eq(std::f64::NAN.max(-9.0), -9.0);
    assert_eq((9.0 as f64).min(std::f64::NAN), 9.0);
    assert_eq((-9.0 as f64).max(std::f64::NAN), -9.0);

    // f32 copysign
    assert_eq(3.5_f32.copysign(0.42), 3.5_f32);
    assert_eq(3.5_f32.copysign(-0.42), -3.5_f32);
    assert_eq((-3.5_f32).copysign(0.42), 3.5_f32);
    assert_eq((-3.5_f32).copysign(-0.42), -3.5_f32);
    assert!(std::f32::NAN.copysign(1.0).is_nan());

    // f64 copysign
    assert_eq(3.5_f64.copysign(0.42), 3.5_f64);
    assert_eq(3.5_f64.copysign(-0.42), -3.5_f64);
    assert_eq((-3.5_f64).copysign(0.42), 3.5_f64);
    assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64);
    assert!(std::f64::NAN.copysign(1.0).is_nan());
}
<|endoftext|>


<commit_before>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `librustc`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `librustc_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `librustc`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use crate::common::parse;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use std::fs;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let content = fs::read_to_string(path).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let edition = repo::edition(path).parse().unwrap();
                    let exprs = collect_exprs(file);
                    test_expressions(edition, exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    rustc_span::create_session_if_not_set_then(edition, |_| {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::librustc_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &librustc_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, librustc_ast);
            }
        }
    });

    (passed, failed)
}

fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::librustc_expr(input).and_then(librustc_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on librustc objects.
fn librustc_brackets(mut librustc_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_ast::ast::{
        Block, BorrowKind, Expr, ExprField, ExprKind, GenericArg, Pat, Stmt, StmtKind, StructExpr,
        StructRest, Ty,
    };
    use rustc_ast::mut_visit::{noop_visit_generic_arg, MutVisitor};
    use rustc_data_structures::map_in_place::MapInPlace;
    use rustc_data_structures::thin_vec::ThinVec;
    use rustc_span::DUMMY_SP;
    use std::mem;
    use std::ops::DerefMut;

    struct BracketsVisitor {
        failed: bool,
    }

    fn flat_map_field<T: MutVisitor>(mut f: ExprField, vis: &mut T) -> Vec<ExprField> {
        if f.is_shorthand {
            noop_visit_expr(&mut f.expr, vis);
        } else {
            vis.visit_expr(&mut f.expr);
        }
        vec![f]
    }

    fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
        let kind = match stmt.kind {
            // Don't wrap toplevel expressions in statements.
            StmtKind::Expr(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Expr(e)
            }
            StmtKind::Semi(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Semi(e)
            }
            s => s,
        };

        vec![Stmt { kind, ..stmt }]
    }

    fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
        use rustc_ast::mut_visit::{noop_visit_expr, visit_thin_attrs};
        match &mut e.kind {
            ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
            ExprKind::Struct(expr) => {
                let StructExpr {
                    qself,
                    path,
                    fields,
                    rest,
                } = expr.deref_mut();
                vis.visit_qself(qself);
                vis.visit_path(path);
                fields.flat_map_in_place(|field| flat_map_field(field, vis));
                if let StructRest::Base(rest) = rest {
                    vis.visit_expr(rest);
                }
                vis.visit_id(&mut e.id);
                vis.visit_span(&mut e.span);
                visit_thin_attrs(&mut e.attrs, vis);
            }
            _ => noop_visit_expr(e, vis),
        }
    }

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            match e.kind {
                ExprKind::ConstBlock(..) => {}
                _ => noop_visit_expr(e, self),
            }
            match e.kind {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            kind: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                            tokens: None,
                        }),
                    );
                    e.kind = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
            match arg {
                // Don't wrap unbraced const generic arg as that's invalid syntax.
                GenericArg::Const(anon_const) => {
                    if let ExprKind::Block(..) = &mut anon_const.value.kind {
                        noop_visit_expr(&mut anon_const.value, self);
                    }
                }
                _ => noop_visit_generic_arg(arg, self),
            }
        }

        fn visit_block(&mut self, block: &mut P<Block>) {
            self.visit_id(&mut block.id);
            block
                .stmts
                .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
            self.visit_span(&mut block.span);
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut librustc_expr);
    if folder.failed {
        None
    } else {
        Some(librustc_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                _ => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, expr)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
            match arg {
                GenericArgument::Const(arg) => GenericArgument::Const(match arg {
                    Expr::Block(_) => fold_expr(self, arg),
                    // Don't wrap unbraced const generic arg as that's invalid syntax.
                    _ => arg,
                }),
                _ => fold_generic_argument(self, arg),
            }
        }

        fn fold_generic_method_argument(
            &mut self,
            arg: GenericMethodArgument,
        ) -> GenericMethodArgument {
            match arg {
                GenericMethodArgument::Const(arg) => GenericMethodArgument::Const(match arg {
                    Expr::Block(_) => fold_expr(self, arg),
                    // Don't wrap unbraced const generic arg as that's invalid syntax.
                    _ => arg,
                }),
                _ => fold_generic_method_argument(self, arg),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Verbatim(tokens) if tokens.is_empty() => {}
                _ => self.0.push(expr),
            }

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<commit_msg>No need to put verbatim exprs through precedence test<commit_after>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

//! The tests in this module do the following:
//!
//! 1. Parse a given expression in both `syn` and `librustc`.
//! 2. Fold over the expression adding brackets around each subexpression (with
//!    some complications - see the `syn_brackets` and `librustc_brackets`
//!    methods).
//! 3. Serialize the `syn` expression back into a string, and re-parse it with
//!    `librustc`.
//! 4. Respan all of the expressions, replacing the spans with the default
//!    spans.
//! 5. Compare the expressions with one another, if they are not equal fail.

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use crate::common::parse;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use regex::Regex;
use rustc_ast::ast;
use rustc_ast::ptr::P;
use rustc_span::edition::Edition;
use std::fs;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

/// Test some pre-set expressions chosen by us.
#[test]
fn test_simple_precedence() {
    const EXPRS: &[&str] = &[
        "1 + 2 * 3 + 4",
        "1 + 2 * ( 3 + 4 )",
        "{ for i in r { } *some_ptr += 1; }",
        "{ loop { break 5; } }",
        "{ if true { () }.mthd() }",
        "{ for i in unsafe { 20 } { } }",
    ];

    let mut failed = 0;

    for input in EXPRS {
        let expr = if let Some(expr) = parse::syn_expr(input) {
            expr
        } else {
            failed += 1;
            continue;
        };

        let pf = match test_expressions(Edition::Edition2018, vec![expr]) {
            (1, 0) => "passed",
            (0, 1) => {
                failed += 1;
                "failed"
            }
            _ => unreachable!(),
        };
        errorf!("=== {}: {}\n", input, pf);
    }

    if failed > 0 {
        panic!("Failed {} tests", failed);
    }
}

/// Test expressions from rustc, like in `test_round_trip`.
#[test]
fn test_rustc_precedence() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all precedence tests");
    }

    let passed = AtomicUsize::new(0);
    let failed = AtomicUsize::new(0);

    // 2018 edition is hard
    let edition_regex = Regex::new(r"\b(async|try)[!(]").unwrap();

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let content = fs::read_to_string(path).unwrap();
            let content = edition_regex.replace_all(&content, "_$0");

            let (l_passed, l_failed) = match syn::parse_file(&content) {
                Ok(file) => {
                    let edition = repo::edition(path).parse().unwrap();
                    let exprs = collect_exprs(file);
                    test_expressions(edition, exprs)
                }
                Err(msg) => {
                    errorf!("syn failed to parse\n{:?}\n", msg);
                    (0, 1)
                }
            };

            errorf!(
                "=== {}: {} passed | {} failed\n",
                path.display(),
                l_passed,
                l_failed
            );

            passed.fetch_add(l_passed, Ordering::SeqCst);
            let prev_failed = failed.fetch_add(l_failed, Ordering::SeqCst);

            if prev_failed + l_failed >= abort_after {
                process::exit(1);
            }
        });

    let passed = passed.load(Ordering::SeqCst);
    let failed = failed.load(Ordering::SeqCst);

    errorf!("\n===== Precedence Test Results =====\n");
    errorf!("{} passed | {} failed\n", passed, failed);

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test_expressions(edition: Edition, exprs: Vec<syn::Expr>) -> (usize, usize) {
    let mut passed = 0;
    let mut failed = 0;

    rustc_span::create_session_if_not_set_then(edition, |_| {
        for expr in exprs {
            let raw = quote!(#expr).to_string();

            let librustc_ast = if let Some(e) = librustc_parse_and_rewrite(&raw) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse raw\n");
                continue;
            };

            let syn_expr = syn_brackets(expr);
            let syn_ast = if let Some(e) = parse::librustc_expr(&quote!(#syn_expr).to_string()) {
                e
            } else {
                failed += 1;
                errorf!("\nFAIL - librustc failed to parse bracketed\n");
                continue;
            };

            if SpanlessEq::eq(&syn_ast, &librustc_ast) {
                passed += 1;
            } else {
                failed += 1;
                errorf!("\nFAIL\n{:?}\n!=\n{:?}\n", syn_ast, librustc_ast);
            }
        }
    });

    (passed, failed)
}

fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
    parse::librustc_expr(input).and_then(librustc_brackets)
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precidence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
///
/// This method operates on librustc objects.
fn librustc_brackets(mut librustc_expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
    use rustc_ast::ast::{
        Block, BorrowKind, Expr, ExprField, ExprKind, GenericArg, Pat, Stmt, StmtKind, StructExpr,
        StructRest, Ty,
    };
    use rustc_ast::mut_visit::{noop_visit_generic_arg, MutVisitor};
    use rustc_data_structures::map_in_place::MapInPlace;
    use rustc_data_structures::thin_vec::ThinVec;
    use rustc_span::DUMMY_SP;
    use std::mem;
    use std::ops::DerefMut;

    struct BracketsVisitor {
        failed: bool,
    }

    fn flat_map_field<T: MutVisitor>(mut f: ExprField, vis: &mut T) -> Vec<ExprField> {
        if f.is_shorthand {
            noop_visit_expr(&mut f.expr, vis);
        } else {
            vis.visit_expr(&mut f.expr);
        }
        vec![f]
    }

    fn flat_map_stmt<T: MutVisitor>(stmt: Stmt, vis: &mut T) -> Vec<Stmt> {
        let kind = match stmt.kind {
            // Don't wrap toplevel expressions in statements.
            StmtKind::Expr(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Expr(e)
            }
            StmtKind::Semi(mut e) => {
                noop_visit_expr(&mut e, vis);
                StmtKind::Semi(e)
            }
            s => s,
        };

        vec![Stmt { kind, ..stmt }]
    }

    fn noop_visit_expr<T: MutVisitor>(e: &mut Expr, vis: &mut T) {
        use rustc_ast::mut_visit::{noop_visit_expr, visit_thin_attrs};
        match &mut e.kind {
            ExprKind::AddrOf(BorrowKind::Raw, ..) => {}
            ExprKind::Struct(expr) => {
                let StructExpr {
                    qself,
                    path,
                    fields,
                    rest,
                } = expr.deref_mut();
                vis.visit_qself(qself);
                vis.visit_path(path);
                fields.flat_map_in_place(|field| flat_map_field(field, vis));
                if let StructRest::Base(rest) = rest {
                    vis.visit_expr(rest);
                }
                vis.visit_id(&mut e.id);
                vis.visit_span(&mut e.span);
                visit_thin_attrs(&mut e.attrs, vis);
            }
            _ => noop_visit_expr(e, vis),
        }
    }

    impl MutVisitor for BracketsVisitor {
        fn visit_expr(&mut self, e: &mut P<Expr>) {
            match e.kind {
                ExprKind::ConstBlock(..) => {}
                _ => noop_visit_expr(e, self),
            }
            match e.kind {
                ExprKind::If(..) | ExprKind::Block(..) | ExprKind::Let(..) => {}
                _ => {
                    let inner = mem::replace(
                        e,
                        P(Expr {
                            id: ast::DUMMY_NODE_ID,
                            kind: ExprKind::Err,
                            span: DUMMY_SP,
                            attrs: ThinVec::new(),
                            tokens: None,
                        }),
                    );
                    e.kind = ExprKind::Paren(inner);
                }
            }
        }

        fn visit_generic_arg(&mut self, arg: &mut GenericArg) {
            match arg {
                // Don't wrap unbraced const generic arg as that's invalid syntax.
                GenericArg::Const(anon_const) => {
                    if let ExprKind::Block(..) = &mut anon_const.value.kind {
                        noop_visit_expr(&mut anon_const.value, self);
                    }
                }
                _ => noop_visit_generic_arg(arg, self),
            }
        }

        fn visit_block(&mut self, block: &mut P<Block>) {
            self.visit_id(&mut block.id);
            block
                .stmts
                .flat_map_in_place(|stmt| flat_map_stmt(stmt, self));
            self.visit_span(&mut block.span);
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn visit_pat(&mut self, pat: &mut P<Pat>) {
            let _ = pat;
        }

        fn visit_ty(&mut self, ty: &mut P<Ty>) {
            let _ = ty;
        }
    }

    let mut folder = BracketsVisitor { failed: false };
    folder.visit_expr(&mut librustc_expr);
    if folder.failed {
        None
    } else {
        Some(librustc_expr)
    }
}

/// Wrap every expression which is not already wrapped in parens with parens, to
/// reveal the precedence of the parsed expressions, and produce a stringified
/// form of the resulting expression.
fn syn_brackets(syn_expr: syn::Expr) -> syn::Expr {
    use syn::fold::*;
    use syn::*;

    struct ParenthesizeEveryExpr;
    impl Fold for ParenthesizeEveryExpr {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Group(_) => unreachable!(),
                Expr::If(..) | Expr::Unsafe(..) | Expr::Block(..) | Expr::Let(..) => {
                    fold_expr(self, expr)
                }
                _ => Expr::Paren(ExprParen {
                    attrs: Vec::new(),
                    expr: Box::new(fold_expr(self, expr)),
                    paren_token: token::Paren::default(),
                }),
            }
        }

        fn fold_generic_argument(&mut self, arg: GenericArgument) -> GenericArgument {
            match arg {
                GenericArgument::Const(arg) => GenericArgument::Const(match arg {
                    Expr::Block(_) => fold_expr(self, arg),
                    // Don't wrap unbraced const generic arg as that's invalid syntax.
                    _ => arg,
                }),
                _ => fold_generic_argument(self, arg),
            }
        }

        fn fold_generic_method_argument(
            &mut self,
            arg: GenericMethodArgument,
        ) -> GenericMethodArgument {
            match arg {
                GenericMethodArgument::Const(arg) => GenericMethodArgument::Const(match arg {
                    Expr::Block(_) => fold_expr(self, arg),
                    // Don't wrap unbraced const generic arg as that's invalid syntax.
                    _ => arg,
                }),
                _ => fold_generic_method_argument(self, arg),
            }
        }

        fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
            match stmt {
                // Don't wrap toplevel expressions in statements.
                Stmt::Expr(e) => Stmt::Expr(fold_expr(self, e)),
                Stmt::Semi(e, semi) => Stmt::Semi(fold_expr(self, e), semi),
                s => s,
            }
        }

        // We don't want to look at expressions that might appear in patterns or
        // types yet. We'll look into comparing those in the future. For now
        // focus on expressions appearing in other places.
        fn fold_pat(&mut self, pat: Pat) -> Pat {
            pat
        }

        fn fold_type(&mut self, ty: Type) -> Type {
            ty
        }
    }

    let mut folder = ParenthesizeEveryExpr;
    folder.fold_expr(syn_expr)
}

/// Walk through a crate collecting all expressions we can find in it.
fn collect_exprs(file: syn::File) -> Vec<syn::Expr> {
    use syn::fold::*;
    use syn::punctuated::Punctuated;
    use syn::*;

    struct CollectExprs(Vec<Expr>);
    impl Fold for CollectExprs {
        fn fold_expr(&mut self, expr: Expr) -> Expr {
            match expr {
                Expr::Verbatim(_) => {}
                _ => self.0.push(expr),
            }

            Expr::Tuple(ExprTuple {
                attrs: vec![],
                elems: Punctuated::new(),
                paren_token: token::Paren::default(),
            })
        }
    }

    let mut folder = CollectExprs(vec![]);
    folder.fold_file(file);
    folder.0
}
<|endoftext|>


<commit_before>use serde::de::Error;
use serde_json::{self, Error as JsonError};

use std::collections::{BTreeMap, HashSet};

use storage::StorageValue;
use events::Milliseconds;
use crypto::{hash, PublicKey, Hash};

/// Public keys of a validator.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidatorKeys {
    /// Consensus key is used for messages related to the consensus algorithm.
    pub consensus_key: PublicKey,
    /// Service key is used for services.
    pub service_key: PublicKey,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    pub previous_cfg_hash: Hash,
    pub actual_from: u64,
    /// List of validator's consensus and service public keys.
    pub validator_keys: Vec<ValidatorKeys>,
    pub consensus: ConsensusConfig,
    pub services: BTreeMap<String, serde_json::Value>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    pub round_timeout: Milliseconds,
    pub status_timeout: Milliseconds,
    pub peers_timeout: Milliseconds,
    pub propose_timeout: Milliseconds,
    pub txs_block_limit: u32,
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            propose_timeout: 500,
            status_timeout: 5000,
            peers_timeout: 10000,
            txs_block_limit: 1000,
        }
    }
}

impl StoredConfiguration {
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        // Check that there are no duplicated keys.
        {
            let mut keys = HashSet::with_capacity(config.validator_keys.len() * 2);
            for k in config.validator_keys.iter() {
                keys.insert(k.consensus_key);
                keys.insert(k.service_key);
            }
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom("Duplicated validator keys are found"));
            }
        }

        Ok(config)
    }
}

impl StorageValue for StoredConfiguration {
    fn serialize(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn deserialize(v: Vec<u8>) -> Self {
        StoredConfiguration::try_deserialize(&v).unwrap()
    }

    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

#[cfg(test)]
mod tests {
    use toml;
    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Duplicated validator keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(ValidatorKeys {
            consensus_key: PublicKey::zero(),
            service_key: PublicKey::zero(),
        });
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = (1..4).map(|i| ValidatorKeys {
                consensus_key: gen_keypair_from_seed(&Seed::new([i; 32])).0,
                service_key: gen_keypair_from_seed(&Seed::new([i * 10; 32])).0,
            }).collect();

        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: 42,
            validator_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) {
        let serialized = configuration.try_serialize().unwrap();
        let _ = StoredConfiguration::try_deserialize(&serialized).unwrap();
    }
}
<commit_msg>Add 'doc(hidden)' attribute to consensus_key<commit_after>use serde::de::Error;
use serde_json::{self, Error as JsonError};

use std::collections::{BTreeMap, HashSet};

use storage::StorageValue;
use events::Milliseconds;
use crypto::{hash, PublicKey, Hash};

/// Public keys of a validator.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidatorKeys {
    /// Consensus key is used for messages related to the consensus algorithm.
    #[doc(hidden)]
    pub consensus_key: PublicKey,
    /// Service key is used for services.
    pub service_key: PublicKey,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    pub previous_cfg_hash: Hash,
    pub actual_from: u64,
    /// List of validator's consensus and service public keys.
    pub validator_keys: Vec<ValidatorKeys>,
    pub consensus: ConsensusConfig,
    pub services: BTreeMap<String, serde_json::Value>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    pub round_timeout: Milliseconds,
    pub status_timeout: Milliseconds,
    pub peers_timeout: Milliseconds,
    pub propose_timeout: Milliseconds,
    pub txs_block_limit: u32,
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            propose_timeout: 500,
            status_timeout: 5000,
            peers_timeout: 10000,
            txs_block_limit: 1000,
        }
    }
}

impl StoredConfiguration {
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        // Check that there are no duplicated keys.
        {
            let mut keys = HashSet::with_capacity(config.validator_keys.len() * 2);
            for k in config.validator_keys.iter() {
                keys.insert(k.consensus_key);
                keys.insert(k.service_key);
            }
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom("Duplicated validator keys are found"));
            }
        }

        Ok(config)
    }
}

impl StorageValue for StoredConfiguration {
    fn serialize(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn deserialize(v: Vec<u8>) -> Self {
        StoredConfiguration::try_deserialize(&v).unwrap()
    }

    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

#[cfg(test)]
mod tests {
    use toml;
    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Duplicated validator keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(ValidatorKeys {
            consensus_key: PublicKey::zero(),
            service_key: PublicKey::zero(),
        });
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = (1..4).map(|i| ValidatorKeys {
                consensus_key: gen_keypair_from_seed(&Seed::new([i; 32])).0,
                service_key: gen_keypair_from_seed(&Seed::new([i * 10; 32])).0,
            }).collect();

        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: 42,
            validator_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) {
        let serialized = configuration.try_serialize().unwrap();
        let _ = StoredConfiguration::try_deserialize(&serialized).unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics)]

use std::panic::Location;

#[track_caller]
fn tracked() -> &'static Location<'static> {
    Location::caller() // most importantly, we never get line 7
}

fn nested_intrinsic() -> &'static Location<'static> {
    Location::caller()
}

fn nested_tracked() -> &'static Location<'static> {
    tracked()
}

macro_rules! caller_location_from_macro {
    () => {
        core::panic::Location::caller()
    };
}

fn test_fn_ptr() {
    fn pass_to_ptr_call<T>(f: fn(T), x: T) {
        f(x);
    }

    #[track_caller]
    fn tracked_unit(_: ()) {
        let expected_line = line!() - 1;
        let location = std::panic::Location::caller();
        assert_eq!(location.file(), file!());
        assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
    }

    pass_to_ptr_call(tracked_unit, ());
}

fn test_trait_obj() {
    trait Tracked {
        #[track_caller]
        fn handle(&self) -> &'static Location<'static> {
            std::panic::Location::caller()
        }
    }

    impl Tracked for () {}
    impl Tracked for u8 {}

    // Test that we get the correct location
    // even with a call through a trait object

    let tracked: &dyn Tracked = &5u8;
    let location = tracked.handle();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 28);

    const TRACKED: &dyn Tracked = &();
    let location = TRACKED.handle();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 28);
}

fn main() {
    let location = Location::caller();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 20);

    let tracked = tracked();
    let expected_line = line!() - 1;
    assert_eq!(tracked.file(), file!());
    assert_eq!(tracked.line(), expected_line);
    assert_eq!(tracked.column(), 19);

    let nested = nested_intrinsic();
    assert_eq!(nested.file(), file!());
    assert_eq!(nested.line(), 11);
    assert_eq!(nested.column(), 5);

    let contained = nested_tracked();
    assert_eq!(contained.file(), file!());
    assert_eq!(contained.line(), 15);
    assert_eq!(contained.column(), 5);

    // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
    // i.e. point to where the macro was invoked, instead of the macro itself.
    let inmacro = caller_location_from_macro!();
    let expected_line = line!() - 1;
    assert_eq!(inmacro.file(), file!());
    assert_eq!(inmacro.line(), expected_line);
    assert_eq!(inmacro.column(), 19);

    let intrinsic = core::intrinsics::caller_location();
    let expected_line = line!() - 1;
    assert_eq!(intrinsic.file(), file!());
    assert_eq!(intrinsic.line(), expected_line);
    assert_eq!(intrinsic.column(), 21);

    test_fn_ptr();
    test_trait_obj();
}
<commit_msg>Auto merge of #2418 - RalfJung:track, r=RalfJung<commit_after>#![feature(core_intrinsics)]

use std::panic::Location;

#[track_caller]
fn tracked() -> &'static Location<'static> {
    Location::caller() // most importantly, we never get line 7
}

fn nested_intrinsic() -> &'static Location<'static> {
    Location::caller()
}

fn nested_tracked() -> &'static Location<'static> {
    tracked()
}

macro_rules! caller_location_from_macro {
    () => {
        core::panic::Location::caller()
    };
}

fn test_fn_ptr() {
    fn pass_to_ptr_call<T>(f: fn(T), x: T) {
        f(x);
    }

    #[track_caller]
    fn tracked_unit(_: ()) {
        let expected_line = line!() - 1;
        let location = std::panic::Location::caller();
        assert_eq!(location.file(), file!());
        assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
    }

    pass_to_ptr_call(tracked_unit, ());
}

fn test_trait_obj() {
    trait Tracked {
        #[track_caller]
        fn handle(&self) -> &'static Location<'static> {
            std::panic::Location::caller()
        }
    }

    impl Tracked for () {}
    impl Tracked for u8 {}

    // Test that we get the correct location
    // even with a call through a trait object

    let tracked: &dyn Tracked = &5u8;
    let location = tracked.handle();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 28);

    const TRACKED: &dyn Tracked = &();
    let location = TRACKED.handle();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 28);
}

fn test_trait_obj2() {
    // track_caller on the impl but not the trait.
    pub trait Foo {
        fn foo(&self) -> &'static Location<'static>;
    }

    struct Bar;
    impl Foo for Bar {
        #[track_caller]
        fn foo(&self) -> &'static Location<'static> {
            std::panic::Location::caller()
        }
    }
    let expected_line = line!() - 4; // the `fn` signature above

    let f = &Bar as &dyn Foo;
    let loc = f.foo(); // trait doesn't track, so we don't point at this call site
    assert_eq!(loc.file(), file!());
    assert_eq!(loc.line(), expected_line);
}

fn main() {
    let location = Location::caller();
    let expected_line = line!() - 1;
    assert_eq!(location.file(), file!());
    assert_eq!(location.line(), expected_line);
    assert_eq!(location.column(), 20);

    let tracked = tracked();
    let expected_line = line!() - 1;
    assert_eq!(tracked.file(), file!());
    assert_eq!(tracked.line(), expected_line);
    assert_eq!(tracked.column(), 19);

    let nested = nested_intrinsic();
    assert_eq!(nested.file(), file!());
    assert_eq!(nested.line(), 11);
    assert_eq!(nested.column(), 5);

    let contained = nested_tracked();
    assert_eq!(contained.file(), file!());
    assert_eq!(contained.line(), 15);
    assert_eq!(contained.column(), 5);

    // `Location::caller()` in a macro should behave similarly to `file!` and `line!`,
    // i.e. point to where the macro was invoked, instead of the macro itself.
    let inmacro = caller_location_from_macro!();
    let expected_line = line!() - 1;
    assert_eq!(inmacro.file(), file!());
    assert_eq!(inmacro.line(), expected_line);
    assert_eq!(inmacro.column(), 19);

    let intrinsic = core::intrinsics::caller_location();
    let expected_line = line!() - 1;
    assert_eq!(intrinsic.file(), file!());
    assert_eq!(intrinsic.line(), expected_line);
    assert_eq!(intrinsic.column(), 21);

    test_fn_ptr();
    test_trait_obj();
    test_trait_obj2();
}
<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(str_char)]

use std::collections::hash_set::HashSet;

pub type ParseResult<T> = Result<ParseSuccess<T>, String>;

pub struct ParseState<T>
{
  /// Even in case of success, we keep error information in case we
  /// fail later.
  pub error: ParseError,
  pub success: Option<ParseSuccess<T>>
}

impl<T> ParseState<T>
{
  #[inline]
  pub fn success(data: T, offset: usize) -> ParseState<T> {
    ParseState {
      error: ParseError::empty(offset),
      success: Some(ParseSuccess::new(data, offset))
    }
  }

  #[inline]
  pub fn from_error(error: ParseError) -> ParseState<T> {
    ParseState {
      error: error,
      success: None
    }
  }

  #[inline]
  pub fn error(offset: usize, expect: &'static str) -> ParseState<T> {
    ParseState::from_error(ParseError::unique(offset, expect))
  }

  #[inline]
  pub fn empty_error(offset: usize) -> ParseState<T> {
    ParseState {
      error: ParseError::empty(offset),
      success: None
    }
  }

  #[inline]
  pub fn map<U, F>(self, op: F) -> ParseState<U> where
   F: FnOnce(ParseSuccess<T>) -> ParseSuccess<U>
  {
    ParseState {
      error: self.error,
      success: self.success.map(op)
    }
  }

  #[inline]
  pub fn and_then<U, F>(self, op: F) -> ParseState<U> where
   F: FnOnce(ParseSuccess<T>) -> ParseState<U>
  {
    match self.success {
      Some(success) => {
        let mut state = op(success);
        state.error = state.error.join(self.error);
        state
      }
      None => ParseState::from_error(self.error)
    }
  }

  #[inline]
  pub fn or_else_join<F>(self, op: F) -> ParseState<T> where
   F: FnOnce() -> ParseState<T>
  {
    self.or_else(|err| op().join(err))
  }

  #[inline]
  pub fn join(mut self, error: ParseError) -> ParseState<T> {
    self.error = self.error.join(error);
    self
  }

  #[inline]
  pub fn or_else<F>(self, op: F) -> ParseState<T> where
   F: FnOnce(ParseError) -> ParseState<T>
  {
    match &self.success {
      &Some(_) => self,
      &None => op(self.error)
    }
  }

  #[inline]
  pub fn map_or_else<U, D, F>(self, default: D, f: F) -> ParseState<U> where
   D: FnOnce() -> ParseSuccess<U>,
   F: FnOnce(ParseSuccess<T>) -> ParseSuccess<U>
  {
    ParseState {
      error: self.error,
      success: Some(self.success.map_or_else(default, f))
    }
  }

  #[inline]
  pub fn to_error(mut self) -> ParseState<T> {
    self.success = None;
    self
  }

  pub fn into_result(self, source: &str) -> ParseResult<T> {
    match self.success {
      Some(success) => {
        Ok(success)
      },
      None => {
        Err(self.error.description(source))
      }
    }
  }
}

impl ParseState<()>
{
  #[inline]
  pub fn stateless(offset: usize) -> ParseState<()> {
    ParseState::success((), offset)
  }

  #[inline]
  pub fn to_stateless_success(self, offset: usize) -> ParseState<()> {
    ParseState {
      error: self.error,
      success: self.success.or(Some(ParseSuccess::stateless(offset)))
    }
  }

  #[inline]
  pub fn merge_success(&mut self, other: ParseSuccess<()>)
  {
    debug_assert!(self.success.is_some(), "ParseState::merge_success can only be called if `self` is successfull.");
    self.success = Some(other);
  }
}

impl<T> ParseState<Vec<T>>
{
  #[inline]
  pub fn merge_success(&mut self, other: ParseSuccess<T>)
  {
    debug_assert!(self.success.is_some(), "ParseState::merge_success can only be called if `self` is successfull.");
    let success = self.success.as_mut().unwrap();
    success.data.push(other.data);
    success.offset = other.offset;
  }
}

#[derive(Debug)]
pub struct ParseSuccess<T>
{
  pub data: T,
  pub offset: usize
}

impl<T> ParseSuccess<T>
{
  #[inline]
  pub fn new(data: T, offset: usize) -> ParseSuccess<T> {
    ParseSuccess {
      data: data,
      offset: offset
    }
  }

  pub fn full_read(&self, input: &str) -> bool {
    debug_assert!(self.offset <= input.len());
    self.offset == input.len()
  }

  pub fn partial_read(&self, input: &str) -> bool {
    !self.full_read(input)
  }
}

impl ParseSuccess<()>
{
  #[inline]
  pub fn stateless(offset: usize) -> ParseSuccess<()> {
    ParseSuccess::new((), offset)
  }
}

#[derive(Clone, Debug)]
pub struct ParseError
{
  pub farthest_offset: usize,
  pub expected: Vec<&'static str>
}

impl ParseError
{
  pub fn unique(offset: usize, expect: &'static str) -> ParseError {
    ParseError {
      farthest_offset: offset,
      expected: vec![expect]
    }
  }

  pub fn empty(offset: usize) -> ParseError {
    ParseError {
      farthest_offset: offset,
      expected: vec![]
    }
  }

  pub fn join(mut self, other: ParseError) -> ParseError {
    if self.farthest_offset > other.farthest_offset {
      self
    }
    else if self.farthest_offset < other.farthest_offset {
      other
    }
    else {
      self.expected.extend(other.expected.into_iter());
      self
    }
  }

  // Partially taken from https://github.com/kevinmehall/rust-peg/blob/master/src/translate.rs
  pub fn line_column(&self, source: &str) -> (usize, usize) {
    let mut remaining = self.farthest_offset;
    let mut line_no = 1usize;
    for line in source.lines_any() {
      let line_len = line.len() + 1;
      if remaining < line_len {
        break;
      }
      remaining -= line_len;
      line_no += 1;
    }
    (line_no, remaining + 1)
  }

  pub fn description(&self, source: &str) -> String {
    let (line, column) = self.line_column(source);
    let expected = self.expected_desc();
    format!("{}:{}: unexpected `{}`, expecting {}.", line, column, self.code_snippet(source), expected)
  }

  fn code_snippet<'a>(&self, source: &'a str) -> &'a str
  {
    debug_assert!(self.farthest_offset <= source.len());
    if self.farthest_offset == source.len() {
      &"<end-of-file>"
    }
    else {
      let code_snippet_len = 10usize;
      let len = std::cmp::min(source.len() - self.farthest_offset, code_snippet_len);
      &source[self.farthest_offset..][..len]
    }
  }

  fn expected_desc(&self) -> String {
    let expected: HashSet<&'static str> = self.expected.clone().into_iter().collect();
    let mut desc = String::new();
    for expect in expected {
      desc.push('`');
      desc.push_str(expect);
      desc.push_str("` or ");
    }
    let len_without_last_or = desc.len() - 4;
    desc.truncate(len_without_last_or);
    desc
  }
}

#[inline]
pub fn parse_any_single_char(input: &str, offset: usize) -> ParseState<char> {
  if offset < input.len() {
    let any = input.char_at(offset);
    ParseState::success(any, offset + any.len_utf8())
  } else {
    ParseState::error(offset, "<character>")
  }
}

#[inline]
pub fn recognize_any_single_char(input: &str, offset: usize) -> ParseState<()> {
  if offset < input.len() {
    let any = input.char_at(offset);
    ParseState::stateless(offset + any.len_utf8())
  } else {
    ParseState::error(offset, "<character>")
  }
}

#[inline]
pub fn parse_match_literal(input: &str, offset: usize, lit: &'static str, lit_len: usize)
  -> ParseState<()>
{
  if offset < input.len() && input[offset..].starts_with(lit) {
    ParseState::stateless(offset + lit_len)
  } else {
    ParseState::error(offset, lit)
  }
}

#[inline]
pub fn recognize_match_literal(input: &str, offset: usize, lit: &'static str, lit_len: usize)
  -> ParseState<()>
{
  parse_match_literal(input, offset, lit, lit_len)
}

#[inline]
/// We erase the errors generated inside a `!e` expression because it is hard to correctly use (see paper Maidl & al. 2014 on error reporting).
pub fn not_predicate(state: ParseState<()>, offset: usize)
  -> ParseState<()>
{
  match state.success {
    Some(_) => ParseState::empty_error(offset),
    _ => ParseState::stateless(offset)
  }
}

#[inline]
pub fn and_predicate(state: ParseState<()>, offset: usize)
  -> ParseState<()>
{
  state.map(|_| ParseSuccess::stateless(offset))
}

#[inline]
pub fn optional_recognizer(state: ParseState<()>, offset: usize)
  -> ParseState<()>
{
  state.to_stateless_success(offset)
}

#[inline]
pub fn optional_parser<T>(state: ParseState<T>, offset: usize)
  -> ParseState<Option<T>>
{
  state.map_or_else(
    || ParseSuccess::new(None, offset),
    |success| ParseSuccess::new(Some(success.data), success.offset))
}
<commit_msg>[Runtime] Compare input and literal with bytes slices instead of with start_with.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(str_char)]

use std::collections::hash_set::HashSet;

pub type ParseResult<T> = Result<ParseSuccess<T>, String>;

pub struct ParseState<T>
{
  /// Even in case of success, we keep error information in case we
  /// fail later.
  pub error: ParseError,
  pub success: Option<ParseSuccess<T>>
}

impl<T> ParseState<T>
{
  #[inline]
  pub fn success(data: T, offset: usize) -> ParseState<T> {
    ParseState {
      error: ParseError::empty(offset),
      success: Some(ParseSuccess::new(data, offset))
    }
  }

  #[inline]
  pub fn from_error(error: ParseError) -> ParseState<T> {
    ParseState {
      error: error,
      success: None
    }
  }

  #[inline]
  pub fn error(offset: usize, expect: &'static str) -> ParseState<T> {
    ParseState::from_error(ParseError::unique(offset, expect))
  }

  #[inline]
  pub fn empty_error(offset: usize) -> ParseState<T> {
    ParseState {
      error: ParseError::empty(offset),
      success: None
    }
  }

  #[inline]
  pub fn map<U, F>(self, op: F) -> ParseState<U> where
   F: FnOnce(ParseSuccess<T>) -> ParseSuccess<U>
  {
    ParseState {
      error: self.error,
      success: self.success.map(op)
    }
  }

  #[inline]
  pub fn and_then<U, F>(self, op: F) -> ParseState<U> where
   F: FnOnce(ParseSuccess<T>) -> ParseState<U>
  {
    match self.success {
      Some(success) => {
        let mut state = op(success);
        state.error = state.error.join(self.error);
        state
      }
      None => ParseState::from_error(self.error)
    }
  }

  #[inline]
  pub fn or_else_join<F>(self, op: F) -> ParseState<T> where
   F: FnOnce() -> ParseState<T>
  {
    self.or_else(|err| op().join(err))
  }

  #[inline]
  pub fn join(mut self, error: ParseError) -> ParseState<T> {
    self.error = self.error.join(error);
    self
  }

  #[inline]
  pub fn or_else<F>(self, op: F) -> ParseState<T> where
   F: FnOnce(ParseError) -> ParseState<T>
  {
    match &self.success {
      &Some(_) => self,
      &None => op(self.error)
    }
  }

  #[inline]
  pub fn map_or_else<U, D, F>(self, default: D, f: F) -> ParseState<U> where
   D: FnOnce() -> ParseSuccess<U>,
   F: FnOnce(ParseSuccess<T>) -> ParseSuccess<U>
  {
    ParseState {
      error: self.error,
      success: Some(self.success.map_or_else(default, f))
    }
  }

  #[inline]
  pub fn to_error(mut self) -> ParseState<T> {
    self.success = None;
    self
  }

  pub fn into_result(self, source: &str) -> ParseResult<T> {
    match self.success {
      Some(success) => {
        Ok(success)
      },
      None => {
        Err(self.error.description(source))
      }
    }
  }
}

impl ParseState<()>
{
  #[inline]
  pub fn stateless(offset: usize) -> ParseState<()> {
    ParseState::success((), offset)
  }

  #[inline]
  pub fn to_stateless_success(self, offset: usize) -> ParseState<()> {
    ParseState {
      error: self.error,
      success: self.success.or(Some(ParseSuccess::stateless(offset)))
    }
  }

  #[inline]
  pub fn merge_success(&mut self, other: ParseSuccess<()>)
  {
    debug_assert!(self.success.is_some(), "ParseState::merge_success can only be called if `self` is successfull.");
    self.success = Some(other);
  }
}

impl<T> ParseState<Vec<T>>
{
  #[inline]
  pub fn merge_success(&mut self, other: ParseSuccess<T>)
  {
    debug_assert!(self.success.is_some(), "ParseState::merge_success can only be called if `self` is successfull.");
    let success = self.success.as_mut().unwrap();
    success.data.push(other.data);
    success.offset = other.offset;
  }
}

#[derive(Debug)]
pub struct ParseSuccess<T>
{
  pub data: T,
  pub offset: usize
}

impl<T> ParseSuccess<T>
{
  #[inline]
  pub fn new(data: T, offset: usize) -> ParseSuccess<T> {
    ParseSuccess {
      data: data,
      offset: offset
    }
  }

  pub fn full_read(&self, input: &str) -> bool {
    debug_assert!(self.offset <= input.len());
    self.offset == input.len()
  }

  pub fn partial_read(&self, input: &str) -> bool {
    !self.full_read(input)
  }
}

impl ParseSuccess<()>
{
  #[inline]
  pub fn stateless(offset: usize) -> ParseSuccess<()> {
    ParseSuccess::new((), offset)
  }
}

#[derive(Clone, Debug)]
pub struct ParseError
{
  pub farthest_offset: usize,
  pub expected: Vec<&'static str>
}

impl ParseError
{
  pub fn unique(offset: usize, expect: &'static str) -> ParseError {
    ParseError {
      farthest_offset: offset,
      expected: vec![expect]
    }
  }

  pub fn empty(offset: usize) -> ParseError {
    ParseError {
      farthest_offset: offset,
      expected: vec![]
    }
  }

  pub fn join(mut self, other: ParseError) -> ParseError {
    if self.farthest_offset > other.farthest_offset {
      self
    }
    else if self.farthest_offset < other.farthest_offset {
      other
    }
    else {
      self.expected.extend(other.expected.into_iter());
      self
    }
  }

  // Partially taken from https://github.com/kevinmehall/rust-peg/blob/master/src/translate.rs
  pub fn line_column(&self, source: &str) -> (usize, usize) {
    let mut remaining = self.farthest_offset;
    let mut line_no = 1usize;
    for line in source.lines_any() {
      let line_len = line.len() + 1;
      if remaining < line_len {
        break;
      }
      remaining -= line_len;
      line_no += 1;
    }
    (line_no, remaining + 1)
  }

  pub fn description(&self, source: &str) -> String {
    let (line, column) = self.line_column(source);
    let expected = self.expected_desc();
    format!("{}:{}: unexpected `{}`, expecting {}.", line, column, self.code_snippet(source), expected)
  }

  fn code_snippet<'a>(&self, source: &'a str) -> &'a str
  {
    debug_assert!(self.farthest_offset <= source.len());
    if self.farthest_offset == source.len() {
      &"<end-of-file>"
    }
    else {
      let code_snippet_len = 10usize;
      let len = std::cmp::min(source.len() - self.farthest_offset, code_snippet_len);
      &source[self.farthest_offset..][..len]
    }
  }

  fn expected_desc(&self) -> String {
    let expected: HashSet<&'static str> = self.expected.clone().into_iter().collect();
    let mut desc = String::new();
    for expect in expected {
      desc.push('`');
      desc.push_str(expect);
      desc.push_str("` or ");
    }
    let len_without_last_or = desc.len() - 4;
    desc.truncate(len_without_last_or);
    desc
  }
}

#[inline]
pub fn parse_any_single_char(input: &str, offset: usize) -> ParseState<char> {
  if offset < input.len() {
    let any = input.char_at(offset);
    ParseState::success(any, offset + any.len_utf8())
  } else {
    ParseState::error(offset, "<character>")
  }
}

#[inline]
pub fn recognize_any_single_char(input: &str, offset: usize) -> ParseState<()> {
  if offset < input.len() {
    let any = input.char_at(offset);
    ParseState::stateless(offset + any.len_utf8())
  } else {
    ParseState::error(offset, "<character>")
  }
}

#[inline]
pub fn parse_match_literal(input: &str, offset: usize, lit: &'static str, lit_len: usize)
  -> ParseState<()>
{
  let end_offset = offset + lit_len;
  if end_offset <= input.len() && &input.as_bytes()[offset..end_offset] == lit.as_bytes() {
    ParseState::stateless(end_offset)
  } else {
    ParseState::error(offset, lit)
  }
}

#[inline]
pub fn recognize_match_literal(input: &str, offset: usize, lit: &'static str, lit_len: usize)
  -> ParseState<()>
{
  parse_match_literal(input, offset, lit, lit_len)
}

#[inline]
/// We erase the errors generated inside a `!e` expression because it is hard to correctly use (see paper Maidl & al. 2014 on error reporting).
pub fn not_predicate(state: ParseState<()>, offset: usize)
  -> ParseState<()>
{
  match state.success {
    Some(_) => ParseState::empty_error(offset),
    _ => ParseState::stateless(offset)
  }
}

#[inline]
pub fn and_predicate(state: ParseState<()>, offset: usize)
  -> ParseState<()>
{
  state.map(|_| ParseSuccess::stateless(offset))
}

#[inline]
pub fn optional_recognizer(state: ParseState<()>, offset: usize)
  -> ParseState<()>
{
  state.to_stateless_success(offset)
}

#[inline]
pub fn optional_parser<T>(state: ParseState<T>, offset: usize)
  -> ParseState<Option<T>>
{
  state.map_or_else(
    || ParseSuccess::new(None, offset),
    |success| ParseSuccess::new(Some(success.data), success.offset))
}
<|endoftext|>