<commit_before>///
/// Delimited Text Scanner for comma/tab separated value formats
///

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

use common::constant::ROWBLOCK_SIZE;
use common::err::*;
use exec::Executor;
use io::stream::*;
use schema::Schema;
use schema::util::finds_target_indexes;
use rows::{shallow_copy, RowBlock, RowBlockWriter};
use rows::vrows::{BorrowedVRowBlock, HeapVRowBlock};
use types::*;
use util::str::{StrSlice,split_str_slice};

/// default buffer size
const BUF_SIZE: usize = 65536;

pub struct DelimTextScanner<'a> {
  // constants
  data_schema     : Schema,
  read_fields     : Option<Schema>,
  read_fields_idxs: Vec<usize>,

  line_delim  : u8,
  field_delim : u8,

  reader      : Box<StreamReader>,

  // variable
  readbuf_ptr      : *mut u8,           // readbuf
  read_len         : usize,             // length of read bytes
  consumed_len     : usize,             // actually consumed bytes length for line slices

  line_slices_idx  : usize,             // current line slice for reading
  line_slices_num  : usize,             // number of filled line slices
  line_slices_ptr  : *mut StrSlice,     // ptr for line slice array
  line_slices      : &'a mut [StrSlice],// line slice array

  fields_slices_ptr: *mut StrSlice,     // ptr for field slice array
  fields_slices    : &'a mut [StrSlice],// field slice array

  owned_rowblock   : HeapVRowBlock<'a>
}

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

    let read_fields_idxs = match read_fields {
      Some(ref s) => finds_target_indexes(&data_schema, s),
      None        => finds_target_indexes(&data_schema, &data_schema),
    };

    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())
    };

    let rowblock = HeapVRowBlock::new(
      match read_fields {
        Some(ref s) => s,
        None        => &data_schema
      }
    );

    DelimTextScanner {
      data_schema: data_schema,
      read_fields: read_fields,
      read_fields_idxs: read_fields_idxs,

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

      reader: stream,

      readbuf_ptr: unsafe { heap::allocate(BUF_SIZE, 16) },
      consumed_len: 0,
      read_len: 0,

      line_slices_idx: 0,
      line_slices_num: 0,
      line_slices_ptr: line_slices_ptr,
      line_slices: line_slices,

      fields_slices_ptr: fields_slices_ptr,
      fields_slices: fields_slices,

      owned_rowblock: rowblock
    }
  }

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

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

  fn find_first_record_index(&self, bytes: &[u8]) -> Option<usize> {
    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 fill_line_slices(&mut self) {

    let mut line_num: usize = 0;
    let mut last_pos: usize = 0; // keep the start offset
    let mut cur_pos : usize = 0; // the current offset

    while (cur_pos < self.read_len && line_num < ROWBLOCK_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[line_num].set_ptr(unsafe {self.readbuf_ptr.offset(last_pos as isize)});
        self.line_slices[line_num].set_len((cur_pos - last_pos) as i32);

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

      cur_pos = cur_pos + 1;
    }

    self.line_slices_num  = line_num; // read line counter
    self.consumed_len = last_pos;
    self.line_slices_idx = 0;
  }

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

    //self.read_fields_idxs.iter().map(|x| x);

    let mut actual_id: usize;
    for x in 0..self.read_fields_idxs.len() {
      actual_id = self.read_fields_idxs[x];

      match self.data_schema.column(actual_id).data_ty().kind() {
        TyKind::Text => self.owned_rowblock.put_text(row_idx, x, &self.fields_slices[actual_id]),
        _ => {}
      }
    }
  }

  /// move the remain bytes into the header of buffer and fill the buffer.
  fn fill_readbuf(&mut self) -> Void {
    let remain_len = self.read_len - self.consumed_len;
    debug_assert!(remain_len >= 0, "remain length must be positive number.");

    // check if buffer should be compact.
    // If true, move the remain bytes into the head of the readbuf.
    if remain_len > 0 {
      unsafe {
        copy_nonoverlapping(
          self.readbuf_ptr.offset(self.consumed_len as isize),
          self.readbuf_ptr,
          remain_len);
      }
    }

    // fill 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 {
    void_ok()
  }

  fn next<'b>(&'b mut self, rowblock: &'b mut BorrowedVRowBlock<'b>) -> TResult<bool> {

    // check if all data are consumed
    if (try!(self.reader.pos()) >= try!(self.reader.len())) {
      rowblock.set_row_num(0);
      return Ok(false); // return false to stop iteration
    }

    let mut row_num: usize = 0; // number of rows which are set to rowblock.
    let mut need_more_rows = true; // indicate whether rowblock is not full or not.
    let mut parse_result: (usize, usize);

    loop { // this loop continues until rowblock is filled or EOS

      if self.line_slices_idx >= self.line_slices_num { // need more line slices
        // compact and fill read buffer
        self.fill_readbuf();
        if self.read_len < 1 { // there is no readable buffer
          break;
        }
        self.fill_line_slices();
      }

      unsafe {
        let mut cur_line_idx = self.line_slices_idx;

        while cur_line_idx < self.line_slices_num && need_more_rows {

          // split each line slice into field slices
          parse_result = split_str_slice(
            &mut self.line_slices[cur_line_idx],
            self.fields_slices,
            self.field_delim
          );

          // the second value of parse result tuple is number of fields
          self.add_row(row_num, parse_result.1);

          cur_line_idx   = cur_line_idx + 1;
          row_num        = row_num + 1;
          need_more_rows = row_num < ROWBLOCK_SIZE;
        }

        // record parsed line index
        self.line_slices_idx = cur_line_idx;
      }

      if !need_more_rows {
        break;
      }
    } // outmost loop

    self.owned_rowblock.set_row_num(row_num);
    copy_vectors(&self.owned_rowblock, rowblock);
    Ok(row_num > 0)
  }

  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";
}

#[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.clone(), None, fin, '\n' as u8);
  assert!(s.init().is_ok());
  let mut rowblock = BorrowedVRowBlock::new(&schema);

  let mut sum = 0;
  while(s.next(&mut rowblock).unwrap()) {
    sum = sum + rowblock.row_num();
    //println!("acc: {}, rows: {}", sum, rowblock.row_num());
  }

  assert_eq!(6001216, sum);
}
  // 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>Fixed wrong import.<commit_after>///
/// Delimited Text Scanner for comma/tab separated value formats
///

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

use common::constant::ROWBLOCK_SIZE;
use common::err::*;
use exec::Executor;
use io::stream::*;
use schema::Schema;
use schema::util::finds_target_indexes;
use rows::{copy_vectors, RowBlock, RowBlockWriter};
use rows::vrows::{BorrowedVRowBlock, HeapVRowBlock};
use types::*;
use util::str::{StrSlice,split_str_slice};

/// default buffer size
const BUF_SIZE: usize = 65536;

pub struct DelimTextScanner<'a> {
  // constants
  data_schema     : Schema,
  read_fields     : Option<Schema>,
  read_fields_idxs: Vec<usize>,

  line_delim  : u8,
  field_delim : u8,

  reader      : Box<StreamReader>,

  // variable
  readbuf_ptr      : *mut u8,           // readbuf
  read_len         : usize,             // length of read bytes
  consumed_len     : usize,             // actually consumed bytes length for line slices

  line_slices_idx  : usize,             // current line slice for reading
  line_slices_num  : usize,             // number of filled line slices
  line_slices_ptr  : *mut StrSlice,     // ptr for line slice array
  line_slices      : &'a mut [StrSlice],// line slice array

  fields_slices_ptr: *mut StrSlice,     // ptr for field slice array
  fields_slices    : &'a mut [StrSlice],// field slice array

  owned_rowblock   : HeapVRowBlock<'a>
}

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

    let read_fields_idxs = match read_fields {
      Some(ref s) => finds_target_indexes(&data_schema, s),
      None        => finds_target_indexes(&data_schema, &data_schema),
    };

    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())
    };

    let rowblock = HeapVRowBlock::new(
      match read_fields {
        Some(ref s) => s,
        None        => &data_schema
      }
    );

    DelimTextScanner {
      data_schema: data_schema,
      read_fields: read_fields,
      read_fields_idxs: read_fields_idxs,

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

      reader: stream,

      readbuf_ptr: unsafe { heap::allocate(BUF_SIZE, 16) },
      consumed_len: 0,
      read_len: 0,

      line_slices_idx: 0,
      line_slices_num: 0,
      line_slices_ptr: line_slices_ptr,
      line_slices: line_slices,

      fields_slices_ptr: fields_slices_ptr,
      fields_slices: fields_slices,

      owned_rowblock: rowblock
    }
  }

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

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

  fn find_first_record_index(&self, bytes: &[u8]) -> Option<usize> {
    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 fill_line_slices(&mut self) {

    let mut line_num: usize = 0;
    let mut last_pos: usize = 0; // keep the start offset
    let mut cur_pos : usize = 0; // the current offset

    while (cur_pos < self.read_len && line_num < ROWBLOCK_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[line_num].set_ptr(unsafe {self.readbuf_ptr.offset(last_pos as isize)});
        self.line_slices[line_num].set_len((cur_pos - last_pos) as i32);

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

      cur_pos = cur_pos + 1;
    }

    self.line_slices_num  = line_num; // read line counter
    self.consumed_len = last_pos;
    self.line_slices_idx = 0;
  }

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

    //self.read_fields_idxs.iter().map(|x| x);

    let mut actual_id: usize;
    for x in 0..self.read_fields_idxs.len() {
      actual_id = self.read_fields_idxs[x];

      match self.data_schema.column(actual_id).data_ty().kind() {
        TyKind::Text => self.owned_rowblock.put_text(row_idx, x, &self.fields_slices[actual_id]),
        _ => {}
      }
    }
  }

  /// move the remain bytes into the header of buffer and fill the buffer.
  fn fill_readbuf(&mut self) -> Void {
    let remain_len = self.read_len - self.consumed_len;
    debug_assert!(remain_len >= 0, "remain length must be positive number.");

    // check if buffer should be compact.
    // If true, move the remain bytes into the head of the readbuf.
    if remain_len > 0 {
      unsafe {
        copy_nonoverlapping(
          self.readbuf_ptr.offset(self.consumed_len as isize),
          self.readbuf_ptr,
          remain_len);
      }
    }

    // fill 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 {
    void_ok()
  }

  fn next<'b>(&'b mut self, rowblock: &'b mut BorrowedVRowBlock<'b>) -> TResult<bool> {

    // check if all data are consumed
    if (try!(self.reader.pos()) >= try!(self.reader.len())) {
      rowblock.set_row_num(0);
      return Ok(false); // return false to stop iteration
    }

    let mut row_num: usize = 0; // number of rows which are set to rowblock.
    let mut need_more_rows = true; // indicate whether rowblock is not full or not.
    let mut parse_result: (usize, usize);

    loop { // this loop continues until rowblock is filled or EOS

      if self.line_slices_idx >= self.line_slices_num { // need more line slices
        // compact and fill read buffer
        self.fill_readbuf();
        if self.read_len < 1 { // there is no readable buffer
          break;
        }
        self.fill_line_slices();
      }

      unsafe {
        let mut cur_line_idx = self.line_slices_idx;

        while cur_line_idx < self.line_slices_num && need_more_rows {

          // split each line slice into field slices
          parse_result = split_str_slice(
            &mut self.line_slices[cur_line_idx],
            self.fields_slices,
            self.field_delim
          );

          // the second value of parse result tuple is number of fields
          self.add_row(row_num, parse_result.1);

          cur_line_idx   = cur_line_idx + 1;
          row_num        = row_num + 1;
          need_more_rows = row_num < ROWBLOCK_SIZE;
        }

        // record parsed line index
        self.line_slices_idx = cur_line_idx;
      }

      if !need_more_rows {
        break;
      }
    } // outmost loop

    self.owned_rowblock.set_row_num(row_num);
    copy_vectors(&self.owned_rowblock, rowblock);
    Ok(row_num > 0)
  }

  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";
}

