<commit_before>
#![allow(unused_imports)]

use std::rc::Rc;
use std::cell::RefCell;
use vm::{object_to_string, object_to_repr, RTE, Env};
use object::{Object, Map, Table, List,
  FnResult, U32String, Function, EnumFunction,
  type_error, argc_error, index_error, value_error, std_exception,
  VARIADIC, new_module
};
use rand::Rand;

pub fn fpanic(pself: &Object, argv: &[Object]) -> FnResult{
  panic!()
}

pub fn print(pself: &Object, argv: &[Object]) -> FnResult{
  for i in 0..argv.len() {
    print!("{}",object_to_string(&argv[i]));
  }
  println!();
  return Ok(Object::Null);
}

pub fn put(pself: &Object, argv: &[Object]) -> FnResult{
  for i in 0..argv.len() {
    print!("{}",object_to_string(&argv[0]));
  }
  return Ok(Object::Null);
}

fn fstr(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"str");
  }
  let s = object_to_string(&argv[0]);
  return Ok(U32String::new_object_str(&s));
}

fn repr(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"repr");
  }
  let s = object_to_repr(&argv[0]);
  return Ok(U32String::new_object_str(&s));
}

fn abs(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"abs");
  }
  match argv[0] {
    Object::Int(x) => {
      return Ok(Object::Int(x.abs()));
    },
    Object::Float(x) => {
      return Ok(Object::Float(x.abs()));
    },
    Object::Complex(z) => {
      return Ok(Object::Float(z.abs()));
    },
    _ => {
      return type_error("Type error in abs(x): x is not an int, float, complex.");
    }
  }
}

fn eval(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult{
  let gtab = match argv.len() {
    1 => env.rte().pgtab.borrow().clone(),
    2 => {
      match argv[1] {
        Object::Map(ref m) => m.clone(),
        _ => return type_error("Type error in eval(s,m): m is not a map.")
      }
    },
    n => {
      return argc_error(n,1,1,"eval")
    }
  };
  match argv[0] {
    Object::String(ref s) => {
      let a: String = s.v.iter().collect();
      return match env.eval_string(&a,"",gtab) {
        Ok(x) => {Ok(x)},
        Err(e) => Err(e)
      }
    },
    _ => {
      return type_error("Type error in eval(s): s is not a string.");
    }
  }
}

fn size(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"size");
  }
  match argv[0] {
    Object::List(ref a) => {
      Ok(Object::Int(a.borrow().v.len() as i32))
    },
    Object::Map(ref m) => {
      Ok(Object::Int(m.borrow().m.len() as i32))
    },
    Object::String(ref s) => {
      Ok(Object::Int(s.v.len() as i32))
    },
    _ => type_error("Type error in size(a): cannot determine the size of a.")
  }
}

fn load_file(env: &mut Env, id: &str) -> FnResult {
  let s = match ::system::read_file(id) {
    Ok(s)=>s,
    Err(()) => return std_exception(&format!("Error: Could not load file '{}.moss'.",id))
  };
  let module = new_module(id);
  env.rte().clear_at_exit(module.map.clone());
  match env.eval_string(&s,id,module.map.clone()) {
    Ok(x) => {
      Ok(Object::Table(Rc::new(module)))
    },
    Err(e) => Err(e)
  }
}

fn load(env: &mut Env, s: &U32String) -> FnResult{
  let s: String = s.v.iter().collect();
  if s=="math" {
    return Ok(::math::load_math());
  }else if s=="cmath" {
    return Ok(::math::load_cmath());
  }else if s=="sys" {
    return Ok(::sys::load_sys(env.rte()));
  }else{
    return load_file(env,&s);
    // return index_error(&format!("Could not load module '{}'.",s));
  }
}

fn fload(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"load");
  }
  match argv[0] {
    Object::String(ref s) => load(env,s),
    _ => type_error("Type error in load(id): id is not a string.")
  }
}

fn iter(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"iter");
  }
  return ::iterable::iter(&argv[0]);
}

fn record(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len()!=1 {
    return argc_error(argv.len(),1,1,"record");
  }
  match argv[0] {
    Object::Table(ref t) => {
      Ok(Object::Map(t.map.clone()))
    },
    _ => type_error("Type error in record(x): x is not a table.")
  }
}

fn fobject(pself: &Object, argv: &[Object]) -> FnResult{
  match argv.len() {
    0 => {
      Ok(Object::Table(Table::new(Object::Null)))
    },
    1 => {
      Ok(Object::Table(Table::new(argv[0].clone())))
    },
    2 => {
      match argv[1] {
        Object::Map(ref m) => {
          Ok(Object::Table(Rc::new(Table{
            prototype: argv[0].clone(),
            map: m.clone()
          })))
        },
        _ => type_error("Type error in object(p,m): m is not a map.")
      }
    },
    n => argc_error(n,0,0,"object")
  }
}

fn ftype(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len()!=1 {
    return argc_error(argv.len(),1,1,"type");
  }
  match argv[0] {
    Object::Null => Ok(Object::Null),
    Object::Bool(x) => Ok(Object::Table(env.rte().type_bool.clone())),
    Object::Int(x) => Ok(Object::Table(env.rte().type_int.clone())),
    Object::Float(x) => Ok(Object::Table(env.rte().type_float.clone())),
    Object::Complex(x) => Ok(Object::Table(env.rte().type_complex.clone())),
    Object::String(ref s) => Ok(Object::Table(env.rte().type_string.clone())),
    Object::List(ref a) => Ok(Object::Table(env.rte().type_list.clone())),
    Object::Map(ref m) => Ok(Object::Table(env.rte().type_map.clone())),
    Object::Table(ref t) => {
      Ok(t.prototype.clone())
    },
    _ => Ok(Object::Null)
  }
}

pub fn flist(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len()!=1 {
    return argc_error(argv.len(),1,1,"list");
  }
  match argv[0] {
    Object::Int(n) => {
      if n<0 {
        return value_error("Value error in list(n): n<0.");
      }
      let mut v: Vec<Object> = Vec::with_capacity(n as usize);
      for i in 0..n {
        v.push(Object::Int(i));
      }
      Ok(List::new_object(v))
    },
    Object::Range(ref r) => {
      let a = match r.a {
        Object::Int(x)=>x,
        _ => return type_error("Type error in list(a..b): a is not an integer.")
      };
      let b = match r.b {
        Object::Int(x)=>x,
        _ => return type_error("Type error in list(a..b): b is not an integer.")
      };
      let mut n = b-a+1;
      if n<0 {n=0;}
      let mut v: Vec<Object> = Vec::with_capacity(n as usize);
      for i in a..b+1 {
        v.push(Object::Int(i));
      }
      Ok(List::new_object(v))
    },
    Object::List(ref a) => {
      Ok(Object::List(a.clone()))
    },
    Object::Map(ref m) => {
      let v: Vec<Object> = m.borrow().m.keys().cloned().collect();
      Ok(List::new_object(v))
    },
    _ => type_error("Type error in list(r): r is not a range.")
  }
}

fn copy(pself: &Object, argv: &[Object]) -> FnResult {
  if argv.len()!=1 {
    return argc_error(argv.len(),1,1,"copy");
  }
  match argv[0] {
    Object::List(ref a) => {
      Ok(List::new_object(a.borrow().v.clone()))
    },
    Object::Map(ref m) => {
      panic!();
    },
    ref x => {
      Ok(x.clone())
    }
  }
}

fn frand(pself: &Object, argv: &[Object]) -> FnResult {
  if argv.len()==1 {
    match argv[0] {
      Object::Range(ref r) => {
        let a = match r.a {
          Object::Int(x)=>x,
          _ => return type_error("Type error in rand(a..b): a is not an integer.")
        };
        let b = match r.b {
          Object::Int(x)=>x,
          _ => return type_error("Type error in rand(a..b): b is not an integer.")
        };
        let mut rng = Rand::new(0);
        let f = Box::new(move |pself: &Object, argv: &[Object]| -> FnResult {
          Ok(Object::Int(rng.rand_range(a,b)))
        });
        return Ok(Function::mutable(f,0,0));
      },
      _ => return type_error("Type error in rand(r): r is not a range.")
    }
  }else{
    return argc_error(argv.len(),1,1,"rand");
  }
}

fn fgtab(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult {
  if argv.len()==1 {
    match argv[0] {
      Object::Function(ref f) => {
        if let EnumFunction::Std(ref fp) = f.f {
          Ok(Object::Map(fp.gtab.clone()))
        }else{
          type_error("Type error in gtab(f): f is not a function from Moss source code.")
        }
      },
      _ => type_error("Type error in gtab(f): f is not a function.")
    }
  }else{
    Ok(Object::Map(env.rte().pgtab.borrow().clone()))
  }
}

pub fn init_rte(rte: &RTE){
  let mut gtab = rte.gtab.borrow_mut();
  gtab.insert_fn_plain("print",print,0,VARIADIC);
  gtab.insert_fn_plain("put",put,0,VARIADIC);
  gtab.insert_fn_plain("str",fstr,1,1);
  gtab.insert_fn_plain("repr",repr,1,1);
  gtab.insert_fn_plain("abs",abs,1,1);
  gtab.insert_fn_env  ("eval",eval,1,1);
  gtab.insert_fn_plain("size",size,1,1);
  gtab.insert_fn_env  ("load",fload,1,1);
  gtab.insert_fn_plain("iter",iter,1,1);
  gtab.insert_fn_plain("record",record,1,1);
  gtab.insert_fn_plain("object",fobject,0,2);
  gtab.insert_fn_env  ("type",ftype,1,1);
  gtab.insert_fn_plain("list",flist,1,1);
  gtab.insert_fn_plain("copy",copy,1,1);
  gtab.insert_fn_plain("rand",frand,1,1);
  gtab.insert_fn_env  ("gtab",fgtab,0,0);
  gtab.insert("empty", Object::Empty);

  let type_bool = rte.type_bool.clone();
  gtab.insert("Bool", Object::Table(type_bool));

  let type_int = rte.type_int.clone();
  gtab.insert("Int", Object::Table(type_int));

  let type_float = rte.type_float.clone();
  gtab.insert("Float", Object::Table(type_float));

  let type_complex = rte.type_complex.clone();
  gtab.insert("Complex", Object::Table(type_complex));

  let type_string = rte.type_string.clone();
  gtab.insert("String", Object::Table(type_string));

  let type_list = rte.type_list.clone();
  ::list::init(&type_list);
  gtab.insert("List", Object::Table(type_list));

  let type_map = rte.type_map.clone();
  ::map::init(&type_map);
  gtab.insert("Map", Object::Table(type_map));

  let type_function = rte.type_function.clone();
  ::function::init(&type_function);
  gtab.insert("Function", Object::Table(type_function));

  let type_iterable = rte.type_iterable.clone();
  ::iterable::init(&type_iterable);
  gtab.insert("Iterable", Object::Table(type_iterable));
}

<commit_msg>update<commit_after>
#![allow(unused_imports)]

use std::rc::Rc;
use std::cell::RefCell;
use vm::{object_to_string, object_to_repr, RTE, Env};
use object::{Object, Map, Table, List,
  FnResult, U32String, Function, EnumFunction,
  type_error, argc_error, index_error, value_error, std_exception,
  VARIADIC, new_module
};
use rand::Rand;
use iterable::iter;
use std::collections::HashMap;

pub fn fpanic(pself: &Object, argv: &[Object]) -> FnResult{
  panic!()
}

pub fn print(pself: &Object, argv: &[Object]) -> FnResult{
  for i in 0..argv.len() {
    print!("{}",object_to_string(&argv[i]));
  }
  println!();
  return Ok(Object::Null);
}

pub fn put(pself: &Object, argv: &[Object]) -> FnResult{
  for i in 0..argv.len() {
    print!("{}",object_to_string(&argv[0]));
  }
  return Ok(Object::Null);
}

fn fstr(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"str");
  }
  let s = object_to_string(&argv[0]);
  return Ok(U32String::new_object_str(&s));
}

fn repr(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"repr");
  }
  let s = object_to_repr(&argv[0]);
  return Ok(U32String::new_object_str(&s));
}

fn abs(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"abs");
  }
  match argv[0] {
    Object::Int(x) => {
      return Ok(Object::Int(x.abs()));
    },
    Object::Float(x) => {
      return Ok(Object::Float(x.abs()));
    },
    Object::Complex(z) => {
      return Ok(Object::Float(z.abs()));
    },
    _ => {
      return type_error("Type error in abs(x): x is not an int, float, complex.");
    }
  }
}

fn eval(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult{
  let gtab = match argv.len() {
    1 => env.rte().pgtab.borrow().clone(),
    2 => {
      match argv[1] {
        Object::Map(ref m) => m.clone(),
        _ => return type_error("Type error in eval(s,m): m is not a map.")
      }
    },
    n => {
      return argc_error(n,1,1,"eval")
    }
  };
  match argv[0] {
    Object::String(ref s) => {
      let a: String = s.v.iter().collect();
      return match env.eval_string(&a,"",gtab) {
        Ok(x) => {Ok(x)},
        Err(e) => Err(e)
      }
    },
    _ => {
      return type_error("Type error in eval(s): s is not a string.");
    }
  }
}

fn size(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"size");
  }
  match argv[0] {
    Object::List(ref a) => {
      Ok(Object::Int(a.borrow().v.len() as i32))
    },
    Object::Map(ref m) => {
      Ok(Object::Int(m.borrow().m.len() as i32))
    },
    Object::String(ref s) => {
      Ok(Object::Int(s.v.len() as i32))
    },
    _ => type_error("Type error in size(a): cannot determine the size of a.")
  }
}

fn load_file(env: &mut Env, id: &str) -> FnResult {
  let s = match ::system::read_file(id) {
    Ok(s)=>s,
    Err(()) => return std_exception(&format!("Error: Could not load file '{}.moss'.",id))
  };
  let module = new_module(id);
  env.rte().clear_at_exit(module.map.clone());
  match env.eval_string(&s,id,module.map.clone()) {
    Ok(x) => {
      Ok(Object::Table(Rc::new(module)))
    },
    Err(e) => Err(e)
  }
}

fn load(env: &mut Env, s: &U32String) -> FnResult{
  let s: String = s.v.iter().collect();
  if s=="math" {
    return Ok(::math::load_math());
  }else if s=="cmath" {
    return Ok(::math::load_cmath());
  }else if s=="sys" {
    return Ok(::sys::load_sys(env.rte()));
  }else{
    return load_file(env,&s);
    // return index_error(&format!("Could not load module '{}'.",s));
  }
}

fn fload(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"load");
  }
  match argv[0] {
    Object::String(ref s) => load(env,s),
    _ => type_error("Type error in load(id): id is not a string.")
  }
}

fn fiter(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len() != 1 {
    return argc_error(argv.len(),1,1,"iter");
  }
  return iter(&argv[0]);
}

fn record(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len()!=1 {
    return argc_error(argv.len(),1,1,"record");
  }
  match argv[0] {
    Object::Table(ref t) => {
      Ok(Object::Map(t.map.clone()))
    },
    _ => type_error("Type error in record(x): x is not a table.")
  }
}

fn fobject(pself: &Object, argv: &[Object]) -> FnResult{
  match argv.len() {
    0 => {
      Ok(Object::Table(Table::new(Object::Null)))
    },
    1 => {
      Ok(Object::Table(Table::new(argv[0].clone())))
    },
    2 => {
      match argv[1] {
        Object::Map(ref m) => {
          Ok(Object::Table(Rc::new(Table{
            prototype: argv[0].clone(),
            map: m.clone()
          })))
        },
        _ => type_error("Type error in object(p,m): m is not a map.")
      }
    },
    n => argc_error(n,0,0,"object")
  }
}

fn ftype(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len()!=1 {
    return argc_error(argv.len(),1,1,"type");
  }
  match argv[0] {
    Object::Null => Ok(Object::Null),
    Object::Bool(x) => Ok(Object::Table(env.rte().type_bool.clone())),
    Object::Int(x) => Ok(Object::Table(env.rte().type_int.clone())),
    Object::Float(x) => Ok(Object::Table(env.rte().type_float.clone())),
    Object::Complex(x) => Ok(Object::Table(env.rte().type_complex.clone())),
    Object::String(ref s) => Ok(Object::Table(env.rte().type_string.clone())),
    Object::List(ref a) => Ok(Object::Table(env.rte().type_list.clone())),
    Object::Map(ref m) => Ok(Object::Table(env.rte().type_map.clone())),
    Object::Table(ref t) => {
      Ok(t.prototype.clone())
    },
    _ => Ok(Object::Null)
  }
}

pub fn flist(pself: &Object, argv: &[Object]) -> FnResult{
  if argv.len()!=1 {
    return argc_error(argv.len(),1,1,"list");
  }
  match argv[0] {
    Object::Int(n) => {
      if n<0 {
        return value_error("Value error in list(n): n<0.");
      }
      let mut v: Vec<Object> = Vec::with_capacity(n as usize);
      for i in 0..n {
        v.push(Object::Int(i));
      }
      Ok(List::new_object(v))
    },
    Object::Range(ref r) => {
      let a = match r.a {
        Object::Int(x)=>x,
        _ => return type_error("Type error in list(a..b): a is not an integer.")
      };
      let b = match r.b {
        Object::Int(x)=>x,
        _ => return type_error("Type error in list(a..b): b is not an integer.")
      };
      let mut n = b-a+1;
      if n<0 {n=0;}
      let mut v: Vec<Object> = Vec::with_capacity(n as usize);
      for i in a..b+1 {
        v.push(Object::Int(i));
      }
      Ok(List::new_object(v))
    },
    Object::List(ref a) => {
      Ok(Object::List(a.clone()))
    },
    Object::Map(ref m) => {
      let v: Vec<Object> = m.borrow().m.keys().cloned().collect();
      Ok(List::new_object(v))
    },
    _ => type_error("Type error in list(r): r is not a range.")
  }
}

fn set(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult {
  match argv.len() {
    1 => {
      let i = &try!(iter(&argv[0]));
      let mut m: HashMap<Object,Object> = HashMap::new();
      loop {
        let y = try!(env.call(i,&Object::Null,&[]));
        if y == Object::Empty {break;}
        m.insert(y,Object::Null);
      }
      return Ok(Object::Map(Rc::new(RefCell::new(Map{
        m: m, frozen: false
      }))));
    },
    n => return argc_error(n,1,1,"set")
  }
}

fn copy(pself: &Object, argv: &[Object]) -> FnResult {
  if argv.len()!=1 {
    return argc_error(argv.len(),1,1,"copy");
  }
  match argv[0] {
    Object::List(ref a) => {
      Ok(List::new_object(a.borrow().v.clone()))
    },
    Object::Map(ref m) => {
      panic!();
    },
    ref x => {
      Ok(x.clone())
    }
  }
}

fn frand(pself: &Object, argv: &[Object]) -> FnResult {
  if argv.len()==1 {
    match argv[0] {
      Object::Range(ref r) => {
        let a = match r.a {
          Object::Int(x)=>x,
          _ => return type_error("Type error in rand(a..b): a is not an integer.")
        };
        let b = match r.b {
          Object::Int(x)=>x,
          _ => return type_error("Type error in rand(a..b): b is not an integer.")
        };
        let mut rng = Rand::new(0);
        let f = Box::new(move |pself: &Object, argv: &[Object]| -> FnResult {
          Ok(Object::Int(rng.rand_range(a,b)))
        });
        return Ok(Function::mutable(f,0,0));
      },
      _ => return type_error("Type error in rand(r): r is not a range.")
    }
  }else{
    return argc_error(argv.len(),1,1,"rand");
  }
}

fn fgtab(env: &mut Env, pself: &Object, argv: &[Object]) -> FnResult {
  if argv.len()==1 {
    match argv[0] {
      Object::Function(ref f) => {
        if let EnumFunction::Std(ref fp) = f.f {
          Ok(Object::Map(fp.gtab.clone()))
        }else{
          type_error("Type error in gtab(f): f is not a function from Moss source code.")
        }
      },
      _ => type_error("Type error in gtab(f): f is not a function.")
    }
  }else{
    Ok(Object::Map(env.rte().pgtab.borrow().clone()))
  }
}

pub fn init_rte(rte: &RTE){
  let mut gtab = rte.gtab.borrow_mut();
  gtab.insert_fn_plain("print",print,0,VARIADIC);
  gtab.insert_fn_plain("put",put,0,VARIADIC);
  gtab.insert_fn_plain("str",fstr,1,1);
  gtab.insert_fn_plain("repr",repr,1,1);
  gtab.insert_fn_plain("abs",abs,1,1);
  gtab.insert_fn_env  ("eval",eval,1,1);
  gtab.insert_fn_plain("size",size,1,1);
  gtab.insert_fn_env  ("load",fload,1,1);
  gtab.insert_fn_plain("iter",fiter,1,1);
  gtab.insert_fn_plain("record",record,1,1);
  gtab.insert_fn_plain("object",fobject,0,2);
  gtab.insert_fn_env  ("type",ftype,1,1);
  gtab.insert_fn_plain("list",flist,1,1);
  gtab.insert_fn_env  ("set",set,1,1);
  gtab.insert_fn_plain("copy",copy,1,1);
  gtab.insert_fn_plain("rand",frand,1,1);
  gtab.insert_fn_env  ("gtab",fgtab,0,0);
  gtab.insert("empty", Object::Empty);

  let type_bool = rte.type_bool.clone();
  gtab.insert("Bool", Object::Table(type_bool));

  let type_int = rte.type_int.clone();
  gtab.insert("Int", Object::Table(type_int));

  let type_float = rte.type_float.clone();
  gtab.insert("Float", Object::Table(type_float));

  let type_complex = rte.type_complex.clone();
  gtab.insert("Complex", Object::Table(type_complex));

  let type_string = rte.type_string.clone();
  gtab.insert("String", Object::Table(type_string));

  let type_list = rte.type_list.clone();
  ::list::init(&type_list);
  gtab.insert("List", Object::Table(type_list));

  let type_map = rte.type_map.clone();
  ::map::init(&type_map);
  gtab.insert("Map", Object::Table(type_map));

  let type_function = rte.type_function.clone();
  ::function::init(&type_function);
  gtab.insert("Function", Object::Table(type_function));

  let type_iterable = rte.type_iterable.clone();
  ::iterable::init(&type_iterable);
  gtab.insert("Iterable", Object::Table(type_iterable));
}

<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! BED reading and writing.
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::bed;
//! let reader = bed::Reader::new(io::stdin());
//! ```

use std::io;
use std::str;

use csv;

pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
}