#[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.clone(), None, fin, '\n' as u8);
  assert!(s.init().is_ok());
  let mut rowblock = BorrowedVRowBlock::new(&schema);

  let mut sum = 0;
  while(s.next(&mut rowblock).unwrap()) {
    sum = sum + rowblock.row_num();
    //println!("acc: {}, rows: {}", sum, rowblock.row_num());
  }

  assert_eq!(6001216, sum);
}
  // 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>extern crate collections;

use std::iter::FlatMap;

struct Forest{
       goats : i32,
       wolves : i32,
       lions : i32
}

/*fn doMeal(x : &Forest) -> Vec<Forest>{
   return vec!([Forest{goats : x.goats -1, wolves : x.wolves -1, lions: x.lions +1},
      Forest{goats : x.goats -1, wolves : x.wolves +1, lions: x.lions -1},
      Forest{goats : x.goats +1, wolves : x.wolves -1, lions: x.lions -1}])
}*/

fn forestStable(forest : &Forest) -> bool {
  if forest.goats == 0{
   return (forest.wolves == 0) || (forest.lions == 0);
  }
  return (forest.wolves == 0) && (forest.lions == 0);
}

fn forestInvalid(forest : &Forest) ->  bool {
  return forest.goats < 0 || forest.wolves < 0 || forest.lions < 0;
}

fn forLessThan(f1: &Forest, f2: &Forest) -> bool{
  let mut res : bool;
  if f1.goats == f2.goats{
    if f1.wolves == f2.wolves {
      if f1.lions == f2.lions {
	res = false;
      }else{
	res = f1.lions < f2.lions;
      }
    }else {
      res = f1.wolves < f2.wolves;
    }
  }else{
    res = f1.goats < f2.goats;
  }
  return res;
}

fn meal(forests: ~[Forest]) -> ~[Forest] {
    let mut mealedForests = Vec::from_fn(forests.len(), |n| Forest{goats : 0, wolves: 0, lions: 0});
    let mut j = 0;
    let mut i = 0;
    while i < forests.len(){
        mealedForests.get(j).goats = forests[i].goats -1;
	mealedForests.get(j).wolves = forests[i].wolves -1;
	mealedForests.get(j).lions = forests[i].lions +1;
	j+=1;
	mealedForests.get(j).goats = forests[i].goats -1;
	mealedForests.get(j).wolves = forests[i].wolves +1;
	mealedForests.get(j).lions = forests[i].lions -1;
	j+=1;
	mealedForests.get(j).goats = forests[i].goats +1;
	mealedForests.get(j).wolves = forests[i].wolves -1;
	mealedForests.get(j).lions = forests[i].lions -1;
	j+=1;
	i+=1;
    }

//  let mut it = forests.iter().flat_map(|&x|[doMeal(x)]);

/*
  return map!(a => [forest_t(-1, -1, +1)+a, forest_t(-1, +1, -1)+a, forest_t(+1, -1, -1)+a])(forests)
    .join
    .partition!(forest_invalid)
    .quickSort
    .uniq.array;*/
}

fn main(){

}<commit_msg>Got Rust implementation working<commit_after>extern crate collections;

use std::cmp::Ordering;
use std::os;

struct Forest{
       goats : i32,
       wolves : i32,
       lions : i32
}

impl Eq for Forest {
    fn eq(&self, other: &Forest) -> bool {
        other.goats == self.goats &&
	other.wolves == self.wolves &&
	other.lions == self.lions}
}

impl Clone for Forest{
    fn clone(&self) -> Forest{
       Forest{goats: self.goats, wolves: self.wolves, lions: self.lions}
    }
}

fn printForest(f : &Forest) {
     print!("Forest [goats= {}, wolves= {}, lions= {}]", f.goats, f.lions, f.wolves);
}

fn printForests(fors : &Vec<Forest>){
   let mut i = 0;
   while i < fors.len(){
   	 printForest(fors.get(i));
	 print!("\n");
	 i+=1;
   }
}

fn forestStable(forest : &Forest) -> bool {
  if forest.goats == 0{
   return (forest.wolves == 0) || (forest.lions == 0);
  }
  return (forest.wolves == 0) && (forest.lions == 0);
}

fn forestInvalid(forest : &Forest) ->  bool {
  return forest.goats < 0 || forest.wolves < 0 || forest.lions < 0;
}

fn forLessThan(f1: &Forest, f2: &Forest) -> Ordering{
  if f1.goats == f2.goats{
    if f1.wolves == f2.wolves {
      if f1.lions == f2.lions {
      	 Equal
      }else{
	f1.lions.cmp(&f2.lions)
      }
    }else {
	f1.wolves.cmp(&f2.wolves)
    }
  }else{
	f1.goats.cmp(&f2.goats)
  }
}

fn meal(forests: &Vec<Forest>) -> Vec<Forest> {
    let mut mealedForests: Vec<Forest> = Vec::with_capacity(forests.len()*3);
    let mut i = 0;
    while i < forests.len() {
    	  let x = &forests.get(i);
    	  mealedForests.push(Forest{goats : x.goats -1, wolves : x.wolves -1, lions: x.lions +1});
    	  mealedForests.push(Forest{goats : x.goats -1, wolves : x.wolves +1, lions: x.lions -1});
    	  mealedForests.push(Forest{goats : x.goats +1, wolves : x.wolves -1, lions: x.lions -1});
	  i+=1;
    }
    let (_, mut okForests) = mealedForests.clone().partition(|a| forestInvalid(a) );
    okForests.sort_by(|a,b| forLessThan(a,b) );
    okForests.dedup();
    return okForests;
}

fn devouringPossible(forests: &Vec<Forest>) -> bool {
  !(forests.len() < 1) && !(forests.iter().any(|x| forestStable(x)))
}

fn stableForests(forests: &Vec<Forest>) -> Vec<Forest> {
    let mut filteredForests: Vec<Forest> = Vec::with_capacity(3);
    let mut i = 0;
    while i < forests.len() {
    	  if forestStable(forests.get(i)){
	     let x = forests.get(i);
	     filteredForests.push(Forest{goats : x.goats, wolves : x.wolves, lions: x.lions});
	  }
	  i+=1;
    }
    filteredForests
}

fn findStableForests(forest: Forest) -> Vec<Forest>{
   let mut forests: Vec<Forest> = Vec::with_capacity(1);
   forests.push(forest);
   while devouringPossible(&forests){
    forests = meal(&forests);
  }
  return stableForests(&forests);
}

fn main(){
   let args = os::args();
   if args.len() != 4{
      print!("Error: input should be in the form of <goats> <wolves> <lions>\n");
      return;
   }
   let initialFor = Forest{goats: std::i32::parse_bytes(args[1].clone().into_bytes(),10).expect("Error: goats not an int.\n"),
       		          wolves: std::i32::parse_bytes(args[2].clone().into_bytes(),10).expect("Error: wolves not an int.\n"),
			  lions:  std::i32::parse_bytes(args[3].clone().into_bytes(),10).expect("Error: lions not an int.\n")};
   let stableFors = findStableForests(initialFor);
   if stableFors.len() < 1 {
      print!("No stable forests found.\n");
   }
   printForests(&stableFors);
}<|endoftext|>


<commit_before>use std::{iter::Peekable, str};

#[derive(Debug, PartialEq, Eq, Hash)]
enum Quotes {
    Single,
    Double,
    None,
}

#[derive(Debug)]
struct EofMatcher {
    eof:       Vec<u8>,
    complete:  bool,
    match_idx: usize,
}

impl EofMatcher {
    fn new() -> Self { EofMatcher { eof: Vec::with_capacity(10), complete: false, match_idx: 0 } }

    #[inline]
    fn next(&mut self, c: u8) -> bool {
        if self.complete && self.eof.get(self.match_idx) == Some(&c) {
            self.match_idx += 1;
        } else if self.complete {
            self.match_idx = 0;
        } else if c == b'\n' {
            self.complete = true;
        } else if !self.eof.is_empty() || !(c as char).is_whitespace() {
            self.eof.push(c);
        }
        self.complete && self.match_idx == self.eof.len()
    }
}

/// Serves as a buffer for storing a string until that string can be terminated.
///
/// # Examples
///
/// This example comes from the shell's REPL, which ensures that the user's input
/// will only be submitted for execution once a terminated command is supplied.
#[derive(Debug)]
pub struct Terminator<I: Iterator<Item = u8>> {
    inner:      RearPeekable<I>,
    eof:        Option<EofMatcher>,
    array:      usize,
    skip_next:  bool,
    quotes:     Quotes,
    terminated: bool,
    and_or:     bool,
    whitespace: bool,
    lt_count:   u8,
    empty:      bool,
}

impl<'a> From<&'a str> for Terminator<std::str::Bytes<'a>> {
    fn from(string: &'a str) -> Self { Terminator::new(string.bytes()) }
}

#[derive(Clone, Debug)]
pub struct RearPeekable<I: Iterator> {
    iter: Peekable<I>,
    now:  Option<I::Item>,
    last: Option<I::Item>,
}

impl<I> Iterator for RearPeekable<I>
where
    I: Iterator,
    I::Item: Copy,
{
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        self.last = self.now;
        self.now = self.iter.next();
        self.now
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

impl<I: Iterator> RearPeekable<I> {
    #[inline]
    pub fn peek(&mut self) -> Option<&I::Item> { self.iter.peek() }

    #[inline]
    pub fn prev(&self) -> Option<&I::Item> { self.last.as_ref() }
}

impl<I: Iterator<Item = u8>> Iterator for Terminator<I> {
    type Item = u8;

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.terminated {
            return None;
        }

        let prev_whitespace = self.whitespace;
        self.whitespace = false;

        let mut next = if prev_whitespace && self.array == 0 && !self.and_or && !self.empty {
            self.inner.find(|&c| c == b'\n' || !c.is_ascii_whitespace())
        } else if prev_whitespace {
            self.inner.find(|&c| !c.is_ascii_whitespace())
        } else {
            self.inner.next()
        };

        if self.skip_next {
            self.skip_next = false;
        } else if let Some(matcher) = self.eof.as_mut() {
            if let Some(character) = next {
                if matcher.next(character) {
                    self.eof = None;
                }
            }
        } else if self.quotes != Quotes::None && next != Some(b'\\') {
            match (next, &self.quotes) {
                (Some(b'\''), Quotes::Single) | (Some(b'"'), Quotes::Double) => {
                    self.quotes = Quotes::None;
                }
                _ => (),
            }
        } else if let Some(character) = next {
            next = self.handle_char(character, prev_whitespace);
            self.empty &= character.is_ascii_whitespace();
        } else if self.array == 0 && !self.and_or && !self.empty {
            self.terminated = true;
        }

        next
    }
}

impl<I: Iterator<Item = u8>> Terminator<I> {
    /// Consumes lines until a statement is formed or the iterator runs dry, and returns the
    /// underlying `String`.
    pub fn terminate(&mut self) -> Option<Result<String, ()>> {
        let stmt = self.collect::<Vec<_>>();
        let stmt = unsafe { String::from_utf8_unchecked(stmt) };

        if self.terminated {
            Some(Ok(stmt))
        } else if self.empty {
            None
        } else {
            Some(Err(()))
        }
    }

    fn handle_char(&mut self, character: u8, prev_whitespace: bool) -> Option<u8> {
        match character {
            b'\'' => {
                self.quotes = Quotes::Single;
                Some(b'\'')
            }
            b'"' => {
                self.quotes = Quotes::Double;
                Some(b'"')
            }
            b'<' => {
                if let Some(&b'<') = self.inner.peek() {
                    self.lt_count += 1;
                } else if self.lt_count == 1 {
                    self.eof = Some(EofMatcher::new());
                    self.lt_count = 0;
                } else {
                    self.lt_count = 0;
                }
                Some(b'<')
            }
            b'[' => {
                self.array += 1;
                Some(b'[')
            }
            b']' => {
                if self.array > 0 {
                    self.array -= 1;
                }
                Some(b']')
            }
            b'#' if prev_whitespace => {
                self.inner.find(|&c| c == b'\n');
                if self.array == 0 && !self.and_or && !self.empty {
                    self.terminated = true;
                    None
                } else {
                    self.whitespace = true;
                    Some(b' ')
                }
            }
            b'\\' => {
                if self.inner.peek() == Some(&b'\n') {
                    self.whitespace = true;
                    self.inner.next();
                    self.next()
                } else {
                    self.skip_next = true;
                    Some(character)
                }
            }
            b'&' | b'|' if self.inner.prev() == Some(&character) => {
                self.and_or = true;
                Some(character)
            }
            b'\n' if self.array == 0 && !self.and_or && !self.empty => {
                self.terminated = true;
                None
            }
            _ if character.is_ascii_whitespace() => {
                self.whitespace = true;
                Some(b' ')
            }
            _ => {
                self.and_or = false;
                Some(character)
            }
        }
    }

    pub fn new(inner: I) -> Terminator<I> {
        Terminator {
            inner:      RearPeekable { iter: inner.peekable(), now: None, last: None },
            eof:        None,
            array:      0,
            skip_next:  false,
            quotes:     Quotes::None,
            terminated: false,
            and_or:     false,
            whitespace: true,
            lt_count:   0,
            empty:      true,
        }
    }
}
<commit_msg>Add support for subshell and ; terminator<commit_after>use std::{iter::Peekable, str};

#[derive(Debug, PartialEq, Eq, Hash)]
enum Quotes {
    Single,
    Double,
    None,
}

#[derive(Debug)]
struct EofMatcher {
    eof:       Vec<u8>,
    complete:  bool,
    match_idx: usize,
}

impl EofMatcher {
    fn new() -> Self { EofMatcher { eof: Vec::with_capacity(10), complete: false, match_idx: 0 } }

    #[inline]
    fn next(&mut self, c: u8) -> bool {
        if self.complete && self.eof.get(self.match_idx) == Some(&c) {
            self.match_idx += 1;
        } else if self.complete {
            self.match_idx = 0;
        } else if c == b'\n' {
            self.complete = true;
        } else if !self.eof.is_empty() || !(c as char).is_whitespace() {
            self.eof.push(c);
        }
        self.complete && self.match_idx == self.eof.len()
    }
}

/// Serves as a buffer for storing a string until that string can be terminated.
///
/// # Examples
///
/// This example comes from the shell's REPL, which ensures that the user's input
/// will only be submitted for execution once a terminated command is supplied.
#[derive(Debug)]
pub struct Terminator<I: Iterator<Item = u8>> {
    inner:      RearPeekable<I>,
    eof:        Option<EofMatcher>,
    array:      usize,
    skip_next:  bool,
    quotes:     Quotes,
    terminated: bool,
    and_or:     bool,
    whitespace: bool,
    lt_count:   u8,
    empty:      bool,
    subshell:   usize,
}

impl<'a> From<&'a str> for Terminator<std::str::Bytes<'a>> {
    fn from(string: &'a str) -> Self { Terminator::new(string.bytes()) }
}

#[derive(Clone, Debug)]
pub struct RearPeekable<I: Iterator> {
    iter: Peekable<I>,
    now:  Option<I::Item>,
    last: Option<I::Item>,
}

impl<I> Iterator for RearPeekable<I>
where
    I: Iterator,
    I::Item: Copy,
{
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        self.last = self.now;
        self.now = self.iter.next();
        self.now
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

impl<I: Iterator> RearPeekable<I> {
    #[inline]
    pub fn peek(&mut self) -> Option<&I::Item> { self.iter.peek() }

    #[inline]
    pub fn prev(&self) -> Option<&I::Item> { self.last.as_ref() }
}

impl<I: Iterator<Item = u8>> Iterator for Terminator<I> {
    type Item = u8;

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.terminated {
            return None;
        }

        let prev_whitespace = self.whitespace;
        self.whitespace = false;

        let mut next = if prev_whitespace && self.array == 0 && !self.and_or && !self.empty {
            self.inner.find(|&c| c == b'\n' || !c.is_ascii_whitespace())
        } else if prev_whitespace {
            self.inner.find(|&c| !c.is_ascii_whitespace())
        } else {
            self.inner.next()
        };

        if self.skip_next {
            self.skip_next = false;
        } else if let Some(matcher) = self.eof.as_mut() {
            if let Some(character) = next {
                if matcher.next(character) {
                    self.eof = None;
                }
            }
        } else if self.quotes != Quotes::None && next != Some(b'\\') {
            match (next, &self.quotes) {
                (Some(b'\''), Quotes::Single) | (Some(b'"'), Quotes::Double) => {
                    self.quotes = Quotes::None;
                }
                _ => (),
            }
        } else if let Some(character) = next {
            next = self.handle_char(character, prev_whitespace);
            self.empty &= character.is_ascii_whitespace();
        } else if self.subshell == 0 && self.array == 0 && !self.and_or && !self.empty {
            self.terminated = true;
        }

        next
    }
}

impl<I: Iterator<Item = u8>> Terminator<I> {
    /// Consumes lines until a statement is formed or the iterator runs dry, and returns the
    /// underlying `String`.
    pub fn terminate(&mut self) -> Option<Result<String, ()>> {
        let stmt = self.collect::<Vec<_>>();
        let stmt = unsafe { String::from_utf8_unchecked(stmt) };

        if self.terminated {
            Some(Ok(stmt))
        } else if self.empty {
            None
        } else {
            Some(Err(()))
        }
    }