impl<R: io::Read> Reader<R> {
    pub fn new(reader: R) -> Self {
        Reader { inner: csv::Reader::from_reader(reader).delimiter(b'\t').has_headers(false) }
    }

    pub fn records(&mut self) -> csv::DecodedRecords<R, Record> {
        self.inner.decode()
    }
}

pub struct Writer<W: io::Write> {
    inner: csv::Writer<W>,
}

impl<W: io::Write> Writer<W> {
    pub fn new(writer: W) -> Self {
        Writer { inner: csv::Writer::from_writer(writer).delimiter(b'\t').flexible(true) }
    }

    pub fn write(&mut self, record: Record) -> csv::Result<()> {
        self.inner.encode(record)
    }
}

/// A BED record as defined by UCSC (https://genome.ucsc.edu/FAQ/FAQformat.html#format1)
#[derive(RustcEncodable)]
#[derive(Debug)]
pub struct Record {
    chrom: String,
    start: u64,
    end: u64,
    fields: Vec<String>,
}

impl Record {
    pub fn new() -> Self {
        Record { chrom: String::new(), start: 0, end: 0, fields: vec![] }
    }

    pub fn chrom(&self) -> &[u8] {
        &self.chrom.as_bytes()
    }

    pub fn start(&self) -> u64 {
        self.start
    }

    pub fn end(&self) -> u64 {
        self.end
    }

    pub fn name(&self) -> Option<&str> {
        self.field(3)
    }

    pub fn score(&self) -> Option<&str> {
        self.field(4)
    }

    pub fn is_forward_strand(&self) -> Option<bool> {
        match self.field(5) {
            Some(v) => if v == "+" { Some(true) } else if v == "-" { Some(false) } else { None },
            None    => None
        }
    }

    pub fn field(&self, i: usize) -> Option<&str> {
        let j = i - 3;
        if self.fields.len() > j {
            Some(&self.fields[j])
        }
        else {
            None
        }
    }

    pub fn set_chrom(&mut self, chrom: &[u8]) {
        self.chrom = str::from_utf8(chrom).ok().expect("Error during string conversion.").to_string();
    }

    pub fn set_start(&mut self, start: u64) {
        self.start = start;
    }

    pub fn set_end(&mut self, end: u64) {
        self.end = end;
    }

    pub fn set_name(&mut self, name: &str) {
        if self.fields.len() < 1 {
            self.fields.push(name.to_string());
        }
        else {
            self.fields[0] = name.to_string();
        }
    }

    pub fn set_score(&mut self, score: &str) {
        if self.fields.len() < 1 {
            self.fields.push("".to_string());
        }
        if self.fields.len() < 2 {
            self.fields.push(score.to_string());
        }
        else {
            self.fields[1] = score.to_string();
        }
    }

    pub fn push_field(&mut self, field: &str) {
        self.fields.push(field.to_string());
    }
}

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

    const BED_FILE: &'static [u8] = b"chr1\t5\t500";
//2\t3\t5005\tname2\tup";

    #[test]
    fn test_reader() {
        let chroms = [b"1", b"2"];
        let starts = [5, 2];
        let ends = [5000, 5005];
        let names = ["name1", "name2"];
        let scores = ["up", "up"];

        let mut reader = Reader::new(BED_FILE);
        for (i, r) in reader.records().enumerate() {
            println!("{:?}", r);
            let record = r.ok().expect("Error reading record");
            assert_eq!(record.chrom(), chroms[i]);
            assert_eq!(record.start(), starts[i]);
            assert_eq!(record.end(), ends[i]);
            assert_eq!(record.name().unwrap(), names[i]);
            assert_eq!(record.score().unwrap(), scores[i]);
        }
    }
}
<commit_msg>Refactoring.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! BED reading and writing.
//!
//! # Example
//!
//! ```
//! use std::io;
//! use bio::io::bed;
//! let reader = bed::Reader::new(io::stdin());
//! ```

use std::io;
use std::str;

use csv;

pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
}

impl<R: io::Read> Reader<R> {
    pub fn new(reader: R) -> Self {
        Reader { inner: csv::Reader::from_reader(reader).delimiter(b'\t').has_headers(false) }
    }

    pub fn records(&mut self) -> csv::DecodedRecords<R, Record> {
        self.inner.decode()
    }
}

pub struct Writer<W: io::Write> {
    inner: csv::Writer<W>,
}

impl<W: io::Write> Writer<W> {
    pub fn new(writer: W) -> Self {
        Writer { inner: csv::Writer::from_writer(writer).delimiter(b'\t').flexible(true) }
    }

    pub fn write(&mut self, record: Record) -> csv::Result<()> {
        self.inner.encode(record)
    }
}

/// A BED record as defined by UCSC (https://genome.ucsc.edu/FAQ/FAQformat.html#format1)
#[derive(RustcEncodable)]
#[derive(Debug)]
pub struct Record<'a> {
    pub chrom: &str,
    pub start: u64,
    pub end: u64,
    fields: Vec<&'a str>
}

impl Record {
    pub fn new() -> Self {
        Record { chrom: "", start: 0, end: 0, fields: vec![] }
    }

    pub fn is_empty() -> bool {
        self.chrom.len() == 0
    }

    pub fn clear() {
        self.chrom = "";
    }

    pub fn name(&self) -> Option<&str> {
        self.field(3)
    }

    pub fn score(&self) -> Option<&str> {
        self.field(4)
    }

    pub fn is_forward_strand(&self) -> Option<bool> {
        match self.field(5) {
            Some(v) => if v == "+" { Some(true) } else if v == "-" { Some(false) } else { None },
            None    => None
        }
    }

    pub fn field(&self, i: usize) -> Option<&str> {
        let j = i - 3;
        if self.fields.len() > j {
            Some(&self.fields[j])
        }
        else {
            None
        }
    }

    pub fn set_name(&mut self, name: &str) {
        if self.fields.len() < 1 {
            self.fields.push(name);
        }
        else {
            self.fields[0] = name;
        }
    }

    pub fn set_score(&mut self, score: &str) {
        if self.fields.len() < 1 {
            self.fields.push(b"");
        }
        if self.fields.len() < 2 {
            self.fields.push(score);
        }
        else {
            self.fields[1] = score;
        }
    }

    pub fn push_field(&mut self, field: &str) {
        self.fields.push(field);
    }
}

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

    const BED_FILE: &'static [u8] = b"chr1\t5\t500";
//2\t3\t5005\tname2\tup";

    #[test]
    fn test_reader() {
        let chroms = [b"1", b"2"];
        let starts = [5, 2];
        let ends = [5000, 5005];
        let names = ["name1", "name2"];
        let scores = ["up", "up"];

        let mut reader = Reader::new(BED_FILE);
        for (i, r) in reader.records().enumerate() {
            println!("{:?}", r);
            let record = r.ok().expect("Error reading record");
            assert_eq!(record.chrom(), chroms[i]);
            assert_eq!(record.start(), starts[i]);
            assert_eq!(record.end(), ends[i]);
            assert_eq!(record.name().unwrap(), names[i]);
            assert_eq!(record.score().unwrap(), scores[i]);
        }
    }
}
<|endoftext|>


<commit_before>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::path::PathBuf;

// from parent
use ERes;
use err;
use read_file;
use footprint;

extern crate rustysexp;
use self::rustysexp::Sexp;

pub struct Layout {
    pub version:i64,
    pub setup:Setup,
    pub elements:Vec<Element>,
}

#[derive(Clone)]
pub enum Element {
    Module(footprint::Module),
    Net(Net),
    NetClass(NetClass),
    Other(Sexp),
}

#[derive(Clone)]
pub struct Setup {
    pub elements:Vec<(String, String)>,
    pub pcbplotparams:Option<Sexp>,
}

#[derive(Clone,PartialEq)]
pub struct Net {
    pub num:i64,
    pub name:String,
}

#[derive(Clone,PartialEq)]
pub struct NetClass {
    pub name:String,
    pub desc:String,
    pub clearance:f64,
    pub trace_width:f64,
    pub via_dia:f64,
    pub via_drill:f64,
    pub uvia_dia:f64,
    pub uvia_drill:f64,
    pub nets:Vec<String>,
}

impl Layout {
    pub fn new() -> Layout {
        Layout {
            version:0,
            elements:vec![],
            setup:Setup::new(),
        }
    }

    pub fn nets(&self) -> Vec<&Net> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::Net(ref net) => v.push(net),
                _ => (),
            }
        }
        v
    }

    pub fn netclasses(&self) -> Vec<&NetClass> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::NetClass(ref net_class) => v.push(net_class),
                _ => (),
            }
        }
        v
    }

    pub fn modify_module<F>(&mut self, reference:&String, fun:F) -> ERes<()>
        where F:Fn(&mut footprint::Module) -> ()
    {
        for ref mut x in &mut self.elements[..] {
            match **x {
                Element::Module(ref mut m) => {
                    if m.is_reference(reference) {
                        return Ok(fun(m))
                    }
                },
                Element::Net(_) => (),
                Element::NetClass(_) => (),
                Element::Other(_) => (),
            }
        }
        Err(format!("did not find module with reference {}", reference))
    }

    pub fn add_net(&mut self, num:i64, name:&'static str) {
        self.elements.push(Element::Net(Net { num:num, name:String::from(name) }));
    }
    pub fn add_netclass(&mut self, name:&'static str, desc:&'static str, clearance:f64, trace_width:f64, via_dia:f64, via_drill:f64, uvia_dia:f64, uvia_drill:f64, nets:Vec<String>) {
        self.elements.push(Element::NetClass(NetClass {
            name:String::from(name),
            desc:String::from(desc),
            clearance:clearance,
            trace_width:trace_width,
            via_dia:via_dia,
            via_drill:via_drill,
            uvia_dia:uvia_dia,
            uvia_drill:uvia_drill,
            nets:nets
            }));
    }
}

impl NetClass {
    pub fn equal_no_net(&self, other:&NetClass) -> bool {
        let mut s1 = self.clone();
        s1.nets = vec![];
        let mut s2 = other.clone();
        s2.nets = vec![];
        return s1 == s2;
    }
    pub fn has_net(&self, name:&'static str) -> bool {
        for net in &self.nets {
            if &net[..] == name {
                return true
            }
        }
        return false
    }
}

impl Setup {
    pub fn new() -> Setup {
        Setup { elements:vec![],pcbplotparams:Some(Sexp::List(vec![Sexp::String(String::from("pcbplotparams"))]))}
    }
}