    fn handle_char(&mut self, character: u8, prev_whitespace: bool) -> Option<u8> {
        match character {
            b'\'' => {
                self.quotes = Quotes::Single;
                Some(b'\'')
            }
            b'"' => {
                self.quotes = Quotes::Double;
                Some(b'"')
            }
            b'(' if self.inner.prev() == Some(&b'$') || self.inner.prev() == Some(&b'@') => {
                self.subshell += 1;
                Some(b'(')
            }
            b')' if self.subshell > 0 => {
                self.subshell -= 1;
                Some(b')')
            }
            b'<' => {
                if let Some(&b'<') = self.inner.peek() {
                    self.lt_count += 1;
                } else if self.lt_count == 1 {
                    self.eof = Some(EofMatcher::new());
                    self.lt_count = 0;
                } else {
                    self.lt_count = 0;
                }
                Some(b'<')
            }
            b'[' => {
                self.array += 1;
                Some(b'[')
            }
            b']' if self.array > 0 => {
                self.array -= 1;
                Some(b']')
            }
            b'#' if prev_whitespace => {
                self.inner.find(|&c| c == b'\n');
                if self.array == 0 && self.subshell == 0 && !self.and_or && !self.empty {
                    self.terminated = true;
                    None
                } else {
                    self.whitespace = true;
                    Some(b' ')
                }
            }
            b'\\' => {
                if self.inner.peek() == Some(&b'\n') {
                    self.whitespace = true;
                    self.inner.next();
                    self.next()
                } else {
                    self.skip_next = true;
                    Some(character)
                }
            }
            b'&' | b'|' if self.inner.prev() == Some(&character) => {
                self.and_or = true;
                Some(character)
            }
            b'\n' | b';'
                if self.array == 0 && self.subshell == 0 && !self.and_or && !self.empty =>
            {
                self.terminated = true;
                None
            }
            _ if character.is_ascii_whitespace() => {
                self.whitespace = true;
                Some(b' ')
            }
            _ => {
                self.and_or = false;
                Some(character)
            }
        }
    }

    pub fn new(inner: I) -> Terminator<I> {
        Terminator {
            inner:      RearPeekable { iter: inner.peekable(), now: None, last: None },
            eof:        None,
            array:      0,
            skip_next:  false,
            quotes:     Quotes::None,
            terminated: false,
            and_or:     false,
            whitespace: true,
            lt_count:   0,
            empty:      true,
            subshell:   0,
        }
    }
}
<|endoftext|>


<commit_before>use utils::time;
use super::heartbeat_rpc::*;
use super::raft::*;
use super::*;
use raft::{RaftService, LogEntry, RaftMsg, Service as raft_svr_trait};
use raft::state_machine::StateMachineCtl;
use parking_lot::Mutex;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::{thread, time as std_time};
use bifrost_hasher::hash_str;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(BIFROST_MEMBERSHIP_SERVICE) as u64;

static MAX_TIMEOUT: i64 = 5000; //5 secs for 500ms heartbeat

struct HBStatus {
    alive: bool,
    last_updated: i64,
}

pub struct HeartbeatService {
    status: Mutex<HashMap<u64, HBStatus>>,
    raft_service: Arc<RaftService>,
    closed: AtomicBool,
    was_leader: AtomicBool,
}

impl Service for HeartbeatService {
    fn ping(&self, id: u64) -> Result<(), ()> {
        let mut stat_map = self.status.lock();
        let current_time = time::get_time();
        let mut stat = stat_map.entry(id).or_insert_with(|| HBStatus {
            alive: false,
            last_updated: current_time,
            //orthodoxy info will trigger the watcher thread to update
        });
        stat.last_updated = current_time;
        // only update the timestamp, let the watcher thread to decide
        Ok(())
    }
}
impl HeartbeatService {
    fn update_raft(&self, online: Vec<u64>, offline: Vec<u64>) {
        let log = commands::hb_online_changed {
            online: online,
            offline: offline
        };
        let (fn_id, _, data) = log.encode();
        self.raft_service.c_command(LogEntry {
            id: 0,
            term: 0,
            sm_id: DEFAULT_SERVICE_ID,
            fn_id: fn_id,
            data: data
        });
    }
    fn transfer_leadership(&self) { //update timestamp for every alive server
        let mut stat_map = self.status.lock();
        let current_time = time::get_time();
        for stat in stat_map.values_mut() {
            if stat.alive {
                stat.last_updated = current_time;
            }
        }
    }
}
dispatch_rpc_service_functions!(HeartbeatService);

pub struct MemberGroup {
    name: String,
    id: u64,
    members: HashSet<u64>
}

pub struct Membership {
    heartbeat: Arc<HeartbeatService>,
    groups: HashMap<u64, MemberGroup>,
    members: HashMap<u64, Member>
}
impl Drop for Membership {
    fn drop(&mut self) {
        self.heartbeat.closed.store(true, Ordering::Relaxed)
    }
}

impl Membership {
    pub fn new(raft_service: Arc<RaftService>) {
        let service = Arc::new(HeartbeatService {
            status: Mutex::new(HashMap::new()),
            closed: AtomicBool::new(false),
            raft_service: raft_service.clone(),
            was_leader: AtomicBool::new(false),
        });
        let service_clone = service.clone();
        thread::spawn(move || {
            while !service_clone.closed.load(Ordering::Relaxed) {
                let is_leader = service_clone.raft_service.is_leader();
                let was_leader = service_clone.was_leader.load(Ordering::Relaxed);
                if !was_leader && is_leader {service_clone.transfer_leadership()}
                if was_leader != is_leader {service_clone.was_leader.store(is_leader, Ordering::Relaxed);}
                if is_leader {
                    let current_time = time::get_time();
                    let mut outdated_members: Vec<u64> = Vec::new();
                    let mut backedin_members: Vec<u64> = Vec::new();
                    {
                        let mut status_map = service_clone.status.lock();
                        let mut members_to_update: HashMap<u64, bool> = HashMap::new();
                        for (id, status) in status_map.iter() {
                            let alive = (current_time - status.last_updated) < MAX_TIMEOUT;
                            if status.alive && !alive {
                                outdated_members.push(id.clone());
                                members_to_update.insert(id.clone(), alive);
                            }
                            if !status.alive && alive {
                                backedin_members.push(id.clone());
                                members_to_update.insert(id.clone(), alive);
                            }
                        }
                        for (id, alive) in members_to_update.iter() {
                            let mut status = status_map.get_mut(&id).unwrap();
                            status.alive = alive.clone();
                        }

                    }
                    service_clone.update_raft(backedin_members, outdated_members);
                }
                thread::sleep(std_time::Duration::from_secs(1));
            }
        });
        raft_service.register_state_machine(Box::new(Membership {
            heartbeat: service,
            groups: HashMap::new(),
            members: HashMap::new(),
        }))
    }
}

impl StateMachineCmds for Membership {
    fn hb_online_changed(&mut self, online: Vec<u64>, offline: Vec<u64>) -> Result<(), ()> {
        let mut stat_map = self.heartbeat.status.lock();
        for id in online {
            if let Some(ref mut stat) = stat_map.get_mut(&id) {
                stat.alive = true;
            }
        }
        for id in offline {
            if let Some(ref mut stat) = stat_map.get_mut(&id) {
                stat.alive = false;
            }
        }
        Ok(())
    }
    fn join(&mut self, address: String) -> Result<u64, ()> {
        let id = hash_str(address.clone());
        let mut stat_map = self.heartbeat.status.lock();
        self.members.entry(id).or_insert_with(|| {
            let current_time = time::get_time();
            let mut stat = stat_map.entry(id).or_insert_with(|| HBStatus {
                alive: true,
                last_updated: current_time
            });
            stat.alive = true;
            stat.last_updated = current_time;
            Member {
                id: id,
                address: address.clone(),
                groups: Vec::new(),
            }
        });
        Ok(id)
    }
    fn leave(&mut self, id: u64) -> Result<(), ()> {
        let mut stat_map = self.heartbeat.status.lock();
        let mut groups:Vec<u64> = Vec::new();
        if let Some(member) = self.members.get(&id) {
            for group in &member.groups {
                groups.push(group.clone());
            }
        }
        for group_id in groups {
            if let Some(ref mut group) = self.groups.get_mut(&group_id) {
                group.members.remove(&id);
            }
        }
        stat_map.remove(&id);
        self.members.remove(&id);
        Err(())
    }
    fn join_group(&mut self, group: u64, id: u64) -> Result<(), ()> {
        Err(())
    }
    fn leave_group(&mut self, group: u64, id: u64) -> Result<(), ()> {
    Err(())
}
    fn members(&self, group: u64) -> Result<Vec<Member>, ()> {
        Err(())
    }
    fn leader(&self, group: u64) -> Result<Member, ()> {
        Err(())
    }
    fn group_members(&self, group: u64) -> Result<Vec<Member>, ()> {
        Err(())
    }
    fn all_members(&self) -> Result<Vec<Member>, ()> {
        Err(())
    }
}
impl StateMachineCtl for Membership {
    sm_complete!();
    fn snapshot(&self) -> Option<Vec<u8>> {
        //Some(serialize!(&self.map))
        None // TODO: Backup members
    }
    fn recover(&mut self, data: Vec<u8>) {
        //self.map = deserialize!(&data);
    }
    fn id(&self) -> u64 {DEFAULT_SERVICE_ID}
}<commit_msg>join and leave groups<commit_after>use utils::time;
use super::heartbeat_rpc::*;
use super::raft::*;
use super::*;
use raft::{RaftService, LogEntry, RaftMsg, Service as raft_svr_trait};
use raft::state_machine::StateMachineCtl;
use parking_lot::Mutex;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::{thread, time as std_time};
use bifrost_hasher::hash_str;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(BIFROST_MEMBERSHIP_SERVICE) as u64;

static MAX_TIMEOUT: i64 = 5000; //5 secs for 500ms heartbeat

struct HBStatus {
    alive: bool,
    last_updated: i64,
}

pub struct HeartbeatService {
    status: Mutex<HashMap<u64, HBStatus>>,
    raft_service: Arc<RaftService>,
    closed: AtomicBool,
    was_leader: AtomicBool,
}