impl fmt::Display for Layout {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(kicad_pcb (version {})", self.version));
        let mut i = 0;
        for element in &self.elements[..] {
            try!(writeln!(f, "  {}", element));
            try!(writeln!(f, ""));
            // kludge to put setup at the right order in the file
            if i == 3 {
                try!(writeln!(f, "  {}", self.setup));
            }
            i+=1;
        }
        writeln!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Other(ref s) => write!(f, "{}", s),
            Element::Module(ref s) => write!(f, "{}", s),
            Element::Net(ref s) => write!(f, "{}", s),
            Element::NetClass(ref s) => write!(f, "{}", s),
        }
    }
}

impl fmt::Display for Net {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if self.name.contains("(") || self.name.contains(")") || self.name.len()==0 {
            write!(f, "(net {} \"{}\")", self.num, self.name)
        } else {
            write!(f, "(net {} {})", self.num, self.name)
        }
    }
}
impl fmt::Display for NetClass {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(net_class {} {} ", self.name, rustysexp::display_string(&self.desc)));
        try!(write!(f, "(clearance {}) ", self.clearance));
        try!(write!(f, "(trace_width {}) ", self.trace_width));
        try!(write!(f, "(via_dia {}) ", self.via_dia));
        try!(write!(f, "(via_drill {}) ", self.via_drill));
        try!(write!(f, "(uvia_dia {}) ", self.uvia_dia));
        try!(write!(f, "(uvia_drill {}) ", self.uvia_drill));
        for net in &self.nets {
            if net.contains("(") || net.contains(")") {
                try!(write!(f, "(add_net \"{}\")", net))
            } else {
                try!(write!(f, "(add_net {})", net))
            }
        }
        write!(f, ")")

    }
}

impl fmt::Display for Setup {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(setup"));
        for ref k in &self.elements {
            try!(writeln!(f, "   ({} {})", k.0, k.1));
        }
        match self.pcbplotparams {
            None => writeln!(f, ")"),
            Some(ref s) => writeln!(f, " {})", s),
        }
    }
}

fn parse_version(e:&Sexp) -> ERes<i64> {
    let l = try!(e.slice_atom("version"));
    l[0].i()
}

fn parse_other(e:&Sexp) -> Element {
    let e2 = e.clone();
    Element::Other(e2)
}

fn parse_module(e:&Sexp) -> ERes<Element> {
    let e2 = e.clone();
    let m = try!(footprint::parse_module(e2));
    Ok(Element::Module(m))
}

fn parse_net(e:&Sexp) -> ERes<Element> {
    let l = try!(e.slice_atom("net"));
    let num = try!(l[0].i());
    let name = try!(l[1].string()).clone();
    Ok(Element::Net(Net { name:name, num:num }))
}

fn parse_net_class(e:&Sexp) -> ERes<Element> {
    fn parse(e:&Sexp, name:&str) -> ERes<f64> {
        let l = try!(e.slice_atom(name));
        l[0].f()
    }
    let l = try!(e.slice_atom("net_class"));
    let name = try!(l[0].string()).clone();
    let desc = try!(l[1].string()).clone();
    let mut clearance = 0.1524;
    let mut trace_width = 0.2032;
    let mut via_dia = 0.675;
    let mut via_drill = 0.25;
    let mut uvia_dia = 0.508;
    let mut uvia_drill = 0.127;
    let mut nets = vec![];
    for x in &l[2..] {
        let list_name = try!(x.list_name());
        let xn = &list_name[..];
        match xn {
            "add_net" => {
                let l1 = try!(x.slice_atom("add_net"));
                nets.push(try!(l1[0].string()).clone())
            },
            "clearance" => clearance = try!(parse(x, xn)),
            "trace_width" => trace_width = try!(parse(x, xn)),
            "via_dia" => via_dia = try!(parse(x, xn)),
            "via_drill" => via_drill = try!(parse(x, xn)),
            "uvia_dia" => uvia_dia = try!(parse(x, xn)),
            "uvia_drill" => uvia_drill = try!(parse(x, xn)),
            _ => return Err(format!("unknown net_class field {}", list_name))
        }
    }
    let net_class = NetClass {
        name:name, desc:desc, clearance:clearance, via_dia:via_dia,
        via_drill:via_drill, uvia_dia:uvia_dia, uvia_drill:uvia_drill,
        nets:nets, trace_width:trace_width,
    };
    Ok(Element::NetClass(net_class))
}

fn parse_setup(e:&Sexp) -> ERes<Setup> {
    let mut h = vec![];
    let mut pcbplotparams = None;
    for v in try!(e.slice_atom("setup")) {
        let n = v.list_name().unwrap().clone();
        match &n[..] {
            "pcbplotparams" => { pcbplotparams = Some(v.clone()); },
            x => {
                // TODO: this is a kludge, implement proper data type for Setup
                let v2 = v.slice_atom(x).unwrap();
                let mut s = String::new();
                let mut first = true;
                for z in v2 {
                    if !first { s.push_str(" ") };
                    first = false;
                    s.push_str(z.string().unwrap());
                }
                h.push((n.clone(), s));
            },
        }
    }
    let s = Setup { elements:h , pcbplotparams:pcbplotparams };
    Ok(s)
}

fn parse(s: &str) -> ERes<Layout> {
    let exp = match rustysexp::parse_str(s) {
        Ok(s) => s,
        Err(x) => return Err(format!("ParseError: {}", x)),
    };
    let l1 = try!(exp.slice_atom("kicad_pcb"));
    let mut layout = Layout::new();

    for ref e in l1 {
        match &try!(e.list_name())[..] {
            "version" => layout.version = try!(parse_version(e)),
            "module" => layout.elements.push(try!(parse_module(e))),
            "net" => layout.elements.push(try!(parse_net(e))),
            "net_class" => layout.elements.push(try!(parse_net_class(e))),
            "setup" => layout.setup = try!(parse_setup(e)),
            _ => layout.elements.push(parse_other(e)),
        }
    }
    Ok(layout)
}

pub fn parse_str(s: &str) -> ERes<Layout> {
    parse(s)
}

pub fn parse_file(filename: &PathBuf) -> ERes<Layout> {
    let name = filename.to_str().unwrap();
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("io error: {}", x))
    });
    parse(&s[..])
}
<commit_msg>Setup::get<commit_after>// (c) 2016 Joost Yervante Damad <joost@productize.be>

use std::fmt;
use std::path::PathBuf;

// from parent
use ERes;
use err;
use read_file;
use footprint;

extern crate rustysexp;
use self::rustysexp::Sexp;

pub struct Layout {
    pub version:i64,
    pub setup:Setup,
    pub elements:Vec<Element>,
}

#[derive(Clone)]
pub enum Element {
    Module(footprint::Module),
    Net(Net),
    NetClass(NetClass),
    Other(Sexp),
}

#[derive(Clone)]
pub struct Setup {
    pub elements:Vec<(String, String)>,
    pub pcbplotparams:Option<Sexp>,
}

#[derive(Clone,PartialEq)]
pub struct Net {
    pub num:i64,
    pub name:String,
}

#[derive(Clone,PartialEq)]
pub struct NetClass {
    pub name:String,
    pub desc:String,
    pub clearance:f64,
    pub trace_width:f64,
    pub via_dia:f64,
    pub via_drill:f64,
    pub uvia_dia:f64,
    pub uvia_drill:f64,
    pub nets:Vec<String>,
}

impl Layout {
    pub fn new() -> Layout {
        Layout {
            version:0,
            elements:vec![],
            setup:Setup::new(),
        }
    }

    pub fn nets(&self) -> Vec<&Net> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::Net(ref net) => v.push(net),
                _ => (),
            }
        }
        v
    }

    pub fn netclasses(&self) -> Vec<&NetClass> {
        let mut v = vec![];
        for element in &self.elements {
            match *element {
                Element::NetClass(ref net_class) => v.push(net_class),
                _ => (),
            }
        }
        v
    }

    pub fn modify_module<F>(&mut self, reference:&String, fun:F) -> ERes<()>
        where F:Fn(&mut footprint::Module) -> ()
    {
        for ref mut x in &mut self.elements[..] {
            match **x {
                Element::Module(ref mut m) => {
                    if m.is_reference(reference) {
                        return Ok(fun(m))
                    }
                },
                Element::Net(_) => (),
                Element::NetClass(_) => (),
                Element::Other(_) => (),
            }
        }
        Err(format!("did not find module with reference {}", reference))
    }

    pub fn add_net(&mut self, num:i64, name:&'static str) {
        self.elements.push(Element::Net(Net { num:num, name:String::from(name) }));
    }
    pub fn add_netclass(&mut self, name:&'static str, desc:&'static str, clearance:f64, trace_width:f64, via_dia:f64, via_drill:f64, uvia_dia:f64, uvia_drill:f64, nets:Vec<String>) {
        self.elements.push(Element::NetClass(NetClass {
            name:String::from(name),
            desc:String::from(desc),
            clearance:clearance,
            trace_width:trace_width,
            via_dia:via_dia,
            via_drill:via_drill,
            uvia_dia:uvia_dia,
            uvia_drill:uvia_drill,
            nets:nets
            }));
    }
}

impl NetClass {
    pub fn equal_no_net(&self, other:&NetClass) -> bool {
        let mut s1 = self.clone();
        s1.nets = vec![];
        let mut s2 = other.clone();
        s2.nets = vec![];
        return s1 == s2;
    }
    pub fn has_net(&self, name:&'static str) -> bool {
        for net in &self.nets {
            if &net[..] == name {
                return true
            }
        }
        return false
    }
}

impl Setup {
    pub fn new() -> Setup {
        Setup { elements:vec![],pcbplotparams:Some(Sexp::List(vec![Sexp::String(String::from("pcbplotparams"))]))}
    }
    pub fn get(&self, s:&String) -> Option<&String> {
        for element in &self.elements {
            if element.0[..] == s[..] {
                return Some(&element.1)
            }
        }
        return None
    }
}

impl fmt::Display for Layout {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(kicad_pcb (version {})", self.version));
        let mut i = 0;
        for element in &self.elements[..] {
            try!(writeln!(f, "  {}", element));
            try!(writeln!(f, ""));
            // kludge to put setup at the right order in the file
            if i == 3 {
                try!(writeln!(f, "  {}", self.setup));
            }
            i+=1;
        }
        writeln!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Other(ref s) => write!(f, "{}", s),
            Element::Module(ref s) => write!(f, "{}", s),
            Element::Net(ref s) => write!(f, "{}", s),
            Element::NetClass(ref s) => write!(f, "{}", s),
        }
    }
}

impl fmt::Display for Net {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if self.name.contains("(") || self.name.contains(")") || self.name.len()==0 {
            write!(f, "(net {} \"{}\")", self.num, self.name)
        } else {
            write!(f, "(net {} {})", self.num, self.name)
        }
    }
}
impl fmt::Display for NetClass {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(net_class {} {} ", self.name, rustysexp::display_string(&self.desc)));
        try!(write!(f, "(clearance {}) ", self.clearance));
        try!(write!(f, "(trace_width {}) ", self.trace_width));
        try!(write!(f, "(via_dia {}) ", self.via_dia));
        try!(write!(f, "(via_drill {}) ", self.via_drill));
        try!(write!(f, "(uvia_dia {}) ", self.uvia_dia));
        try!(write!(f, "(uvia_drill {}) ", self.uvia_drill));
        for net in &self.nets {
            if net.contains("(") || net.contains(")") {
                try!(write!(f, "(add_net \"{}\")", net))
            } else {
                try!(write!(f, "(add_net {})", net))
            }
        }
        write!(f, ")")

    }
}

impl fmt::Display for Setup {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(writeln!(f, "(setup"));
        for ref k in &self.elements {
            try!(writeln!(f, "   ({} {})", k.0, k.1));
        }
        match self.pcbplotparams {
            None => writeln!(f, ")"),
            Some(ref s) => writeln!(f, " {})", s),
        }
    }
}

fn parse_version(e:&Sexp) -> ERes<i64> {
    let l = try!(e.slice_atom("version"));
    l[0].i()
}

fn parse_other(e:&Sexp) -> Element {
    let e2 = e.clone();
    Element::Other(e2)
}

fn parse_module(e:&Sexp) -> ERes<Element> {
    let e2 = e.clone();
    let m = try!(footprint::parse_module(e2));
    Ok(Element::Module(m))
}

fn parse_net(e:&Sexp) -> ERes<Element> {
    let l = try!(e.slice_atom("net"));
    let num = try!(l[0].i());
    let name = try!(l[1].string()).clone();
    Ok(Element::Net(Net { name:name, num:num }))
}

fn parse_net_class(e:&Sexp) -> ERes<Element> {
    fn parse(e:&Sexp, name:&str) -> ERes<f64> {
        let l = try!(e.slice_atom(name));
        l[0].f()
    }
    let l = try!(e.slice_atom("net_class"));
    let name = try!(l[0].string()).clone();
    let desc = try!(l[1].string()).clone();
    let mut clearance = 0.1524;
    let mut trace_width = 0.2032;
    let mut via_dia = 0.675;
    let mut via_drill = 0.25;
    let mut uvia_dia = 0.508;
    let mut uvia_drill = 0.127;
    let mut nets = vec![];
    for x in &l[2..] {
        let list_name = try!(x.list_name());
        let xn = &list_name[..];
        match xn {
            "add_net" => {
                let l1 = try!(x.slice_atom("add_net"));
                nets.push(try!(l1[0].string()).clone())
            },
            "clearance" => clearance = try!(parse(x, xn)),
            "trace_width" => trace_width = try!(parse(x, xn)),
            "via_dia" => via_dia = try!(parse(x, xn)),
            "via_drill" => via_drill = try!(parse(x, xn)),
            "uvia_dia" => uvia_dia = try!(parse(x, xn)),
            "uvia_drill" => uvia_drill = try!(parse(x, xn)),
            _ => return Err(format!("unknown net_class field {}", list_name))
        }
    }
    let net_class = NetClass {
        name:name, desc:desc, clearance:clearance, via_dia:via_dia,
        via_drill:via_drill, uvia_dia:uvia_dia, uvia_drill:uvia_drill,
        nets:nets, trace_width:trace_width,
    };
    Ok(Element::NetClass(net_class))
}

fn parse_setup(e:&Sexp) -> ERes<Setup> {
    let mut h = vec![];
    let mut pcbplotparams = None;
    for v in try!(e.slice_atom("setup")) {
        let n = v.list_name().unwrap().clone();
        match &n[..] {
            "pcbplotparams" => { pcbplotparams = Some(v.clone()); },
            x => {
                // TODO: this is a kludge, implement proper data type for Setup
                let v2 = v.slice_atom(x).unwrap();
                let mut s = String::new();
                let mut first = true;
                for z in v2 {
                    if !first { s.push_str(" ") };
                    first = false;
                    s.push_str(z.string().unwrap());
                }
                h.push((n.clone(), s));
            },
        }
    }
    let s = Setup { elements:h , pcbplotparams:pcbplotparams };
    Ok(s)
}

fn parse(s: &str) -> ERes<Layout> {
    let exp = match rustysexp::parse_str(s) {
        Ok(s) => s,
        Err(x) => return Err(format!("ParseError: {}", x)),
    };
    let l1 = try!(exp.slice_atom("kicad_pcb"));
    let mut layout = Layout::new();

    for ref e in l1 {
        match &try!(e.list_name())[..] {
            "version" => layout.version = try!(parse_version(e)),
            "module" => layout.elements.push(try!(parse_module(e))),
            "net" => layout.elements.push(try!(parse_net(e))),
            "net_class" => layout.elements.push(try!(parse_net_class(e))),
            "setup" => layout.setup = try!(parse_setup(e)),
            _ => layout.elements.push(parse_other(e)),
        }
    }
    Ok(layout)
}

pub fn parse_str(s: &str) -> ERes<Layout> {
    parse(s)
}

pub fn parse_file(filename: &PathBuf) -> ERes<Layout> {
    let name = filename.to_str().unwrap();
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("io error: {}", x))
    });
    parse(&s[..])
}
<|endoftext|>


<commit_before>macro_rules! define_ty {
    ($name:ident, $($elty:ident),+) => {
        #[repr(simd)]
        #[derive(Clone, Copy, Debug, PartialEq)]
        #[allow(non_camel_case_types)]
        pub struct $name($($elty),*);
    }
}

macro_rules! define_ty_doc {
    ($name:ident, $($elty:ident),+ | $(#[$doc:meta])*) => {
        $(#[$doc])*
        #[repr(simd)]
        #[derive(Clone, Copy, Debug, PartialEq)]
        #[allow(non_camel_case_types)]
        pub struct $name($($elty),*);
    }
}

macro_rules! define_impl {
    (
        $name:ident, $elemty:ident, $nelems:expr, $boolname:ident,
        $($elname:ident),+
    ) => {
        impl $name {
            #[inline(always)]
            pub fn new($($elname: $elemty),*) -> $name {
                $name($($elname),*)
            }

            #[inline(always)]
            pub fn splat(value: $elemty) -> $name {
                $name($({
                    #[allow(non_camel_case_types, dead_code)]
                    struct $elname;
                    value
                }),*)
            }

            #[inline(always)]
            pub fn extract(self, idx: u32) -> $elemty {
                assert!(idx < $nelems);
                unsafe { simd_extract(self, idx) }
            }

            #[inline(always)]
            pub fn replace(self, idx: u32, val: $elemty) -> $name {
                assert!(idx < $nelems);
                unsafe { simd_insert(self, idx, val) }
            }

            #[inline(always)]
            pub fn store(self, slice: &mut [$elemty], offset: usize) {
                assert!(slice[offset..].len() >= $nelems);
                unsafe { self.store_unchecked(slice, offset) }
            }

            #[inline(always)]
            pub unsafe fn store_unchecked(
                self,
                slice: &mut [$elemty],
                offset: usize,
            ) {
                use std::mem::size_of;
                use std::ptr;

                ptr::copy_nonoverlapping(
                    &self as *const $name as *const u8,
                    slice.get_unchecked_mut(offset) as *mut $elemty as *mut u8,
                    size_of::<$name>());
            }

            #[inline(always)]
            pub fn load(slice: &[$elemty], offset: usize) -> $name {
                assert!(slice[offset..].len() >= $nelems);
                unsafe { $name::load_unchecked(slice, offset) }
            }

            #[inline(always)]
            pub unsafe fn load_unchecked(
                slice: &[$elemty],
                offset: usize,
            ) -> $name {
                use std::mem::size_of;
                use std::ptr;

                let mut x = $name::splat(0 as $elemty);
                ptr::copy_nonoverlapping(
                    slice.get_unchecked(offset) as *const $elemty as *const u8,
                    &mut x as *mut $name as *mut u8,
                    size_of::<$name>());
                x
            }

            #[inline(always)]
            pub fn eq(self, other: $name) -> $boolname {
                unsafe { simd_eq(self, other) }
            }

            #[inline(always)]
            pub fn ne(self, other: $name) -> $boolname {
                unsafe { simd_ne(self, other) }
            }

            #[inline(always)]
            pub fn lt(self, other: $name) -> $boolname {
                unsafe { simd_lt(self, other) }
            }

            #[inline(always)]
            pub fn le(self, other: $name) -> $boolname {
                unsafe { simd_le(self, other) }
            }

            #[inline(always)]
            pub fn gt(self, other: $name) -> $boolname {
                unsafe { simd_gt(self, other) }
            }

            #[inline(always)]
            pub fn ge(self, other: $name) -> $boolname {
                unsafe { simd_ge(self, other) }
            }
        }
    }
}

macro_rules! define_from {
    ($to:ident, $($from:ident),+) => {
        $(
            impl From<$from> for $to {
                #[inline(always)]
                fn from(f: $from) -> $to {
                    unsafe { ::std::mem::transmute(f) }
                }
            }
        )+
    }
}

macro_rules! define_common_ops {
    ($($ty:ident),+) => {
        $(
            impl ::std::ops::Add for $ty {
                type Output = Self;
                #[inline(always)]
                fn add(self, other: Self) -> Self {
                    unsafe { simd_add(self, other) }
                }
            }

            impl ::std::ops::Sub for $ty {
                type Output = Self;
                #[inline(always)]
                fn sub(self, other: Self) -> Self {
                    unsafe { simd_sub(self, other) }
                }
            }

            impl ::std::ops::Mul for $ty {
                type Output = Self;
                #[inline(always)]
                fn mul(self, other: Self) -> Self {
                    unsafe { simd_mul(self, other) }
                }
            }
        )+
    }
}

macro_rules! define_float_ops {
    ($($ty:ident),+) => {
        $(
            impl ::std::ops::Div for $ty {
                type Output = Self;
                #[inline(always)]
                fn div(self, other: Self) -> Self {
                    unsafe { simd_div(self, other) }
                }
            }
        )+
    }
}

macro_rules! define_shifts {
    ($ty:ident, $elem:ident, $($by:ident),+) => {
        $(
            impl ::std::ops::Shl<$by> for $ty {
                type Output = Self;
                #[inline(always)]
                fn shl(self, other: $by) -> Self {
                    unsafe { simd_shl(self, $ty::splat(other as $elem)) }
                }
            }
            impl ::std::ops::Shr<$by> for $ty {
                type Output = Self;
                #[inline(always)]
                fn shr(self, other: $by) -> Self {
                    unsafe { simd_shr(self, $ty::splat(other as $elem)) }
                }
            }
        )+
    }
}

macro_rules! define_integer_ops {
    ($(($ty:ident, $elem:ident)),+) => {
        $(
            impl ::std::ops::BitAnd for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitand(self, other: Self) -> Self {
                    unsafe { simd_and(self, other) }
                }
            }
            impl ::std::ops::BitOr for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitor(self, other: Self) -> Self {
                    unsafe { simd_or(self, other) }
                }
            }
            impl ::std::ops::BitXor for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitxor(self, other: Self) -> Self {
                    unsafe { simd_xor(self, other) }
                }
            }
            impl ::std::ops::Not for $ty {
                type Output = Self;
                #[inline(always)]
                fn not(self) -> Self {
                    $ty::splat(!0) ^ self
                }
            }
            define_shifts!(
                $ty, $elem,
                u8, u16, u32, u64, usize,
                i8, i16, i32, i64, isize);

            impl ::std::fmt::LowerHex for $ty {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    write!(f, "{}(", stringify!($ty))?;
                    let n = ::std::mem::size_of_val(self) / ::std::mem::size_of::<$elem>();
                    for i in 0..n {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        write!(f, "{:#x}", self.extract(i as u32))?;
                    }
                    write!(f, ")")
                }
            }
        )+
    }
}