impl Service for HeartbeatService {
    fn ping(&self, id: u64) -> Result<(), ()> {
        let mut stat_map = self.status.lock();
        let current_time = time::get_time();
        let mut stat = stat_map.entry(id).or_insert_with(|| HBStatus {
            alive: false,
            last_updated: current_time,
            //orthodoxy info will trigger the watcher thread to update
        });
        stat.last_updated = current_time;
        // only update the timestamp, let the watcher thread to decide
        Ok(())
    }
}
impl HeartbeatService {
    fn update_raft(&self, online: Vec<u64>, offline: Vec<u64>) {
        let log = commands::hb_online_changed {
            online: online,
            offline: offline
        };
        let (fn_id, _, data) = log.encode();
        self.raft_service.c_command(LogEntry {
            id: 0,
            term: 0,
            sm_id: DEFAULT_SERVICE_ID,
            fn_id: fn_id,
            data: data
        });
    }
    fn transfer_leadership(&self) { //update timestamp for every alive server
        let mut stat_map = self.status.lock();
        let current_time = time::get_time();
        for stat in stat_map.values_mut() {
            if stat.alive {
                stat.last_updated = current_time;
            }
        }
    }
}
dispatch_rpc_service_functions!(HeartbeatService);

pub struct MemberGroup {
    name: String,
    id: u64,
    members: HashSet<u64>
}

pub struct Membership {
    heartbeat: Arc<HeartbeatService>,
    groups: HashMap<u64, MemberGroup>,
    members: HashMap<u64, Member>
}
impl Drop for Membership {
    fn drop(&mut self) {
        self.heartbeat.closed.store(true, Ordering::Relaxed)
    }
}

impl Membership {
    pub fn new(raft_service: Arc<RaftService>) {
        let service = Arc::new(HeartbeatService {
            status: Mutex::new(HashMap::new()),
            closed: AtomicBool::new(false),
            raft_service: raft_service.clone(),
            was_leader: AtomicBool::new(false),
        });
        let service_clone = service.clone();
        thread::spawn(move || {
            while !service_clone.closed.load(Ordering::Relaxed) {
                let is_leader = service_clone.raft_service.is_leader();
                let was_leader = service_clone.was_leader.load(Ordering::Relaxed);
                if !was_leader && is_leader {service_clone.transfer_leadership()}
                if was_leader != is_leader {service_clone.was_leader.store(is_leader, Ordering::Relaxed);}
                if is_leader {
                    let current_time = time::get_time();
                    let mut outdated_members: Vec<u64> = Vec::new();
                    let mut backedin_members: Vec<u64> = Vec::new();
                    {
                        let mut status_map = service_clone.status.lock();
                        let mut members_to_update: HashMap<u64, bool> = HashMap::new();
                        for (id, status) in status_map.iter() {
                            let alive = (current_time - status.last_updated) < MAX_TIMEOUT;
                            if status.alive && !alive {
                                outdated_members.push(id.clone());
                                members_to_update.insert(id.clone(), alive);
                            }
                            if !status.alive && alive {
                                backedin_members.push(id.clone());
                                members_to_update.insert(id.clone(), alive);
                            }
                        }
                        for (id, alive) in members_to_update.iter() {
                            let mut status = status_map.get_mut(&id).unwrap();
                            status.alive = alive.clone();
                        }

                    }
                    service_clone.update_raft(backedin_members, outdated_members);
                }
                thread::sleep(std_time::Duration::from_secs(1));
            }
        });
        raft_service.register_state_machine(Box::new(Membership {
            heartbeat: service,
            groups: HashMap::new(),
            members: HashMap::new(),
        }))
    }
}

impl StateMachineCmds for Membership {
    fn hb_online_changed(&mut self, online: Vec<u64>, offline: Vec<u64>) -> Result<(), ()> {
        let mut stat_map = self.heartbeat.status.lock();
        for id in online {
            if let Some(ref mut stat) = stat_map.get_mut(&id) {
                stat.alive = true;
            }
        }
        for id in offline {
            if let Some(ref mut stat) = stat_map.get_mut(&id) {
                stat.alive = false;
            }
        }
        Ok(())
    }
    fn join(&mut self, address: String) -> Result<u64, ()> {
        let id = hash_str(address.clone());
        let mut stat_map = self.heartbeat.status.lock();
        self.members.entry(id).or_insert_with(|| {
            let current_time = time::get_time();
            let mut stat = stat_map.entry(id).or_insert_with(|| HBStatus {
                alive: true,
                last_updated: current_time
            });
            stat.alive = true;
            stat.last_updated = current_time;
            Member {
                id: id,
                address: address.clone(),
                groups: Vec::new(),
            }
        });
        Ok(id)
    }
    fn leave(&mut self, id: u64) -> Result<(), ()> {
        let mut groups:Vec<u64> = Vec::new();
        {
            let mut stat_map = self.heartbeat.status.lock();
            stat_map.remove(&id);
        }
        if let Some(member) = self.members.get(&id) {
            for group in &member.groups {
                groups.push(group.clone());
            }
        }
        for group_id in groups {
            self.leave_group(group_id, id);
        }
        self.members.remove(&id);
        Ok(())
    }
    fn join_group(&mut self, group: u64, id: u64) -> Result<(), ()> {
        if let Some(ref mut group) = self.groups.get_mut(&group) {
            group.members.insert(id);
            Ok(())
        } else {
            Err(())
        }
    }
    fn leave_group(&mut self, group: u64, id: u64) -> Result<(), ()> {
        if let Some(ref mut group) = self.groups.get_mut(&group) {
            group.members.remove(&id);
            Ok(())
        } else {
            Err(())
        }
    }
    fn members(&self, group: u64) -> Result<Vec<Member>, ()> {
        Err(())
    }
    fn leader(&self, group: u64) -> Result<Member, ()> {
        Err(())
    }
    fn group_members(&self, group: u64) -> Result<Vec<Member>, ()> {
        Err(())
    }
    fn all_members(&self) -> Result<Vec<Member>, ()> {
        Err(())
    }
}
impl StateMachineCtl for Membership {
    sm_complete!();
    fn snapshot(&self) -> Option<Vec<u8>> {
        //Some(serialize!(&self.map))
        None // TODO: Backup members
    }
    fn recover(&mut self, data: Vec<u8>) {
        //self.map = deserialize!(&data);
    }
    fn id(&self) -> u64 {DEFAULT_SERVICE_ID}
}<|endoftext|>


<commit_before>use std::io;
use std::u32;
use std::fs::File;

use utility::{ErrorKind, ReadStream, many_metadata};

use metadata::{
  Metadata, Data,
  StreamInfo, CueSheet, VorbisComment, Picture,
  PictureType,
};

// Will return true when the unwrapped value of `option` and `other` match
// or `option` is `Option::None`, otherwise false.
#[inline]
pub fn optional_eq<T: Eq>(option: Option<T>, other: T) -> bool {
  option.map_or(true, |value| value == other)
}

// With the given filename, return all metadata blocks available.
//
// This function expects a flac file, but will return a proper `Result::Err`
// when things go wrong.
//
// # Failures
//
// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
//   filename isn't found.
// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
//   within the file isn't valid FLAC data.
pub fn get_metadata(filename: &str) -> Result<Vec<Metadata>, ErrorKind> {
  File::open(filename).map_err(|e| ErrorKind::IO(e.kind()))
                      .and_then(|file| {
    let mut stream   = ReadStream::new(file);
    let mut metadata = Vec::new();

    let result = many_metadata(&mut stream, |block| metadata.push(block));

    if let Err(kind) = result {
      match kind {
        ErrorKind::HeaderParser |
        ErrorKind::Unknown      => Err(ErrorKind::IO(
                                     io::ErrorKind::InvalidData)),
        _                       => Err(kind),
      }
    } else {
      Ok(metadata)
    }
  })
}