macro_rules! define_casts {
    ($(($fromty:ident, $toty:ident, $cast:ident)),+) => {
        $(
            impl $fromty {
                #[inline(always)]
                pub fn $cast(self) -> ::simd::$toty {
                    unsafe { simd_cast(self) }
                }
            }
        )+
    }
}

/// Is a feature supported by the host CPU?
///
/// This macro performs run-time feature detection. It returns true if the host
/// CPU in which the binary is running on supports a particular feature.
#[macro_export]
macro_rules! cfg_feature_enabled {
    ($name:tt) => (
        {
            #[cfg(target_feature = $name)]
            {
                true
            }
            #[cfg(not(target_feature = $name))]
            {
                __unstable_detect_feature!($name)
            }
        }
    )
}

/// On ARM features are only detected at compile-time using
/// cfg(target_feature), so if this macro is executed the
/// feature is not supported.
#[cfg(any(target_arch = "arm",
          target_arch = "aarch64"))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
    ("neon") => { false };
    ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}

/// In all unsupported architectures using the macro is an error
#[cfg(not(any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm",
              target_arch = "aarch64")))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
    ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}

#[cfg(test)]
mod tests {
    #[cfg(target_arch = "x86_64")]
    #[test]
    fn test_macros() {
        assert!(cfg_feature_enabled!("sse"));
    }
}
<commit_msg>Make vector constructors const functions (#137)<commit_after>macro_rules! define_ty {
    ($name:ident, $($elty:ident),+) => {
        #[repr(simd)]
        #[derive(Clone, Copy, Debug, PartialEq)]
        #[allow(non_camel_case_types)]
        pub struct $name($($elty),*);
    }
}

macro_rules! define_ty_doc {
    ($name:ident, $($elty:ident),+ | $(#[$doc:meta])*) => {
        $(#[$doc])*
        #[repr(simd)]
        #[derive(Clone, Copy, Debug, PartialEq)]
        #[allow(non_camel_case_types)]
        pub struct $name($($elty),*);
    }
}

macro_rules! define_impl {
    (
        $name:ident, $elemty:ident, $nelems:expr, $boolname:ident,
        $($elname:ident),+
    ) => {
        impl $name {
            #[inline(always)]
            pub const fn new($($elname: $elemty),*) -> $name {
                $name($($elname),*)
            }

            #[inline(always)]
            pub fn splat(value: $elemty) -> $name {
                $name($({
                    #[allow(non_camel_case_types, dead_code)]
                    struct $elname;
                    value
                }),*)
            }

            #[inline(always)]
            pub fn extract(self, idx: u32) -> $elemty {
                assert!(idx < $nelems);
                unsafe { simd_extract(self, idx) }
            }

            #[inline(always)]
            pub fn replace(self, idx: u32, val: $elemty) -> $name {
                assert!(idx < $nelems);
                unsafe { simd_insert(self, idx, val) }
            }

            #[inline(always)]
            pub fn store(self, slice: &mut [$elemty], offset: usize) {
                assert!(slice[offset..].len() >= $nelems);
                unsafe { self.store_unchecked(slice, offset) }
            }

            #[inline(always)]
            pub unsafe fn store_unchecked(
                self,
                slice: &mut [$elemty],
                offset: usize,
            ) {
                use std::mem::size_of;
                use std::ptr;

                ptr::copy_nonoverlapping(
                    &self as *const $name as *const u8,
                    slice.get_unchecked_mut(offset) as *mut $elemty as *mut u8,
                    size_of::<$name>());
            }

            #[inline(always)]
            pub fn load(slice: &[$elemty], offset: usize) -> $name {
                assert!(slice[offset..].len() >= $nelems);
                unsafe { $name::load_unchecked(slice, offset) }
            }

            #[inline(always)]
            pub unsafe fn load_unchecked(
                slice: &[$elemty],
                offset: usize,
            ) -> $name {
                use std::mem::size_of;
                use std::ptr;

                let mut x = $name::splat(0 as $elemty);
                ptr::copy_nonoverlapping(
                    slice.get_unchecked(offset) as *const $elemty as *const u8,
                    &mut x as *mut $name as *mut u8,
                    size_of::<$name>());
                x
            }

            #[inline(always)]
            pub fn eq(self, other: $name) -> $boolname {
                unsafe { simd_eq(self, other) }
            }

            #[inline(always)]
            pub fn ne(self, other: $name) -> $boolname {
                unsafe { simd_ne(self, other) }
            }

            #[inline(always)]
            pub fn lt(self, other: $name) -> $boolname {
                unsafe { simd_lt(self, other) }
            }

            #[inline(always)]
            pub fn le(self, other: $name) -> $boolname {
                unsafe { simd_le(self, other) }
            }

            #[inline(always)]
            pub fn gt(self, other: $name) -> $boolname {
                unsafe { simd_gt(self, other) }
            }

            #[inline(always)]
            pub fn ge(self, other: $name) -> $boolname {
                unsafe { simd_ge(self, other) }
            }
        }
    }
}

macro_rules! define_from {
    ($to:ident, $($from:ident),+) => {
        $(
            impl From<$from> for $to {
                #[inline(always)]
                fn from(f: $from) -> $to {
                    unsafe { ::std::mem::transmute(f) }
                }
            }
        )+
    }
}

macro_rules! define_common_ops {
    ($($ty:ident),+) => {
        $(
            impl ::std::ops::Add for $ty {
                type Output = Self;
                #[inline(always)]
                fn add(self, other: Self) -> Self {
                    unsafe { simd_add(self, other) }
                }
            }

            impl ::std::ops::Sub for $ty {
                type Output = Self;
                #[inline(always)]
                fn sub(self, other: Self) -> Self {
                    unsafe { simd_sub(self, other) }
                }
            }

            impl ::std::ops::Mul for $ty {
                type Output = Self;
                #[inline(always)]
                fn mul(self, other: Self) -> Self {
                    unsafe { simd_mul(self, other) }
                }
            }
        )+
    }
}

macro_rules! define_float_ops {
    ($($ty:ident),+) => {
        $(
            impl ::std::ops::Div for $ty {
                type Output = Self;
                #[inline(always)]
                fn div(self, other: Self) -> Self {
                    unsafe { simd_div(self, other) }
                }
            }
        )+
    }
}

macro_rules! define_shifts {
    ($ty:ident, $elem:ident, $($by:ident),+) => {
        $(
            impl ::std::ops::Shl<$by> for $ty {
                type Output = Self;
                #[inline(always)]
                fn shl(self, other: $by) -> Self {
                    unsafe { simd_shl(self, $ty::splat(other as $elem)) }
                }
            }
            impl ::std::ops::Shr<$by> for $ty {
                type Output = Self;
                #[inline(always)]
                fn shr(self, other: $by) -> Self {
                    unsafe { simd_shr(self, $ty::splat(other as $elem)) }
                }
            }
        )+
    }
}

macro_rules! define_integer_ops {
    ($(($ty:ident, $elem:ident)),+) => {
        $(
            impl ::std::ops::BitAnd for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitand(self, other: Self) -> Self {
                    unsafe { simd_and(self, other) }
                }
            }
            impl ::std::ops::BitOr for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitor(self, other: Self) -> Self {
                    unsafe { simd_or(self, other) }
                }
            }
            impl ::std::ops::BitXor for $ty {
                type Output = Self;
                #[inline(always)]
                fn bitxor(self, other: Self) -> Self {
                    unsafe { simd_xor(self, other) }
                }
            }
            impl ::std::ops::Not for $ty {
                type Output = Self;
                #[inline(always)]
                fn not(self) -> Self {
                    $ty::splat(!0) ^ self
                }
            }
            define_shifts!(
                $ty, $elem,
                u8, u16, u32, u64, usize,
                i8, i16, i32, i64, isize);

            impl ::std::fmt::LowerHex for $ty {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    write!(f, "{}(", stringify!($ty))?;
                    let n = ::std::mem::size_of_val(self) / ::std::mem::size_of::<$elem>();
                    for i in 0..n {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        write!(f, "{:#x}", self.extract(i as u32))?;
                    }
                    write!(f, ")")
                }
            }
        )+
    }
}

macro_rules! define_casts {
    ($(($fromty:ident, $toty:ident, $cast:ident)),+) => {
        $(
            impl $fromty {
                #[inline(always)]
                pub fn $cast(self) -> ::simd::$toty {
                    unsafe { simd_cast(self) }
                }
            }
        )+
    }
}

/// Is a feature supported by the host CPU?
///
/// This macro performs run-time feature detection. It returns true if the host
/// CPU in which the binary is running on supports a particular feature.
#[macro_export]
macro_rules! cfg_feature_enabled {
    ($name:tt) => (
        {
            #[cfg(target_feature = $name)]
            {
                true
            }
            #[cfg(not(target_feature = $name))]
            {
                __unstable_detect_feature!($name)
            }
        }
    )
}

/// On ARM features are only detected at compile-time using
/// cfg(target_feature), so if this macro is executed the
/// feature is not supported.
#[cfg(any(target_arch = "arm",
          target_arch = "aarch64"))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
    ("neon") => { false };
    ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}

/// In all unsupported architectures using the macro is an error
#[cfg(not(any(target_arch = "x86",
              target_arch = "x86_64",
              target_arch = "arm",
              target_arch = "aarch64")))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
    ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}