/// Reads and returns the `StreamInfo` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
///   filename isn't found.
/// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
///   within the file isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_stream_info("path/to/file.flac") {
///   Ok(stream_info) => {
///     // Use the stream_info variable...
///   }
///   Err(error)      => println!("{:?}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let stream_info = metadata::get_stream_info("path/to/file.flac").unwrap();
/// ```
pub fn get_stream_info(filename: &str) -> Result<StreamInfo, ErrorKind> {
  get_metadata(filename).and_then(|blocks| {
    let mut result = Err(ErrorKind::NotFound);

    for block in blocks {
      if let Data::StreamInfo(stream_info) = block.data {
        result = Ok(stream_info);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `VorbisComment` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
///   filename isn't found.
/// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
///   within the file isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_vorbis_comment("path/to/file.flac") {
///   Ok(vorbis_comment) => {
///     // Use the vorbis_comment variable...
///   }
///   Err(error)         => println!("{:?}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let vorbis_comment =
///   metadata::get_vorbis_comment("path/to/file.flac").unwrap();
/// ```
pub fn get_vorbis_comment(filename: &str)
                          -> Result<VorbisComment, ErrorKind> {
  get_metadata(filename).and_then(|blocks| {
    let mut result = Err(ErrorKind::NotFound);

    for block in blocks {
      if let Data::VorbisComment(vorbis_comment) = block.data {
        result = Ok(vorbis_comment);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `CueSheet` metadata block of the given FLAC file.
///
/// # Failures
///
/// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
///   filename isn't found.
/// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
///   within the file isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_cue_sheet("path/to/file.flac") {
///   Ok(cue_sheet) => {
///     // Use the cue_sheet variable...
///   }
///   Err(error)    => println!("{:?}", error),
/// }
/// ```
///
/// Or just ignore the errors
///
/// ```no_run
/// use flac::metadata;
///
/// let cue_sheet = metadata::get_cue_sheet("path/to/file.flac").unwrap();
/// ```
pub fn get_cue_sheet(filename: &str) -> Result<CueSheet, ErrorKind> {
  get_metadata(filename).and_then(|blocks| {
    let mut result = Err(ErrorKind::NotFound);

    for block in blocks {
      if let Data::CueSheet(cue_sheet) = block.data {
        result = Ok(cue_sheet);
        break;
      }
    }

    result
  })
}

/// Reads and returns a `Picture` metadata block of the given FLAC file.
///
/// There can be more than one `Picture` block in a file and this function
/// takes optional, that being `Option<T>`, parameters that act as
/// constraints to search within. The `Picture` with the largest area
/// matching all constraints will be returned.
///
/// Putting `None` into any of the optional constraints conveys that you
/// want any of that parameter. Otherwise it will try to look for the image
/// that matches within the given constraints.
///
/// # Failures
///
/// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
///   filename isn't found.
/// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
///   within the file isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let result = metadata::get_picture("path/to/file.flac",
///                                    Some(PictureType::FileIcon),
///                                    Some("image/gif"),
///                                    None, None, None,
///                                    None, None);
///
/// match result {
///   Ok(picture) => {
///     // Use the picture variable...
///   }
///   Err(error)  => println!("{:?}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let picture = metadata::get_picture("path/to/file.flac",
///                                     Some(PictureType::FileIcon),
///                                     Some("image/gif"),
///                                     None, None, None,
///                                     None, None).unwrap();
/// ```
pub fn get_picture(filename: &str,
                   picture_type: Option<PictureType>,
                   mime_type: Option<&str>,
                   description: Option<&str>,
                   max_width: Option<u32>,
                   max_height: Option<u32>,
                   max_depth: Option<u32>,
                   max_colors: Option<u32>)
                   -> Result<Picture, ErrorKind> {
  get_metadata(filename).and_then(|blocks| {
    let mut result = Err(ErrorKind::NotFound);

    let mut max_area_seen  = 0;
    let mut max_depth_seen = 0;

    let max_value      = u32::max_value();
    let max_width_num  = max_width.unwrap_or(max_value);
    let max_height_num = max_height.unwrap_or(max_value);
    let max_depth_num  = max_depth.unwrap_or(max_value);
    let max_colors_num = max_colors.unwrap_or(max_value);

    for block in blocks {
      if let Data::Picture(picture) = block.data {
        let area = (picture.width as u64) * (picture.height as u64);

        if optional_eq(picture_type, picture.picture_type) &&
           optional_eq(mime_type, &picture.mime_type) &&
           optional_eq(description, &picture.description) &&
           picture.width <= max_width_num &&
           picture.height <= max_height_num &&
           picture.depth <= max_depth_num &&
           picture.colors <= max_colors_num &&
           (area > max_area_seen || (area == max_area_seen &&
                                     picture.depth > max_depth_seen)) {
          max_area_seen  = area;
          max_depth_seen = picture.depth;
          result         = Ok(picture);
        }
      }
    }

    result
  })
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::io;

  use utility::ErrorKind;

  #[test]
  #[should_panic]
  fn test_panic_optional_eq() {
    assert!(optional_eq(Some(1), 0));
  }

  #[test]
  fn test_optional_eq() {
    assert!(optional_eq(None, 0), "Should always return true when None");
    assert!(optional_eq(Some(0), 0), "Should return true (Some(0) == 0)");
  }

  #[test]
  fn test_get_metadata() {
    let not_found    = get_metadata("non-existent/file.txt");
    let invalid_data = get_metadata("README.md");
    let result       = get_metadata("tests/assets/input-SVAUP.flac");

    assert_eq!(not_found.unwrap_err(), ErrorKind::IO(
                                         io::ErrorKind::NotFound));
    assert_eq!(invalid_data.unwrap_err(), ErrorKind::IO(
                                            io::ErrorKind::InvalidData));
    assert!(result.is_ok());
  }
}
<commit_msg>Add `ErrorKind` specific for not finding metadata<commit_after>use std::io;
use std::u32;
use std::fs::File;

use utility::{ErrorKind, ReadStream, many_metadata};

use metadata::{
  Metadata, Data,
  StreamInfo, CueSheet, VorbisComment, Picture,
  PictureType,
};

// Will return true when the unwrapped value of `option` and `other` match
// or `option` is `Option::None`, otherwise false.
#[inline]
pub fn optional_eq<T: Eq>(option: Option<T>, other: T) -> bool {
  option.map_or(true, |value| value == other)
}

// With the given filename, return all metadata blocks available.
//
// This function expects a flac file, but will return a proper `Result::Err`
// when things go wrong.
//
// # Failures
//
// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
//   filename isn't found.
// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
//   within the file isn't valid FLAC data.
pub fn get_metadata(filename: &str) -> Result<Vec<Metadata>, ErrorKind> {
  File::open(filename).map_err(|e| ErrorKind::IO(e.kind()))
                      .and_then(|file| {
    let mut stream   = ReadStream::new(file);
    let mut metadata = Vec::new();

    let result = many_metadata(&mut stream, |block| metadata.push(block));

    if let Err(kind) = result {
      match kind {
        ErrorKind::HeaderParser |
        ErrorKind::Unknown      => Err(ErrorKind::IO(
                                     io::ErrorKind::InvalidData)),
        _                       => Err(kind),
      }
    } else {
      Ok(metadata)
    }
  })
}

/// Reads and returns the `StreamInfo` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the there is no `StreamInfo`
///   within the file.
/// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
///   filename isn't found.
/// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
///   within the file isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_stream_info("path/to/file.flac") {
///   Ok(stream_info) => {
///     // Use the stream_info variable...
///   }
///   Err(error)      => println!("{:?}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let stream_info = metadata::get_stream_info("path/to/file.flac").unwrap();
/// ```
pub fn get_stream_info(filename: &str) -> Result<StreamInfo, ErrorKind> {
  get_metadata(filename).and_then(|blocks| {
    let mut result = Err(ErrorKind::NotFound);

    for block in blocks {
      if let Data::StreamInfo(stream_info) = block.data {
        result = Ok(stream_info);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `VorbisComment` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the there is no `VorbisComment`
///   within the file.
/// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
///   filename isn't found.
/// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
///   within the file isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_vorbis_comment("path/to/file.flac") {
///   Ok(vorbis_comment) => {
///     // Use the vorbis_comment variable...
///   }
///   Err(error)         => println!("{:?}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let vorbis_comment =
///   metadata::get_vorbis_comment("path/to/file.flac").unwrap();
/// ```
pub fn get_vorbis_comment(filename: &str)
                          -> Result<VorbisComment, ErrorKind> {
  get_metadata(filename).and_then(|blocks| {
    let mut result = Err(ErrorKind::NotFound);

    for block in blocks {
      if let Data::VorbisComment(vorbis_comment) = block.data {
        result = Ok(vorbis_comment);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `CueSheet` metadata block of the given FLAC file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the there is no `CueSheet`
///   within the file.
/// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
///   filename isn't found.
/// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
///   within the file isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_cue_sheet("path/to/file.flac") {
///   Ok(cue_sheet) => {
///     // Use the cue_sheet variable...
///   }
///   Err(error)    => println!("{:?}", error),
/// }
/// ```
///
/// Or just ignore the errors
///
/// ```no_run
/// use flac::metadata;
///
/// let cue_sheet = metadata::get_cue_sheet("path/to/file.flac").unwrap();
/// ```
pub fn get_cue_sheet(filename: &str) -> Result<CueSheet, ErrorKind> {
  get_metadata(filename).and_then(|blocks| {
    let mut result = Err(ErrorKind::NotFound);

    for block in blocks {
      if let Data::CueSheet(cue_sheet) = block.data {
        result = Ok(cue_sheet);
        break;
      }
    }

    result
  })
}

/// Reads and returns a `Picture` metadata block of the given FLAC file.
///
/// There can be more than one `Picture` block in a file and this function
/// takes optional, that being `Option<T>`, parameters that act as
/// constraints to search within. The `Picture` with the largest area
/// matching all constraints will be returned.
///
/// Putting `None` into any of the optional constraints conveys that you
/// want any of that parameter. Otherwise it will try to look for the image
/// that matches within the given constraints.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the there is no `Picture`
///   within the file, or no `Picture` that fits the given constraints.
/// * `ErrorKind::IO(io::ErrorKind::NotFound)` is returned when the given
///   filename isn't found.
/// * `ErrorKind::IO(io::ErrorKind::InvalidData)` is returned when the data
///   within the file isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let result = metadata::get_picture("path/to/file.flac",
///                                    Some(PictureType::FileIcon),
///                                    Some("image/gif"),
///                                    None, None, None,
///                                    None, None);
///
/// match result {
///   Ok(picture) => {
///     // Use the picture variable...
///   }
///   Err(error)  => println!("{:?}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let picture = metadata::get_picture("path/to/file.flac",
///                                     Some(PictureType::FileIcon),
///                                     Some("image/gif"),
///                                     None, None, None,
///                                     None, None).unwrap();
/// ```
pub fn get_picture(filename: &str,
                   picture_type: Option<PictureType>,
                   mime_type: Option<&str>,
                   description: Option<&str>,
                   max_width: Option<u32>,
                   max_height: Option<u32>,
                   max_depth: Option<u32>,
                   max_colors: Option<u32>)
                   -> Result<Picture, ErrorKind> {
  get_metadata(filename).and_then(|blocks| {
    let mut result = Err(ErrorKind::NotFound);

    let mut max_area_seen  = 0;
    let mut max_depth_seen = 0;

    let max_value      = u32::max_value();
    let max_width_num  = max_width.unwrap_or(max_value);
    let max_height_num = max_height.unwrap_or(max_value);
    let max_depth_num  = max_depth.unwrap_or(max_value);
    let max_colors_num = max_colors.unwrap_or(max_value);

    for block in blocks {
      if let Data::Picture(picture) = block.data {
        let area = (picture.width as u64) * (picture.height as u64);

        if optional_eq(picture_type, picture.picture_type) &&
           optional_eq(mime_type, &picture.mime_type) &&
           optional_eq(description, &picture.description) &&
           picture.width <= max_width_num &&
           picture.height <= max_height_num &&
           picture.depth <= max_depth_num &&
           picture.colors <= max_colors_num &&
           (area > max_area_seen || (area == max_area_seen &&
                                     picture.depth > max_depth_seen)) {
          max_area_seen  = area;
          max_depth_seen = picture.depth;
          result         = Ok(picture);
        }
      }
    }

    result
  })
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::io;

  use utility::ErrorKind;

  #[test]
  #[should_panic]
  fn test_panic_optional_eq() {
    assert!(optional_eq(Some(1), 0));
  }

  #[test]
  fn test_optional_eq() {
    assert!(optional_eq(None, 0), "Should always return true when None");
    assert!(optional_eq(Some(0), 0), "Should return true (Some(0) == 0)");
  }

  #[test]
  fn test_get_metadata() {
    let not_found    = get_metadata("non-existent/file.txt");
    let invalid_data = get_metadata("README.md");
    let result       = get_metadata("tests/assets/input-SVAUP.flac");

    assert_eq!(not_found.unwrap_err(), ErrorKind::IO(
                                         io::ErrorKind::NotFound));
    assert_eq!(invalid_data.unwrap_err(), ErrorKind::IO(
                                            io::ErrorKind::InvalidData));
    assert!(result.is_ok());
  }
}
<|endoftext|>


<commit_before>use std::io::{self, Error, Result};
use std::u32;
use std::fs::File;

use utility::{ReadStream, many_metadata};

use metadata::{
  Metadata, Data,
  StreamInfo, CueSheet, VorbisComment, Picture,
  PictureType,
};

// Will return true when the unwrapped value of `option` and `other` match
// or `option` is `Option::None`, otherwise false.
#[inline]
pub fn optional_eq<T: Eq>(option: Option<T>, other: T) -> bool {
  option.map_or(true, |value| value == other)
}

// With the given filename, return all metadata blocks available.
//
// This function expects a flac file, but will return a proper `Result::Err`
// when things go wrong.
//
// # Failures
//
// * `ErrorKind::NotFound` is returned when the given filename isn't found.
// * `ErrorKind::InvalidData` is returned when the data within the file
//   isn't valid FLAC data.
pub fn get_metadata(filename: &str) -> Result<Vec<Metadata>> {
  File::open(filename).and_then(|file| {
    let mut stream   = ReadStream::new(file);
    let mut metadata = Vec::new();

    let is_error = many_metadata(&mut stream, |block| metadata.push(block));

    if is_error {
      let error_str = "parser: couldn't find any metadata";

      Err(Error::new(io::ErrorKind::InvalidData, error_str))
    } else {
      Ok(metadata)
    }
  })
}

/// Reads and returns the `StreamInfo` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `StreamInfo` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_stream_info("path/to/file.flac") {
///   Ok(stream_info) => {
///     // Use the stream_info variable...
///   }
///   Err(error)      => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let stream_info = metadata::get_stream_info("path/to/file.flac").unwrap();
/// ```
pub fn get_stream_info(filename: &str) -> Result<StreamInfo> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find StreamInfo";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::StreamInfo(stream_info) = block.data {
        result = Ok(stream_info);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `VorbisComment` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `VorbisComment` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_vorbis_comment("path/to/file.flac") {
///   Ok(vorbis_comment) => {
///     // Use the vorbis_comment variable...
///   }
///   Err(error)         => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let vorbis_comment =
///   metadata::get_vorbis_comment("path/to/file.flac").unwrap();
/// ```
pub fn get_vorbis_comment(filename: &str) -> Result<VorbisComment> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find VorbisComment";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::VorbisComment(vorbis_comment) = block.data {
        result = Ok(vorbis_comment);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `CueSheet` metadata block of the given FLAC file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `CueSheet` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_cue_sheet("path/to/file.flac") {
///   Ok(cue_sheet) => {
///     // Use the cue_sheet variable...
///   }
///   Err(error)    => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors
///
/// ```no_run
/// use flac::metadata;
///
/// let cue_sheet = metadata::get_cue_sheet("path/to/file.flac").unwrap();
/// ```
pub fn get_cue_sheet(filename: &str) -> Result<CueSheet> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find CueSheet";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::CueSheet(cue_sheet) = block.data {
        result = Ok(cue_sheet);
        break;
      }
    }

    result
  })
}

/// Reads and returns a `Picture` metadata block of the given FLAC file.
///
/// There can be more than one `Picture` block in a file and this function
/// takes optional, that being `Option<T>`, parameters that act as
/// constraints to search within. The `Picture` with the largest area
/// matching all constraints will be returned.
///
/// Putting `None` into any of the optional constraints conveys that you
/// want any of that parameter. Otherwise it will try to look for the image
/// that matches within the given constraints.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found,
///   there is no `Picture` within the file, or no `Picture` that fits the
///   given constraints.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let result = metadata::get_picture("path/to/file.flac",
///                                    Some(PictureType::FileIcon),
///                                    Some("image/gif"),
///                                    None, None, None,
///                                    None, None);
///
/// match result {
///   Ok(picture) => {
///     // Use the picture variable...
///   }
///   Err(error)  => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let picture = metadata::get_picture("path/to/file.flac",
///                                     Some(PictureType::FileIcon),
///                                     Some("image/gif"),
///                                     None, None, None,
///                                     None, None).unwrap();
/// ```
pub fn get_picture(filename: &str,
                   picture_type: Option<PictureType>,
                   mime_type: Option<&str>,
                   description: Option<&str>,
                   max_width: Option<u32>,
                   max_height: Option<u32>,
                   max_depth: Option<u32>,
                   max_colors: Option<u32>)
                   -> Result<Picture> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find any Picture";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    let mut max_area_seen  = 0;
    let mut max_depth_seen = 0;

    let max_value      = u32::max_value();
    let max_width_num  = max_width.unwrap_or(max_value);
    let max_height_num = max_height.unwrap_or(max_value);
    let max_depth_num  = max_depth.unwrap_or(max_value);
    let max_colors_num = max_colors.unwrap_or(max_value);

    for block in blocks {
      if let Data::Picture(picture) = block.data {
        let area = (picture.width as u64) * (picture.height as u64);

        if optional_eq(picture_type, picture.picture_type) &&
           optional_eq(mime_type, &picture.mime_type) &&
           optional_eq(description, &picture.description) &&
           picture.width <= max_width_num &&
           picture.height <= max_height_num &&
           picture.depth <= max_depth_num &&
           picture.colors <= max_colors_num &&
           (area > max_area_seen || (area == max_area_seen &&
                                     picture.depth > max_depth_seen)) {
          max_area_seen  = area;
          max_depth_seen = picture.depth;
          result         = Ok(picture);
        }
      }
    }

    result
  })
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::io::ErrorKind;

  #[test]
  #[should_panic]
  fn test_panic_optional_eq() {
    assert!(optional_eq(Some(1), 0));
  }

  #[test]
  fn test_optional_eq() {
    assert!(optional_eq(None, 0), "Should always return true when None");
    assert!(optional_eq(Some(0), 0), "Should return true (Some(0) == 0)");
  }

  #[test]
  fn test_get_metadata() {
    let not_found    = get_metadata("non-existent/file.txt");
    let invalid_data = get_metadata("README.md");
    let result       = get_metadata("tests/assets/input-SVAUP.flac");

    assert_eq!(not_found.unwrap_err().kind(), ErrorKind::NotFound);
    assert_eq!(invalid_data.unwrap_err().kind(), ErrorKind::InvalidData);
    assert!(result.is_ok());
  }
}
<commit_msg>Change the base `get_metadata` to return ErrorKind<commit_after>use std::io;
use std::u32;
use std::fs::File;

use utility::{ErrorKind, ReadStream, many_metadata};

use metadata::{
  Metadata, Data,
  StreamInfo, CueSheet, VorbisComment, Picture,
  PictureType,
};

// Will return true when the unwrapped value of `option` and `other` match
// or `option` is `Option::None`, otherwise false.
#[inline]
pub fn optional_eq<T: Eq>(option: Option<T>, other: T) -> bool {
  option.map_or(true, |value| value == other)
}

// With the given filename, return all metadata blocks available.
//
// This function expects a flac file, but will return a proper `Result::Err`
// when things go wrong.
//
// # Failures
//
// * `ErrorKind::NotFound` is returned when the given filename isn't found.
// * `ErrorKind::InvalidData` is returned when the data within the file
//   isn't valid FLAC data.
pub fn get_metadata(filename: &str) -> Result<Vec<Metadata>, ErrorKind> {
  File::open(filename).map_err(|e| ErrorKind::IO(e.kind()))
                      .and_then(|file| {
    let mut stream   = ReadStream::new(file);
    let mut metadata = Vec::new();

    let result = many_metadata(&mut stream, |block| metadata.push(block));

    if let Err(kind) = result {
      match kind {
        ErrorKind::HeaderParser |
        ErrorKind::Unknown      => Err(ErrorKind::IO(
                                     io::ErrorKind::InvalidData)),
        _                       => Err(kind),
      }
    } else {
      Ok(metadata)
    }
  })
}

/// Reads and returns the `StreamInfo` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `StreamInfo` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_stream_info("path/to/file.flac") {
///   Ok(stream_info) => {
///     // Use the stream_info variable...
///   }
///   Err(error)      => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let stream_info = metadata::get_stream_info("path/to/file.flac").unwrap();
/// ```
pub fn get_stream_info(filename: &str) -> Result<StreamInfo> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find StreamInfo";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::StreamInfo(stream_info) = block.data {
        result = Ok(stream_info);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `VorbisComment` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `VorbisComment` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_vorbis_comment("path/to/file.flac") {
///   Ok(vorbis_comment) => {
///     // Use the vorbis_comment variable...
///   }
///   Err(error)         => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let vorbis_comment =
///   metadata::get_vorbis_comment("path/to/file.flac").unwrap();
/// ```
pub fn get_vorbis_comment(filename: &str) -> Result<VorbisComment> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find VorbisComment";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::VorbisComment(vorbis_comment) = block.data {
        result = Ok(vorbis_comment);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `CueSheet` metadata block of the given FLAC file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `CueSheet` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_cue_sheet("path/to/file.flac") {
///   Ok(cue_sheet) => {
///     // Use the cue_sheet variable...
///   }
///   Err(error)    => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors
///
/// ```no_run
/// use flac::metadata;
///
/// let cue_sheet = metadata::get_cue_sheet("path/to/file.flac").unwrap();
/// ```
pub fn get_cue_sheet(filename: &str) -> Result<CueSheet> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find CueSheet";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    for block in blocks {
      if let Data::CueSheet(cue_sheet) = block.data {
        result = Ok(cue_sheet);
        break;
      }
    }

    result
  })
}

/// Reads and returns a `Picture` metadata block of the given FLAC file.
///
/// There can be more than one `Picture` block in a file and this function
/// takes optional, that being `Option<T>`, parameters that act as
/// constraints to search within. The `Picture` with the largest area
/// matching all constraints will be returned.
///
/// Putting `None` into any of the optional constraints conveys that you
/// want any of that parameter. Otherwise it will try to look for the image
/// that matches within the given constraints.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found,
///   there is no `Picture` within the file, or no `Picture` that fits the
///   given constraints.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let result = metadata::get_picture("path/to/file.flac",
///                                    Some(PictureType::FileIcon),
///                                    Some("image/gif"),
///                                    None, None, None,
///                                    None, None);
///
/// match result {
///   Ok(picture) => {
///     // Use the picture variable...
///   }
///   Err(error)  => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
/// use flac::metadata::PictureType;
///
/// let picture = metadata::get_picture("path/to/file.flac",
///                                     Some(PictureType::FileIcon),
///                                     Some("image/gif"),
///                                     None, None, None,
///                                     None, None).unwrap();
/// ```
pub fn get_picture(filename: &str,
                   picture_type: Option<PictureType>,
                   mime_type: Option<&str>,
                   description: Option<&str>,
                   max_width: Option<u32>,
                   max_height: Option<u32>,
                   max_depth: Option<u32>,
                   max_colors: Option<u32>)
                   -> Result<Picture> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find any Picture";
    let mut result = Err(Error::new(io::ErrorKind::NotFound, error_str));

    let mut max_area_seen  = 0;
    let mut max_depth_seen = 0;

    let max_value      = u32::max_value();
    let max_width_num  = max_width.unwrap_or(max_value);
    let max_height_num = max_height.unwrap_or(max_value);
    let max_depth_num  = max_depth.unwrap_or(max_value);
    let max_colors_num = max_colors.unwrap_or(max_value);

    for block in blocks {
      if let Data::Picture(picture) = block.data {
        let area = (picture.width as u64) * (picture.height as u64);

        if optional_eq(picture_type, picture.picture_type) &&
           optional_eq(mime_type, &picture.mime_type) &&
           optional_eq(description, &picture.description) &&
           picture.width <= max_width_num &&
           picture.height <= max_height_num &&
           picture.depth <= max_depth_num &&
           picture.colors <= max_colors_num &&
           (area > max_area_seen || (area == max_area_seen &&
                                     picture.depth > max_depth_seen)) {
          max_area_seen  = area;
          max_depth_seen = picture.depth;
          result         = Ok(picture);
        }
      }
    }

    result
  })
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::io::ErrorKind;

  #[test]
  #[should_panic]
  fn test_panic_optional_eq() {
    assert!(optional_eq(Some(1), 0));
  }

  #[test]
  fn test_optional_eq() {
    assert!(optional_eq(None, 0), "Should always return true when None");
    assert!(optional_eq(Some(0), 0), "Should return true (Some(0) == 0)");
  }

  #[test]
  fn test_get_metadata() {
    let not_found    = get_metadata("non-existent/file.txt");
    let invalid_data = get_metadata("README.md");
    let result       = get_metadata("tests/assets/input-SVAUP.flac");

    assert_eq!(not_found.unwrap_err().kind(), ErrorKind::NotFound);
    assert_eq!(invalid_data.unwrap_err().kind(), ErrorKind::InvalidData);
    assert!(result.is_ok());
  }
}
<|endoftext|>


<commit_before>//! Contains the full definition of a data system which Ardite will use.

use std::collections::BTreeMap;
use std::io::BufReader;
use std::fs::File;
use std::ops::Deref;
use std::path::PathBuf;

use serde_json;
use serde_yaml;

use error::{Error, NotAcceptable};
use schema::{Schema, BoxedSchema};
use value::Key;

/// The definition object which contains all necessary information to
/// understand an Ardite Schema Definition.
#[derive(Debug)]
pub struct Definition {
  /// Types defined in the database.
  types: BTreeMap<Key, Type>
}

#[cfg(test)]
impl_debug_eq!(Definition);

impl Definition {
  /// Creates a new empty instance of `Definition`.
  pub fn new() -> Self {
    Definition {
      types: BTreeMap::new()
    }
  }

  /// Add a new type to the `Definition`.
  pub fn add_type<K>(&mut self, name: K, type_: Type) where K: Into<Key> {
    self.types.insert(name.into(), type_);
  }

  /// Gets type of a certain name.
  pub fn get_type<'a, K>(&self, name: K) -> Option<&Type> where K: Into<&'a Key> {
    self.types.get(name.into())
  }

  /// Gets an Ardite Schema Definition from a file. Aims to support mainly the
  /// JSON and YAML formats.
  // TODO: validate file against JSON schema.
  pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
    let extension = path.extension().map_or("", |s| s.to_str().unwrap());
    let file = try!(File::open(&path));
    let reader = BufReader::new(file);
    Ok(match extension {
      "json" => try!(serde_json::from_reader(reader)),
      "yml" => try!(serde_yaml::from_reader(reader)),
      _ => {
        return Err(Error::new(
          NotAcceptable,
          format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()),
          Some("Use a recognizable file extension like '.json' or '.yml'.".to_owned())
        ))
      }
    })
  }
}

/// Represents a high-level database type.
#[derive(Debug)]
pub struct Type {
  /// The schema used to validate data which claims to be of this type.
  schema: Option<BoxedSchema>
}

#[cfg(test)]
impl_debug_eq!(Type);

impl Type {
  /// Create a new instance of `Type`.
  pub fn new() -> Self {
    Type {
      schema: None
    }
  }

  /// Set the schema for the type. Polymorphic so it accepts any type which
  /// implements schema which gets boxed into a trait object. If you have a
  /// schema trait object, see `set_boxed_schema`.
  pub fn set_schema<S>(&mut self, schema: S) where S: Schema + 'static {
    self.schema = Some(Box::new(schema));
  }

  pub fn set_boxed_schema(&mut self, schema: BoxedSchema) {
    self.schema = Some(schema);
  }

  /// Gets the schema of the type.
  pub fn schema(&self) -> Option<&Schema> {
    self.schema.as_ref().map(|schema| schema.deref())
  }
}
<commit_msg>fix(schema): update to new error format<commit_after>//! Contains the full definition of a data system which Ardite will use.

use std::collections::BTreeMap;
use std::io::BufReader;
use std::fs::File;
use std::ops::Deref;
use std::path::PathBuf;

use serde_json;
use serde_yaml;

use error::{Error, NotAcceptable};
use schema::{Schema, BoxedSchema};
use value::Key;

/// The definition object which contains all necessary information to
/// understand an Ardite Schema Definition.
#[derive(Debug)]
pub struct Definition {
  /// Types defined in the database.
  types: BTreeMap<Key, Type>
}

#[cfg(test)]
impl_debug_eq!(Definition);

impl Definition {
  /// Creates a new empty instance of `Definition`.
  pub fn new() -> Self {
    Definition {
      types: BTreeMap::new()
    }
  }

  /// Add a new type to the `Definition`.
  pub fn add_type<K>(&mut self, name: K, type_: Type) where K: Into<Key> {
    self.types.insert(name.into(), type_);
  }

  /// Gets type of a certain name.
  pub fn get_type<'a, K>(&self, name: K) -> Option<&Type> where K: Into<&'a Key> {
    self.types.get(name.into())
  }

  /// Gets an Ardite Schema Definition from a file. Aims to support mainly the
  /// JSON and YAML formats.
  // TODO: validate file against JSON schema.
  pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
    let extension = path.extension().map_or("", |s| s.to_str().unwrap());
    let file = try!(File::open(&path));
    let reader = BufReader::new(file);
    Ok(match extension {
      "json" => try!(serde_json::from_reader(reader)),
      "yml" => try!(serde_yaml::from_reader(reader)),
      _ => {
        return Err(
          Error
          ::new(NotAcceptable, format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()))
          .set_hint("Use a recognizable file extension like '.json' or '.yml'.")
        )
      }
    })
  }
}

/// Represents a high-level database type.
#[derive(Debug)]
pub struct Type {
  /// The schema used to validate data which claims to be of this type.
  schema: Option<BoxedSchema>
}

#[cfg(test)]
impl_debug_eq!(Type);

impl Type {
  /// Create a new instance of `Type`.
  pub fn new() -> Self {
    Type {
      schema: None
    }
  }

  /// Set the schema for the type. Polymorphic so it accepts any type which
  /// implements schema which gets boxed into a trait object. If you have a
  /// schema trait object, see `set_boxed_schema`.
  pub fn set_schema<S>(&mut self, schema: S) where S: Schema + 'static {
    self.schema = Some(Box::new(schema));
  }

  pub fn set_boxed_schema(&mut self, schema: BoxedSchema) {
    self.schema = Some(schema);
  }

  /// Gets the schema of the type.
  pub fn schema(&self) -> Option<&Schema> {
    self.schema.as_ref().map(|schema| schema.deref())
  }
}
<|endoftext|>