#[cfg(test)]
mod tests {
    #[cfg(target_arch = "x86_64")]
    #[test]
    fn test_macros() {
        assert!(cfg_feature_enabled!("sse"));
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! gc_ref_type {
    {
        pub struct $fields_type:ident / $ref_type:ident / $storage_type:ident / $ref_storage_type:ident <'a> {
            $($field_name:ident / $field_setter_name:ident : $field_type: ty),*
        }
    } => {
        // === $storage_type: the InHeap representation of the struct
        pub struct $storage_type<'a> {
            $($field_name: <$field_type as $crate::traits::IntoHeap<'a>>::In),*
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $fields_type<'a>;

            unsafe fn mark(&self) {
                if !$crate::Heap::get_mark_bit(self) {
                    $crate::Heap::set_mark_bit(self);
                    $(
                        $crate::traits::InHeap::mark(&self.$field_name);
                    )*
                }
            }

            unsafe fn from_heap(&self) -> $fields_type<'a> {
                $fields_type {
                    $( $field_name: $crate::traits::InHeap::from_heap(&self.$field_name) ),*
                }
            }
        }

        // === $fields_type: A safe version of the struct
        #[derive(Clone, Debug)]
        pub struct $fields_type<'a> {
            $(pub $field_name: $field_type),*
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $fields_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                $storage_type {
                    $( $field_name: $crate::traits::IntoHeap::into_heap(self.$field_name) ),*
                }
            }
        }

        impl<'a> $crate::traits::IntoHeapAllocation<'a> for $fields_type<'a> {
            type Ref = $ref_type<'a>;

            fn wrap_gcref(gcref: $crate::GCRef<'a, $storage_type<'a>>) -> $ref_type<'a> {
                $ref_type(gcref)
            }
        }

        // === $ref_storage_type: The InHeap representation of a reference to the struct
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        pub struct $ref_storage_type<'a>(*mut $storage_type<'a>);

        unsafe impl<'a> $crate::traits::InHeap<'a> for $ref_storage_type<'a> {
            type Out = $ref_type<'a>;

            unsafe fn mark(&self) {
                let ptr = self.0;
                if !ptr.is_null() {
                    $crate::traits::InHeap::mark(&*ptr);
                }
            }

            unsafe fn from_heap(&self) -> $ref_type<'a> {
                $ref_type($crate::GCRef::new(self.0))
            }
        }

        // === $ref_type: A safe reference to the struct
        #[derive(Clone, Debug, PartialEq, Eq)]
        pub struct $ref_type<'a>($crate::GCRef<'a, $storage_type<'a>>);

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $ref_type<'a> {
            type In = $ref_storage_type<'a>;

            fn into_heap(self) -> $ref_storage_type<'a> {
                $ref_storage_type(self.0.as_mut_ptr())
            }
        }

        impl<'a> $ref_type<'a> {
            // Field accessors.
            $(
                pub fn $field_name(&self) -> $field_type {
                    let ptr = self.0.as_ptr();
                    unsafe {
                        $crate::traits::InHeap::from_heap(&(*ptr).$field_name)
                    }
                }

                pub fn $field_setter_name(&self, v: $field_type) {
                    let ptr = self.0.as_mut_ptr();
                    let u = $crate::traits::IntoHeap::into_heap(v);
                    unsafe {
                        (*ptr).$field_name = u;
                    }
                }
            )*

            pub fn as_mut_ptr(&self) -> *mut $storage_type<'a> {
                self.0.as_mut_ptr()
            }
        }
    }
}

#[macro_export]
macro_rules! gc_inline_enum {
    { AS_ITEM $x:item } => { $x };
    { AS_EXPR $x:expr } => { $x };

    {
        PARSE_VARIANTS $helper_name:ident
        {}
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name DONE
            $($etc)*
        }
    };

    {
        PARSE_VARIANTS $helper_name:ident
        { $variant_name:ident }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name NO_FIELDS
            {}
            $($etc)*
        }
    };

    {
        PARSE_VARIANTS $helper_name:ident
        { $variant_name:ident , $($more_variants:tt)* }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name NO_FIELDS
            { $($more_variants)* }
            $($etc)*
        }
    };

    {
        PARSE_VARIANTS $helper_name:ident
        { $variant_name:ident ( $($field_types:tt)* ) }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name ( $($field_types)* )
            { }
            $($etc)*
        }
    };

    {
        PARSE_VARIANTS $helper_name:ident
        { $variant_name:ident ( $($field_types:tt)* ), $($more_variants:tt)* }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name ( $($field_types)* )
            { $($more_variants)* }
            $($etc)*
        }
    };

    {
        DECLARE_STORAGE_TYPE DONE { $($accumulated_output:tt)* } $storage_type:ident
    } => {
        gc_inline_enum! {
            AS_ITEM
            pub enum $storage_type<'a> {
                $($accumulated_output)*
            }
        }
    };

    {
        DECLARE_STORAGE_TYPE VARIANT $variant_name:ident NO_FIELDS
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS DECLARE_STORAGE_TYPE $more_variants {
                $($accumulated_output)*
                $variant_name,
            }
            $storage_type
        }
    };

    {
        DECLARE_STORAGE_TYPE VARIANT $variant_name:ident ( $($field_type:ty),* )
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS DECLARE_STORAGE_TYPE $more_variants {
                $($accumulated_output)*
                $variant_name($(<$field_type as $crate::traits::IntoHeap<'a>>::In),*),
            }
            $storage_type
        }
    };

    {
        MARK DONE { $($accumulated_output:tt)* } $self_ref:ident, $_storage_type:ty
    } => {
        gc_inline_enum! {
            AS_EXPR
            match *$self_ref {
                $($accumulated_output)*
            }
        }
    };

    {
        MARK VARIANT $name:ident NO_FIELDS
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_ref:ident, $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS MARK $more_variants {
                $($accumulated_output)*
                $storage_type::$name => (),
            }
            $self_ref, $storage_type
        }
    };

    {
        MARK VARIANT $name:ident ( $($field_type:ty),* )
        $($etc:tt)*
    } => {
        gc_inline_enum! {
            TYPES_TO_IDENTS ( $($field_type),*, ) () (a b c d e f g h i j k l m n o p q r s t u v w x y z)
            (MARK CONTINUE_VARIANT $name $($etc)*)
        }
    };

    {
        MARK CONTINUE_VARIANT $name:ident
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_ref:ident, $storage_type:ident
        ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS MARK $more_variants {
                $($accumulated_output)*
                $storage_type::$name ( $(ref $binding),* ) => {
                    $( $crate::traits::InHeap::mark($binding); )*
                }
            }
            $self_ref, $storage_type
        }
    };

    { TYPES_TO_IDENTS () ($(($binding:ident : $btype:ty))*) $_leftovers:tt ($($ctn:tt)*) } => {
        gc_inline_enum! { $($ctn)* ($(($binding : $btype))*) }
    };
    {
        TYPES_TO_IDENTS
        ($t:ty, $($ts:ty),*)
        ($(($binding:ident : $btype:ty))*)
        ($id:ident $($ids:tt)*)
        ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            TYPES_TO_IDENTS
            ($($ts),*)
            ($(($binding : $btype))* ($id : $t))
            ($($ids)*)
            ($($ctn)*)
        }
    };

    {
        TO_HEAP DONE { $($accumulated_output:tt)* }
        $self_:expr, $_stack_type:ident / $_storage_type:ident
    } => {
        gc_inline_enum! {
            AS_EXPR
            match $self_ {
                $($accumulated_output)*
            }
        }
    };

    {
        TO_HEAP VARIANT $name:ident NO_FIELDS
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_:expr, $stack_type:ident / $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS TO_HEAP $more_variants {
                $($accumulated_output)*
                $stack_type::$name => $storage_type::$name,
            }
            $self_, $stack_type / $storage_type
        }
    };

    {
        TO_HEAP VARIANT $name:ident ( $($field_type:ty),* )
        $($etc:tt)*
    } => {
        gc_inline_enum! {
            TYPES_TO_IDENTS ( $($field_type),*, ) () (a b c d e f g h i j k l m n o p q r s t u v w x y z)
            (TO_HEAP CONTINUE_VARIANT $name $($etc)*)
        }
    };

    {
        TO_HEAP CONTINUE_VARIANT $name:ident
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_:expr, $stack_type:ident / $storage_type:ident
        ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS TO_HEAP $more_variants {
                $($accumulated_output)*
                $stack_type::$name ( $($binding),* ) =>
                    $storage_type::$name( $($crate::traits::IntoHeap::into_heap($binding)),* ),
            }
            $self_, $stack_type / $storage_type
        }
    };

    {
        FROM_HEAP DONE { $($accumulated_output:tt)* }
        $self_ref:expr, $_stack_type:ident / $_storage_type:ident
    } => {
        gc_inline_enum! {
            AS_EXPR
            match $self_ref {
                $($accumulated_output)*
            }
        }
    };

    {
        FROM_HEAP VARIANT $name:ident NO_FIELDS
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_ref:expr, $stack_type:ident / $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS FROM_HEAP $more_variants {
                $($accumulated_output)*
                &$storage_type::$name => $stack_type::$name,
            }
            $self_ref, $stack_type / $storage_type
        }
    };

    {
        FROM_HEAP VARIANT $name:ident ( $($field_type:ty),* )
        $($etc:tt)*
    } => {
        gc_inline_enum! {
            TYPES_TO_IDENTS ( $($field_type),*, ) () (a b c d e f g h i j k l m n o p q r s t u v w x y z)
            (FROM_HEAP CONTINUE_VARIANT $name $($etc)*)
        }
    };

    {
        FROM_HEAP CONTINUE_VARIANT $name:ident
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_ref:expr, $stack_type:ident / $storage_type:ident
        ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS FROM_HEAP $more_variants {
                $($accumulated_output)*
                &$storage_type::$name ( ref $($binding),* ) =>
                    $stack_type::$name( $($crate::traits::InHeap::from_heap($binding)),* ),
            }
            $self_ref, $stack_type / $storage_type
        }
    };

    {
        pub enum $stack_type:ident / $storage_type:ident <'a>
            $variants:tt
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS DECLARE_STORAGE_TYPE $variants {}
            $storage_type
        }

        gc_inline_enum! {
            AS_ITEM
            #[derive(Debug, Clone, PartialEq)]
            pub enum $stack_type<'a>
                $variants
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $stack_type<'a>;

            unsafe fn mark(&self) {
                gc_inline_enum! {
                    PARSE_VARIANTS MARK $variants {}
                    self, $storage_type
                }
            }

            unsafe fn from_heap(&self) -> $stack_type<'a> {
                gc_inline_enum! {
                    PARSE_VARIANTS FROM_HEAP $variants {}
                    self, $stack_type / $storage_type
                }
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $stack_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                gc_inline_enum! {
                    PARSE_VARIANTS TO_HEAP $variants {}
                    self, $stack_type / $storage_type
                }
            }
        }
    }
}
<commit_msg>Make `pub` optional in `gc_ref_type!{}` and `gc_inline_enum!{}`. If it is present, all types declared are `pub`. (Struct fields are declared `pub` regardless; rustc apparently accepts this without complaint even if the struct is not `pub`.)<commit_after>#[macro_export]
macro_rules! gc_ref_type {
    { @as_item $it:item } => { $it };

    {
        pub $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct (pub) $($x)*
        }
    };
    {
        struct $($x:tt)*
    } => {
        gc_ref_type! {
            @gc_heap_struct () struct $($x)*
        }
    };

    {
        @gc_heap_struct ( $($maybe_pub:tt)* )
        struct $fields_type:ident / $ref_type:ident / $storage_type:ident / $ref_storage_type:ident <'a> {
            $($field_name:ident / $field_setter_name:ident : $field_type: ty),*
        }
    } => {
        // === $storage_type: the InHeap representation of the struct
        gc_ref_type! {
            @as_item
            $($maybe_pub)* struct $storage_type<'a> {
                $( pub $field_name: <$field_type as $crate::traits::IntoHeap<'a>>::In ),*
            }
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $fields_type<'a>;

            unsafe fn mark(&self) {
                if !$crate::Heap::get_mark_bit(self) {
                    $crate::Heap::set_mark_bit(self);
                    $(
                        $crate::traits::InHeap::mark(&self.$field_name);
                    )*
                }
            }

            unsafe fn from_heap(&self) -> $fields_type<'a> {
                $fields_type {
                    $( $field_name: $crate::traits::InHeap::from_heap(&self.$field_name) ),*
                }
            }
        }

        // === $fields_type: A safe version of the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug)]
            $($maybe_pub)* struct $fields_type<'a> {
                $( pub $field_name: $field_type ),*
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $fields_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                $storage_type {
                    $( $field_name: $crate::traits::IntoHeap::into_heap(self.$field_name) ),*
                }
            }
        }

        impl<'a> $crate::traits::IntoHeapAllocation<'a> for $fields_type<'a> {
            type Ref = $ref_type<'a>;

            fn wrap_gcref(gcref: $crate::GCRef<'a, $storage_type<'a>>) -> $ref_type<'a> {
                $ref_type(gcref)
            }
        }

        // === $ref_storage_type: The InHeap representation of a reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Copy, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_storage_type<'a>(*mut $storage_type<'a>);
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $ref_storage_type<'a> {
            type Out = $ref_type<'a>;

            unsafe fn mark(&self) {
                let ptr = self.0;
                if !ptr.is_null() {
                    $crate::traits::InHeap::mark(&*ptr);
                }
            }

            unsafe fn from_heap(&self) -> $ref_type<'a> {
                $ref_type($crate::GCRef::new(self.0))
            }
        }

        // === $ref_type: A safe reference to the struct
        gc_ref_type! {
            @as_item
            #[derive(Clone, Debug, PartialEq, Eq)]
            $($maybe_pub)* struct $ref_type<'a>($crate::GCRef<'a, $storage_type<'a>>);
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $ref_type<'a> {
            type In = $ref_storage_type<'a>;

            fn into_heap(self) -> $ref_storage_type<'a> {
                $ref_storage_type(self.0.as_mut_ptr())
            }
        }

        impl<'a> $ref_type<'a> {
            // Field accessors.
            $(
                pub fn $field_name(&self) -> $field_type {
                    let ptr = self.0.as_ptr();
                    unsafe {
                        $crate::traits::InHeap::from_heap(&(*ptr).$field_name)
                    }
                }

                pub fn $field_setter_name(&self, v: $field_type) {
                    let ptr = self.0.as_mut_ptr();
                    let u = $crate::traits::IntoHeap::into_heap(v);
                    unsafe {
                        (*ptr).$field_name = u;
                    }
                }
            )*

            pub fn as_mut_ptr(&self) -> *mut $storage_type<'a> {
                self.0.as_mut_ptr()
            }
        }
    }
}

#[macro_export]
macro_rules! gc_inline_enum {
    { AS_ITEM $x:item } => { $x };
    { AS_EXPR $x:expr } => { $x };

    {
        PARSE_VARIANTS $helper_name:ident
        {}
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name DONE
            $($etc)*
        }
    };

    {
        PARSE_VARIANTS $helper_name:ident
        { $variant_name:ident }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name NO_FIELDS
            {}
            $($etc)*
        }
    };

    {
        PARSE_VARIANTS $helper_name:ident
        { $variant_name:ident , $($more_variants:tt)* }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name NO_FIELDS
            { $($more_variants)* }
            $($etc)*
        }
    };

    {
        PARSE_VARIANTS $helper_name:ident
        { $variant_name:ident ( $($field_types:tt)* ) }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name ( $($field_types)* )
            { }
            $($etc)*
        }
    };

    {
        PARSE_VARIANTS $helper_name:ident
        { $variant_name:ident ( $($field_types:tt)* ), $($more_variants:tt)* }
        $( $etc:tt )*
    } => {
        gc_inline_enum! {
            $helper_name VARIANT $variant_name ( $($field_types)* )
            { $($more_variants)* }
            $($etc)*
        }
    };

    {
        DECLARE_STORAGE_TYPE DONE { $($accumulated_output:tt)* }
        ( $($maybe_pub:tt)* ) $storage_type:ident
    } => {
        gc_inline_enum! {
            AS_ITEM
            $($maybe_pub)*
            enum $storage_type<'a> {
                $($accumulated_output)*
            }
        }
    };

    {
        DECLARE_STORAGE_TYPE VARIANT $variant_name:ident NO_FIELDS
        $more_variants:tt
        { $($accumulated_output:tt)* }
        ( $($maybe_pub:tt)* ) $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS DECLARE_STORAGE_TYPE $more_variants {
                $($accumulated_output)*
                $variant_name,
            }
            ( $($maybe_pub)* ) $storage_type
        }
    };

    {
        DECLARE_STORAGE_TYPE VARIANT $variant_name:ident ( $($field_type:ty),* )
        $more_variants:tt
        { $($accumulated_output:tt)* }
        ( $($maybe_pub:tt)* ) $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS DECLARE_STORAGE_TYPE $more_variants {
                $($accumulated_output)*
                $variant_name($(<$field_type as $crate::traits::IntoHeap<'a>>::In),*),
            }
            ( $($maybe_pub)* ) $storage_type
        }
    };

    {
        MARK DONE { $($accumulated_output:tt)* } $self_ref:ident, $_storage_type:ty
    } => {
        gc_inline_enum! {
            AS_EXPR
            match *$self_ref {
                $($accumulated_output)*
            }
        }
    };

    {
        MARK VARIANT $name:ident NO_FIELDS
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_ref:ident, $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS MARK $more_variants {
                $($accumulated_output)*
                $storage_type::$name => (),
            }
            $self_ref, $storage_type
        }
    };

    {
        MARK VARIANT $name:ident ( $($field_type:ty),* )
        $($etc:tt)*
    } => {
        gc_inline_enum! {
            TYPES_TO_IDENTS ( $($field_type),*, ) () (a b c d e f g h i j k l m n o p q r s t u v w x y z)
            (MARK CONTINUE_VARIANT $name $($etc)*)
        }
    };

    {
        MARK CONTINUE_VARIANT $name:ident
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_ref:ident, $storage_type:ident
        ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS MARK $more_variants {
                $($accumulated_output)*
                $storage_type::$name ( $(ref $binding),* ) => {
                    $( $crate::traits::InHeap::mark($binding); )*
                }
            }
            $self_ref, $storage_type
        }
    };

    { TYPES_TO_IDENTS () ($(($binding:ident : $btype:ty))*) $_leftovers:tt ($($ctn:tt)*) } => {
        gc_inline_enum! { $($ctn)* ($(($binding : $btype))*) }
    };
    {
        TYPES_TO_IDENTS
        ($t:ty, $($ts:ty),*)
        ($(($binding:ident : $btype:ty))*)
        ($id:ident $($ids:tt)*)
        ($($ctn:tt)*)
    } => {
        gc_inline_enum! {
            TYPES_TO_IDENTS
            ($($ts),*)
            ($(($binding : $btype))* ($id : $t))
            ($($ids)*)
            ($($ctn)*)
        }
    };

    {
        TO_HEAP DONE { $($accumulated_output:tt)* }
        $self_:expr, $_stack_type:ident / $_storage_type:ident
    } => {
        gc_inline_enum! {
            AS_EXPR
            match $self_ {
                $($accumulated_output)*
            }
        }
    };

    {
        TO_HEAP VARIANT $name:ident NO_FIELDS
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_:expr, $stack_type:ident / $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS TO_HEAP $more_variants {
                $($accumulated_output)*
                $stack_type::$name => $storage_type::$name,
            }
            $self_, $stack_type / $storage_type
        }
    };

    {
        TO_HEAP VARIANT $name:ident ( $($field_type:ty),* )
        $($etc:tt)*
    } => {
        gc_inline_enum! {
            TYPES_TO_IDENTS ( $($field_type),*, ) () (a b c d e f g h i j k l m n o p q r s t u v w x y z)
            (TO_HEAP CONTINUE_VARIANT $name $($etc)*)
        }
    };

    {
        TO_HEAP CONTINUE_VARIANT $name:ident
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_:expr, $stack_type:ident / $storage_type:ident
        ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS TO_HEAP $more_variants {
                $($accumulated_output)*
                $stack_type::$name ( $($binding),* ) =>
                    $storage_type::$name( $($crate::traits::IntoHeap::into_heap($binding)),* ),
            }
            $self_, $stack_type / $storage_type
        }
    };

    {
        FROM_HEAP DONE { $($accumulated_output:tt)* }
        $self_ref:expr, $_stack_type:ident / $_storage_type:ident
    } => {
        gc_inline_enum! {
            AS_EXPR
            match $self_ref {
                $($accumulated_output)*
            }
        }
    };

    {
        FROM_HEAP VARIANT $name:ident NO_FIELDS
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_ref:expr, $stack_type:ident / $storage_type:ident
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS FROM_HEAP $more_variants {
                $($accumulated_output)*
                &$storage_type::$name => $stack_type::$name,
            }
            $self_ref, $stack_type / $storage_type
        }
    };

    {
        FROM_HEAP VARIANT $name:ident ( $($field_type:ty),* )
        $($etc:tt)*
    } => {
        gc_inline_enum! {
            TYPES_TO_IDENTS ( $($field_type),*, ) () (a b c d e f g h i j k l m n o p q r s t u v w x y z)
            (FROM_HEAP CONTINUE_VARIANT $name $($etc)*)
        }
    };

    {
        FROM_HEAP CONTINUE_VARIANT $name:ident
        $more_variants:tt
        { $($accumulated_output:tt)* }
        $self_ref:expr, $stack_type:ident / $storage_type:ident
        ( $(($binding:ident : $field_type:ty))* )
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS FROM_HEAP $more_variants {
                $($accumulated_output)*
                &$storage_type::$name ( ref $($binding),* ) =>
                    $stack_type::$name( $($crate::traits::InHeap::from_heap($binding)),* ),
            }
            $self_ref, $stack_type / $storage_type
        }
    };

    {
        pub $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum (pub) $($x)*
        }
    };

    {
        enum $($x:tt)*
    } => {
        gc_inline_enum! {
            @gc_heap_enum () enum $($x)*
        }
    };

    {
        @gc_heap_enum
        ($($maybe_pub:tt)*)
        enum $stack_type:ident / $storage_type:ident <'a>
        $variants:tt
    } => {
        gc_inline_enum! {
            PARSE_VARIANTS DECLARE_STORAGE_TYPE $variants {}
            ( $($maybe_pub)* ) $storage_type
        }

        gc_inline_enum! {
            AS_ITEM
            #[derive(Debug, Clone, PartialEq)]
            $($maybe_pub)*
            enum $stack_type<'a>
                $variants
        }

        unsafe impl<'a> $crate::traits::InHeap<'a> for $storage_type<'a> {
            type Out = $stack_type<'a>;

            unsafe fn mark(&self) {
                gc_inline_enum! {
                    PARSE_VARIANTS MARK $variants {}
                    self, $storage_type
                }
            }

            unsafe fn from_heap(&self) -> $stack_type<'a> {
                gc_inline_enum! {
                    PARSE_VARIANTS FROM_HEAP $variants {}
                    self, $stack_type / $storage_type
                }
            }
        }

        unsafe impl<'a> $crate::traits::IntoHeap<'a> for $stack_type<'a> {
            type In = $storage_type<'a>;

            fn into_heap(self) -> $storage_type<'a> {
                gc_inline_enum! {
                    PARSE_VARIANTS TO_HEAP $variants {}
                    self, $stack_type / $storage_type
                }
            }
        }
    }
}
<|endoftext|>