<commit_before>#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]

extern crate collections;

use std::fmt::Show;
use std::io::fs::File;
use std::io::{IoResult, IoErrorKind};

type Err = uint;
type ParserClosure<'a,I,O> = |I|:'a -> Parser<I,O>;

//type ParserClosure<'a,I,O> = |I|:'a -> Parser<'a,I,O>;
//type ParserClosure<'a,I,O> = Fn<I, Parser<'a,I,O>>;
#[deriving(Show,PartialEq,Eq)]
pub enum Parser<I,O> {
  Done(I,O),
  Error(Err),
  //Incomplete(ParserClosure<'a,I,O>)
  //Incomplete(|I|:'a -> Parser<'a,I,O>)
  //Incomplete(fn(I) -> Parser<'a,I,O>)
}

pub trait Mapper<O,N> {
  fn map(&self, f: |O| -> Parser<O,N>) -> Parser<O,N>;
  fn mapf(&self, f: |O| -> Option<N>) -> Parser<O,N>;
}

impl<'a> Mapper<&'a [u8], &'a [u8]> for Parser<&'a [u8],&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8], &'a [u8]>) -> Parser<&'c [u8], &'a [u8]> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<&'a [u8]>) -> Parser<&'a [u8], &'a [u8]> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a> Mapper<&'a [u8],&'a [u8]> for Parser<(),&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],&'a[u8]>) -> Parser<&'c [u8], &'a [u8]> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<&'a [u8]>) -> Parser<&'a [u8], &'a [u8]> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}
impl<'a> Mapper<&'a [u8],()> for Parser<(),&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],()>) -> Parser<&'c [u8], ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<()>) -> Parser<&'a [u8], ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a> Mapper<&'a [u8],()> for Parser<&'a [u8],&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],()>) -> Parser<&'c [u8], ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<()>) -> Parser<&'a [u8], ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a> Mapper<&'a [u8],&'a str> for Parser<&'a [u8],&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],&'c str>) -> Parser<&'c [u8], &'c str> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<&'a str>) -> Parser<&'a [u8], &'a str> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a> Mapper<&'a [u8],&'a str> for Parser<(),&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],&'a str>) -> Parser<&'c [u8], &'a str> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<&'a str>) -> Parser<&'a [u8], &'a str> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a> Mapper<&'a str,()> for Parser<&'a [u8],&'a str> {
  fn map<'b,'c>(&'b self, f: |&'a str| -> Parser<&'c str,()>) -> Parser<&'c str, ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a str| -> Option<()>) -> Parser<&'a str, ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

pub trait Ender<O> {
  fn end(&self, f: |O| -> ()) -> ();
}

impl<'a> Ender<&'a [u8]> for Parser<&'a [u8],&'a [u8]> {
  fn end(&self, f: |&'a [u8]| -> ()) -> () {
    match self {
      &Error(_) => (),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => {
        f(*o)
      }
    }
  }
}
impl<'a> Ender<&'a str> for Parser<&'a [u8],&'a str> {
  fn end(&self, f: |&'a str| -> ()) -> () {
    match self {
      &Error(_) => (),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => {
        f(*o)
      }
    }
  }
}

impl<'a> Ender<&'a [u8]> for Parser<(),&'a [u8]> {
  fn end(&self, f: |&'a [u8]| -> ()) -> () {
    match self {
      &Error(_) => (),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => {
        f(*o)
      }
    }
  }
}

/***/
impl<'a>  Parser<(),&'a [u8]> {
  pub fn m2<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],()>) -> Parser<&'c [u8], ()> {
    match self {
      &Error(ref e) => Error(*e),
      &Done(_, ref o) => f(*o)
    }
  }
  pub fn m3<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],&'c [u8]>) -> Parser<&'c [u8], &'c [u8]> {
    match self {
      &Error(ref e) => Error(*e),
      &Done(_, ref o) => f(*o)
    }
  }
}
impl<'a>  Parser<&'a [u8],&'a str> {
  pub fn m4<'b,'c>(&'b self, f: |&'a str| -> Parser<&'c str,()>) -> Parser<&'c str, ()> {
    match self {
      &Error(ref e) => Error(*e),
      &Done(_, ref o) => f(*o)
    }
  }
}
/***/

pub fn accline<'a>(input: &'a [u8]) -> Parser<&'a [u8], &'a [u8]> {
  match input.iter().position(|&c| c == '\n' as u8) {
    None      => Error(0),//Incomplete(accline),
    Some(pos) => Done(input.slice_from(pos), input.slice(0, pos))
  }
}

pub fn print<T: Show>(input: T) -> Parser<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub struct FileProducer {
  size: uint,
  file: File
}

pub enum ProducerState<O> {
  Eof(O),
  Continue,
  Data(O),
  ProducerError(Err),
}

pub fn begin<'a>(input: &'a [u8]) -> Parser<(), &'a [u8]> {
  Done((), input)
}

type ParserStarterClosure<'a,I,T,O> = |Parser<(),I>|:'a -> Parser<T,O>;

impl FileProducer {
  pub fn new(filename: &str, buffer_size: uint) -> IoResult<FileProducer> {
    File::open(&Path::new(filename)).map(|f| { FileProducer {size: buffer_size, file: f} })
  }

  pub fn produce(&mut self) -> ProducerState<Vec<u8>> {
    let mut v = Vec::with_capacity(self.size);
    match self.file.push(self.size, &mut v) {
      Err(e) => {
        match e.kind {
          IoErrorKind::NoProgress => Continue,
          IoErrorKind::EndOfFile  => Eof(v),
          _          => ProducerError(0)
        }
      },
      Ok(i)  => {
        println!("read {} bytes", i);
        Data(v)
      }
    }
  }

  pub fn push<T,O>(&mut self, f: |Parser<(),&[u8]>| -> Parser<T,O>) {
    let mut v2 = Vec::new();
    loop {
      if self.file.eof() {
        println!("end");
        break;
      }
      let state = self.produce();
      let mut acc: Vec<u8> = Vec::new();
      match state {
        ProducerError(e)  => println!("error: {}", e),
        Continue => {},
        Data(v) => {
          v2.push_all(acc.as_slice());
          v2.push_all(v.as_slice());
          //acc.push_all(v.as_slice());
          //let r: &'a[u8] = acc.as_slice();
          //let data = if acc.len() == 0 { v } else { acc.push_all(v.as_slice()); acc };
          let p = Done((), v2.as_slice());
          match f(p) {
          //match f(begin(v2.as_slice())) {
            Error(e)      => println!("error, stopping: {}", e),
            //Incomplete(_) => println!("incomplete, continue"),
            Done(_, _)    => {
              //println!("end, done");
              acc.clear();
            }
          }
        },
        Eof(v) => {
          println!("GOT EOF");
          v2.push_all(acc.as_slice());
          v2.push_all(v.as_slice());
          //acc.push_all(v.as_slice());
          //let r: &'a[u8] = acc.as_slice();
          //let data = if acc.len() == 0 { v } else { acc.push_all(v.as_slice()); acc };
          let p = Done((), v2.as_slice());
          match f(p) {
          //match f(begin(v2.as_slice())) {
            Error(e)      => println!("error, stopping: {}", e),
            //Incomplete(_) => println!("incomplete, continue"),
            Done(_, _)    => {
              println!("end, done");
              acc.clear();
            }
          };
          break;
        }
      }
      v2.clear();
    }
    println!("end push");
  }
}

#[test]
fn map_fn() {
  Done((),()).map(print);
}

#[test]
fn map_closure() {
  Done((),()).map(|data| { println!("data: {}", data); Done(data,())});
  //assert_eq!(decoded.number, 10);
}

#[test]
fn t1() {
  let v1:Vec<u8> = vec![1,2,3];
  let v2 = vec![4,5,6];
  let d = Done(v1.as_slice(), v2.as_slice());
  let res = d.map(print);
  assert_eq!(res, Done(v2.as_slice(), ()));
}

#[test]
fn end_test() {
  let v1:Vec<u8> = vec![1,2,3];
  let v2 = vec![4,5,6];
  let d = Done(v1.as_slice(), v2.as_slice());
  let mut res: Vec<u8> = Vec::new();
  d.end(|v:&[u8]| res.push_all(v));
  assert_eq!(res.as_slice(), v2.as_slice());
}
<commit_msg>remove some Mapper implementations<commit_after>#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]

extern crate collections;

use std::fmt::Show;
use std::io::fs::File;
use std::io::{IoResult, IoErrorKind};

type Err = uint;
type ParserClosure<'a,I,O> = |I|:'a -> Parser<I,O>;

//type ParserClosure<'a,I,O> = |I|:'a -> Parser<'a,I,O>;
//type ParserClosure<'a,I,O> = Fn<I, Parser<'a,I,O>>;
#[deriving(Show,PartialEq,Eq)]
pub enum Parser<I,O> {
  Done(I,O),
  Error(Err),
  //Incomplete(ParserClosure<'a,I,O>)
  //Incomplete(|I|:'a -> Parser<'a,I,O>)
  //Incomplete(fn(I) -> Parser<'a,I,O>)
}

pub trait Mapper<O,N> {
  fn map(&self, f: |O| -> Parser<O,N>) -> Parser<O,N>;
  fn mapf(&self, f: |O| -> Option<N>) -> Parser<O,N>;
}

impl<'a,N> Mapper<&'a [u8], &'a [u8]> for Parser<N,&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8], &'a [u8]>) -> Parser<&'c [u8], &'a [u8]> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<&'a [u8]>) -> Parser<&'a [u8], &'a [u8]> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a,N> Mapper<&'a [u8],()> for Parser<N,&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],()>) -> Parser<&'c [u8], ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<()>) -> Parser<&'a [u8], ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a,N> Mapper<&'a [u8],&'a str> for Parser<N,&'a [u8]> {
  fn map<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],&'c str>) -> Parser<&'c [u8], &'c str> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a [u8]| -> Option<&'a str>) -> Parser<&'a [u8], &'a str> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a,N> Mapper<&'a str,()> for Parser<N,&'a str> {
  fn map<'b,'c>(&'b self, f: |&'a str| -> Parser<&'c str,()>) -> Parser<&'c str, ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |&'a str| -> Option<()>) -> Parser<&'a str, ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

impl<'a,N> Mapper<(),()> for Parser<N,()> {
  fn map<'b,'c>(&'b self, f: |()| -> Parser<(),()>) -> Parser<(), ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => f(*o)
    }
  }

  fn mapf(&self, f: |()| -> Option<()>) -> Parser<(), ()> {
    match self {
      &Error(ref e) => Error(*e),
      //&Incomplete(ref cl) => Error(0),//Incomplete(|input: &'a I| {*cl(input).mapf(f)}),
      &Done(_, ref o) => match f(*o) {
        Some(output) => Done(*o, output),
        None         => Error(0)
      }
    }
  }
}

pub trait Ender<O> {
  fn end(&self, f: |O| -> ()) -> ();
}

impl<'a> Ender<&'a [u8]> for Parser<&'a [u8],&'a [u8]> {
  fn end(&self, f: |&'a [u8]| -> ()) -> () {
    match self {
      &Error(_) => (),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => {
        f(*o)
      }
    }
  }
}
impl<'a> Ender<&'a str> for Parser<&'a [u8],&'a str> {
  fn end(&self, f: |&'a str| -> ()) -> () {
    match self {
      &Error(_) => (),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => {
        f(*o)
      }
    }
  }
}

impl<'a> Ender<&'a [u8]> for Parser<(),&'a [u8]> {
  fn end(&self, f: |&'a [u8]| -> ()) -> () {
    match self {
      &Error(_) => (),
      //&Incomplete(ref cl) => Incomplete(f), //Incomplete(|input:I| { cl(input).map(f) })
      &Done(_, ref o) => {
        f(*o)
      }
    }
  }
}

/***/
impl<'a>  Parser<(),&'a [u8]> {
  pub fn m2<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],()>) -> Parser<&'c [u8], ()> {
    match self {
      &Error(ref e) => Error(*e),
      &Done(_, ref o) => f(*o)
    }
  }
  pub fn m3<'b,'c>(&'b self, f: |&'a [u8]| -> Parser<&'c [u8],&'c [u8]>) -> Parser<&'c [u8], &'c [u8]> {
    match self {
      &Error(ref e) => Error(*e),
      &Done(_, ref o) => f(*o)
    }
  }
}
impl<'a>  Parser<&'a [u8],&'a str> {
  pub fn m4<'b,'c>(&'b self, f: |&'a str| -> Parser<&'c str,()>) -> Parser<&'c str, ()> {
    match self {
      &Error(ref e) => Error(*e),
      &Done(_, ref o) => f(*o)
    }
  }
}
/***/

pub fn accline<'a>(input: &'a [u8]) -> Parser<&'a [u8], &'a [u8]> {
  match input.iter().position(|&c| c == '\n' as u8) {
    None      => Error(0),//Incomplete(accline),
    Some(pos) => Done(input.slice_from(pos), input.slice(0, pos))
  }
}

pub fn print<T: Show>(input: T) -> Parser<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub struct FileProducer {
  size: uint,
  file: File
}

pub enum ProducerState<O> {
  Eof(O),
  Continue,
  Data(O),
  ProducerError(Err),
}

pub fn begin<'a>(input: &'a [u8]) -> Parser<(), &'a [u8]> {
  Done((), input)
}

type ParserStarterClosure<'a,I,T,O> = |Parser<(),I>|:'a -> Parser<T,O>;

impl FileProducer {
  pub fn new(filename: &str, buffer_size: uint) -> IoResult<FileProducer> {
    File::open(&Path::new(filename)).map(|f| { FileProducer {size: buffer_size, file: f} })
  }

  pub fn produce(&mut self) -> ProducerState<Vec<u8>> {
    let mut v = Vec::with_capacity(self.size);
    match self.file.push(self.size, &mut v) {
      Err(e) => {
        match e.kind {
          IoErrorKind::NoProgress => Continue,
          IoErrorKind::EndOfFile  => Eof(v),
          _          => ProducerError(0)
        }
      },
      Ok(i)  => {
        println!("read {} bytes", i);
        Data(v)
      }
    }
  }

  pub fn push<T,O>(&mut self, f: |Parser<(),&[u8]>| -> Parser<T,O>) {
    let mut v2 = Vec::new();
    loop {
      if self.file.eof() {
        println!("end");
        break;
      }
      let state = self.produce();
      let mut acc: Vec<u8> = Vec::new();
      match state {
        ProducerError(e)  => println!("error: {}", e),
        Continue => {},
        Data(v) => {
          v2.push_all(acc.as_slice());
          v2.push_all(v.as_slice());
          //acc.push_all(v.as_slice());
          //let r: &'a[u8] = acc.as_slice();
          //let data = if acc.len() == 0 { v } else { acc.push_all(v.as_slice()); acc };
          let p = Done((), v2.as_slice());
          match f(p) {
          //match f(begin(v2.as_slice())) {
            Error(e)      => println!("error, stopping: {}", e),
            //Incomplete(_) => println!("incomplete, continue"),
            Done(_, _)    => {
              //println!("end, done");
              acc.clear();
            }
          }
        },
        Eof(v) => {
          println!("GOT EOF");
          v2.push_all(acc.as_slice());
          v2.push_all(v.as_slice());
          //acc.push_all(v.as_slice());
          //let r: &'a[u8] = acc.as_slice();
          //let data = if acc.len() == 0 { v } else { acc.push_all(v.as_slice()); acc };
          let p = Done((), v2.as_slice());
          match f(p) {
          //match f(begin(v2.as_slice())) {
            Error(e)      => println!("error, stopping: {}", e),
            //Incomplete(_) => println!("incomplete, continue"),
            Done(_, _)    => {
              println!("end, done");
              acc.clear();
            }
          };
          break;
        }
      }
      v2.clear();
    }
    println!("end push");
  }
}

#[test]
fn map_fn() {
  Done((),()).map(print);
}

#[test]
fn map_closure() {
  Done((),()).map(|data| { println!("data: {}", data); Done(data,())});
  //assert_eq!(decoded.number, 10);
}

#[test]
fn t1() {
  let v1:Vec<u8> = vec![1,2,3];
  let v2 = vec![4,5,6];
  let d = Done(v1.as_slice(), v2.as_slice());
  let res = d.map(print);
  assert_eq!(res, Done(v2.as_slice(), ()));
}

#[test]
fn end_test() {
  let v1:Vec<u8> = vec![1,2,3];
  let v2 = vec![4,5,6];
  let d = Done(v1.as_slice(), v2.as_slice());
  let mut res: Vec<u8> = Vec::new();
  d.end(|v:&[u8]| res.push_all(v));
  assert_eq!(res.as_slice(), v2.as_slice());
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A one-dimensional length, tagged with its units.

use num_traits;

// Euclid has its own Zero and One traits instead of of using the num_traits equivalents.
// Unfortunately, num_traits::Zero requires Add, which opens a bag of sad things:
//  - Most importantly, for Point2D to implement Zero it would need to implement Add<Self> which we
//    don't want (we allow "Point + Vector" and "Vector + Vector" semantics and purposefully disallow
//    "Point + Point".
//  - Some operations that require, say, One and Div (for example Scale::inv) currently return a
//    type parameterized over T::Output which is ambiguous with num_traits::One because it inherits
//    Mul which also has an Output associated type. To fix it need to complicate type signatures
//    by using <T as Trait>::Output which makes the code and documentation harder to read.
//
// On the other hand, euclid::num::Zero/One are automatically implemented for all types that
// implement their num_traits counterpart. Euclid users never need to explicitly use
// euclid::num::Zero/One and can/should only manipulate the num_traits equivalents without risk
// of compatibility issues with euclid.

pub trait Zero {
    fn zero() -> Self;
}

impl<T: num_traits::Zero> Zero for T {
    fn zero() -> T {
        num_traits::Zero::zero()
    }
}

pub trait One {
    fn one() -> Self;
}

impl<T: num_traits::One> One for T {
    fn one() -> T {
        num_traits::One::one()
    }
}

/// Defines the nearest integer value to the original value.
pub trait Round: Copy {
    /// Rounds to the nearest integer value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn round(self) -> Self;
}
/// Defines the biggest integer equal or lower than the original value.
pub trait Floor: Copy {
    /// Rounds to the biggest integer equal or lower than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn floor(self) -> Self;
}
/// Defines the smallest integer equal or greater than the original value.
pub trait Ceil: Copy {
    /// Rounds to the smallest integer equal or greater than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn ceil(self) -> Self;
}

macro_rules! num_float {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                (self + 0.5).floor()
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                num_traits::Float::floor(self)
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                num_traits::Float::ceil(self)
            }
        }
    };
}
num_float!(f32);
num_float!(f64);
<commit_msg>Auto merge of #464 - kyren:master, r=nical<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! A one-dimensional length, tagged with its units.

use num_traits;

// Euclid has its own Zero and One traits instead of of using the num_traits equivalents.
// Unfortunately, num_traits::Zero requires Add, which opens a bag of sad things:
//  - Most importantly, for Point2D to implement Zero it would need to implement Add<Self> which we
//    don't want (we allow "Point + Vector" and "Vector + Vector" semantics and purposefully disallow
//    "Point + Point".
//  - Some operations that require, say, One and Div (for example Scale::inv) currently return a
//    type parameterized over T::Output which is ambiguous with num_traits::One because it inherits
//    Mul which also has an Output associated type. To fix it need to complicate type signatures
//    by using <T as Trait>::Output which makes the code and documentation harder to read.
//
// On the other hand, euclid::num::Zero/One are automatically implemented for all types that
// implement their num_traits counterpart. Euclid users never need to explicitly use
// euclid::num::Zero/One and can/should only manipulate the num_traits equivalents without risk
// of compatibility issues with euclid.

pub trait Zero {
    fn zero() -> Self;
}

impl<T: num_traits::Zero> Zero for T {
    fn zero() -> T {
        num_traits::Zero::zero()
    }
}

pub trait One {
    fn one() -> Self;
}

impl<T: num_traits::One> One for T {
    fn one() -> T {
        num_traits::One::one()
    }
}

/// Defines the nearest integer value to the original value.
pub trait Round: Copy {
    /// Rounds to the nearest integer value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn round(self) -> Self;
}
/// Defines the biggest integer equal or lower than the original value.
pub trait Floor: Copy {
    /// Rounds to the biggest integer equal or lower than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn floor(self) -> Self;
}
/// Defines the smallest integer equal or greater than the original value.
pub trait Ceil: Copy {
    /// Rounds to the smallest integer equal or greater than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    #[must_use]
    fn ceil(self) -> Self;
}

macro_rules! num_int {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                self
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                self
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                self
            }
        }
    };
}

macro_rules! num_float {
    ($ty:ty) => {
        impl Round for $ty {
            #[inline]
            fn round(self) -> $ty {
                (self + 0.5).floor()
            }
        }
        impl Floor for $ty {
            #[inline]
            fn floor(self) -> $ty {
                num_traits::Float::floor(self)
            }
        }
        impl Ceil for $ty {
            #[inline]
            fn ceil(self) -> $ty {
                num_traits::Float::ceil(self)
            }
        }
    };
}

num_int!(i16);
num_int!(u16);
num_int!(i32);
num_int!(u32);
num_int!(i64);
num_int!(u64);
num_int!(isize);
num_int!(usize);
num_float!(f32);
num_float!(f64);
<|endoftext|>


<commit_before>//! A module to parse Open Document Spreadsheets
//!
//! # Reference
//! OASIS Open Document Format for Office Application 1.2 (ODF 1.2)
//! http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.pdf

use std::io::{BufReader, Read, Seek};
use std::collections::HashMap;
use std::borrow::Cow;

use zip::read::{ZipArchive, ZipFile};
use zip::result::ZipError;
use quick_xml::Reader as XmlReader;
use quick_xml::events::Event;
use quick_xml::events::attributes::Attributes;

use {DataType, Metadata, Range, Reader};
use vba::VbaProject;
use std::marker::PhantomData;

const MIMETYPE: &'static [u8] = b"application/vnd.oasis.opendocument.spreadsheet";

type OdsReader<'a> = XmlReader<BufReader<ZipFile<'a>>>;

/// An enum for ods specific errors
#[derive(Debug, Fail)]
pub enum OdsError {
    /// Io error
    #[fail(display = "{}", _0)]
    Io(#[cause] ::std::io::Error),
    /// Zip error
    #[fail(display = "{}", _0)]
    Zip(#[cause] ::zip::result::ZipError),
    /// Xml error
    #[fail(display = "{}", _0)]
    Xml(#[cause] ::quick_xml::Error),
    /// Error while parsing string
    #[fail(display = "{}", _0)]
    Parse(#[cause] ::std::string::ParseError),
    /// Error while parsing float
    #[fail(display = "{}", _0)]
    ParseFloat(#[cause] ::std::num::ParseFloatError),

    /// Invalid MIME
    #[fail(display = "Invalid MIME type: {:?}", _0)]
    InvalidMime(Vec<u8>),
    /// File not found
    #[fail(display = "Cannot find '{}' file", _0)]
    FileNotFound(&'static str),
    /// Unexpected end of file
    #[fail(display = "Expecting {} found EOF", _0)]
    Eof(&'static str),
    /// Unexpexted error
    #[fail(display = "Expecting {} found {}", expected, found)]
    Mismatch {
        /// Expected
        expected: &'static str,
        /// Found
        found: String,
    },
}

from_err!(::std::io::Error, OdsError, Io);
from_err!(::zip::result::ZipError, OdsError, Zip);
from_err!(::quick_xml::Error, OdsError, Xml);
from_err!(::std::string::ParseError, OdsError, Parse);
from_err!(::std::num::ParseFloatError, OdsError, ParseFloat);

/// An OpenDocument Spreadsheet document parser
///
/// # Reference
/// OASIS Open Document Format for Office Application 1.2 (ODF 1.2)
/// http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.pdf
pub struct Ods<RS>
where
    RS: Read + Seek,
{
    sheets: HashMap<String, (Range<DataType>, Range<String>)>,
    metadata: Metadata,
    marker: PhantomData<RS>,
}

impl<RS: Read + Seek> Reader for Ods<RS> {
    type RS = RS;
    type Error = OdsError;

    fn new(reader: RS) -> Result<Self, OdsError>
    where
        RS: Read + Seek,
    {
        let mut zip = ZipArchive::new(reader)?;

        // check mimetype
        match zip.by_name("mimetype") {
            Ok(mut f) => {
                let mut buf = [0u8; 46];
                f.read_exact(&mut buf)?;
                if &buf[..] != MIMETYPE {
                    return Err(OdsError::InvalidMime(buf.to_vec()));
                }
            }
            Err(ZipError::FileNotFound) => return Err(OdsError::FileNotFound("mimetype")),
            Err(e) => return Err(OdsError::Zip(e)),
        }

        let (sheets, defined_names) = parse_content(zip)?;
        let metadata = Metadata {
            sheets: sheets.keys().map(|k| k.to_string()).collect(),
            names: defined_names,
        };

        Ok(Ods {
            sheets: sheets,
            metadata: metadata,
            marker: PhantomData,
        })
    }

    /// Gets `VbaProject`
    fn vba_project(&mut self) -> Option<Result<Cow<VbaProject>, OdsError>> {
        None
    }

    /// Read sheets from workbook.xml and get their corresponding path from relationships
    fn metadata(&self) -> &Metadata {
        &self.metadata
    }

    /// Read worksheet data in corresponding worksheet path
    fn worksheet_range(&mut self, name: &str) -> Option<Result<Range<DataType>, OdsError>> {
        self.sheets.get(name).map(|r| Ok(r.0.to_owned()))
    }

    /// Read worksheet data in corresponding worksheet path
    fn worksheet_formula(&mut self, name: &str) -> Option<Result<Range<String>, OdsError>> {
        self.sheets.get(name).map(|r| Ok(r.1.to_owned()))
    }
}

/// Parses content.xml and store the result in `self.content`
fn parse_content<RS: Read + Seek>(
    mut zip: ZipArchive<RS>,
) -> Result<
    (
        HashMap<String, (Range<DataType>, Range<String>)>,
        Vec<(String, String)>,
    ),
    OdsError,
> {
    let mut reader = match zip.by_name("content.xml") {
        Ok(f) => {
            let mut r = XmlReader::from_reader(BufReader::new(f));
            r.check_end_names(false)
                .trim_text(true)
                .check_comments(false)
                .expand_empty_elements(true);
            r
        }
        Err(ZipError::FileNotFound) => return Err(OdsError::FileNotFound("content.xml")),
        Err(e) => return Err(OdsError::Zip(e)),
    };
    let mut buf = Vec::new();
    let mut sheets = HashMap::new();
    let mut defined_names = Vec::new();
    loop {
        match reader.read_event(&mut buf) {
            Ok(Event::Start(ref e)) if e.name() == b"table:table" => if let Some(ref a) =
                e.attributes()
                    .filter_map(|a| a.ok())
                    .find(|a| a.key == b"table:name")
            {
                let name = a.unescape_and_decode_value(&reader).map_err(OdsError::Xml)?;
                let (range, formulas) = read_table(&mut reader)?;
                sheets.insert(name, (range, formulas));
            },
            Ok(Event::Start(ref e)) if e.name() == b"table:named-expressions" => {
                defined_names = read_named_expressions(&mut reader)?;
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(OdsError::Xml(e)),
            _ => (),
        }
        buf.clear();
    }
    Ok((sheets, defined_names))
}

fn read_table(reader: &mut OdsReader) -> Result<(Range<DataType>, Range<String>), OdsError> {
    let mut cells = Vec::new();
    let mut formulas = Vec::new();
    let mut cols = Vec::new();
    let mut buf = Vec::new();
    let mut row_buf = Vec::new();
    let mut cell_buf = Vec::new();
    cols.push(0);
    loop {
        match reader.read_event(&mut buf) {
            Ok(Event::Start(ref e)) if e.name() == b"table:table-row" => {
                read_row(
                    reader,
                    &mut row_buf,
                    &mut cell_buf,
                    &mut cells,
                    &mut formulas,
                )?;
                cols.push(cells.len());
            }
            Ok(Event::End(ref e)) if e.name() == b"table:table" => break,
            Err(e) => return Err(OdsError::Xml(e)),
            Ok(_) => (),
        }
        buf.clear();
    }
    Ok((get_range(cells, &cols), get_range(formulas, &cols)))
}

fn get_range<T: Default + Clone + PartialEq>(mut cells: Vec<T>, cols: &[usize]) -> Range<T> {
    // find smallest area with non empty Cells
    let mut row_min = None;
    let mut row_max = 0;
    let mut col_min = ::std::usize::MAX;
    let mut col_max = 0;
    {
        for (i, w) in cols.windows(2).enumerate() {
            let row = &cells[w[0]..w[1]];
            if let Some(p) = row.iter().position(|c| c != &T::default()) {
                if row_min.is_none() {
                    row_min = Some(i);
                }
                row_max = i;
                if p < col_min {
                    col_min = p;
                }
                if let Some(p) = row.iter().rposition(|c| c != &T::default()) {
                    if p > col_max {
                        col_max = p;
                    }
                }
            }
        }
    }
    let row_min = match row_min {
        Some(min) => min,
        _ => return Range::default(),
    };

    // rebuild cells into its smallest non empty area
    let cells_len = (row_max + 1 - row_min) * (col_max + 1 - col_min);
    if cells.len() != cells_len {
        let mut new_cells = Vec::with_capacity(cells_len);
        let empty_cells = vec![T::default(); col_max + 1];
        for w in cols.windows(2).skip(row_min).take(row_max + 1) {
            let row = &cells[w[0]..w[1]];
            if row.len() < col_max + 1 {
                new_cells.extend_from_slice(&row[col_min..]);
                new_cells.extend_from_slice(&empty_cells[row.len()..]);
            } else if row.len() == col_max + 1 {
                new_cells.extend_from_slice(&row[col_min..]);
            } else {
                new_cells.extend_from_slice(&row[col_min..col_max + 1]);
            }
        }
        cells = new_cells;
    }
    Range {
        start: (row_min as u32, col_min as u32),
        end: (row_max as u32, col_max as u32),
        inner: cells,
    }
}

fn read_row(
    reader: &mut OdsReader,
    row_buf: &mut Vec<u8>,
    cell_buf: &mut Vec<u8>,
    cells: &mut Vec<DataType>,
    formulas: &mut Vec<String>,
) -> Result<(), OdsError> {
    loop {
        row_buf.clear();
        match reader.read_event(row_buf) {
            Ok(Event::Start(ref e)) if e.name() == b"table:table-cell" => {
                let (value, formula, is_closed) = get_datatype(reader, e.attributes(), cell_buf)?;
                cells.push(value);
                formulas.push(formula);
                if !is_closed {
                    reader.read_to_end(b"table:table-cell", cell_buf)?;
                }
            }
            Ok(Event::End(ref e)) if e.name() == b"table:table-row" => break,
            Err(e) => return Err(OdsError::Xml(e)),
            Ok(e) => {
                return Err(OdsError::Mismatch {
                    expected: "table-cell",
                    found: format!("{:?}", e),
                })
            }
        }
    }
    Ok(())
}

/// Converts table-cell element into a `DataType`
///
/// ODF 1.2-19.385
fn get_datatype(
    reader: &mut OdsReader,
    atts: Attributes,
    buf: &mut Vec<u8>,
) -> Result<(DataType, String, bool), OdsError> {
    let mut is_string = false;
    let mut is_value_set = false;
    let mut val = DataType::Empty;
    let mut formula = String::new();
    for a in atts {
        let a = a?;
        match a.key {
            b"office:value" if !is_value_set => {
                let v = reader.decode(&a.value);
                val = DataType::Float(v.parse().map_err(OdsError::ParseFloat)?);
                is_value_set = true;
            }
            b"office:string-value" | b"office:date-value" | b"office:time-value"
                if !is_value_set =>
            {
                val = DataType::String(a.unescape_and_decode_value(reader).map_err(OdsError::Xml)?);
                is_value_set = true;
            }
            b"office:boolean-value" if !is_value_set => {
                val = DataType::Bool(&*a.value == b"TRUE");
                is_value_set = true;
            }
            b"office:value-type" if !is_value_set => is_string = &*a.value == b"string",
            b"table:formula" => {
                formula = a.unescape_and_decode_value(reader).map_err(OdsError::Xml)?;
            }
            _ => (),
        }
    }
    if !is_value_set && is_string {
        // If the value type is string and the office:string-value attribute
        // is not present, the element content defines the value.
        loop {
            buf.clear();
            match reader.read_event(buf) {
                Ok(Event::Text(ref e)) => {
                    return Ok((
                        DataType::String(e.unescape_and_decode(reader).map_err(OdsError::Xml)?),
                        formula,
                        false,
                    ));
                }
                Ok(Event::End(ref e)) if e.name() == b"table:table-cell" => {
                    return Ok((DataType::String("".to_string()), formula, true));
                }
                Err(e) => return Err(OdsError::Xml(e)),
                Ok(Event::Eof) => return Err(OdsError::Eof("table:table-cell")),
                _ => (),
            }
        }
    } else {
        Ok((val, formula, false))
    }
}

fn read_named_expressions(reader: &mut OdsReader) -> Result<Vec<(String, String)>, OdsError> {
    let mut defined_names = Vec::new();
    let mut buf = Vec::new();
    loop {
        buf.clear();
        match reader.read_event(&mut buf) {
            Ok(Event::Start(ref e))
                if e.name() == b"table:named-range" || e.name() == b"table:named-expression" =>
            {
                let mut name = String::new();
                let mut formula = String::new();
                for a in e.attributes() {
                    let a = a.map_err(OdsError::Xml)?;
                    match a.key {
                        b"table:name" => {
                            name = a.unescape_and_decode_value(reader).map_err(OdsError::Xml)?
                        }
                        b"table:cell-range-address" | b"table:expression" => {
                            formula = a.unescape_and_decode_value(reader).map_err(OdsError::Xml)?
                        }
                        _ => (),
                    }
                }
                defined_names.push((name, formula));
            }
            Ok(Event::End(ref e))
                if e.name() == b"table:named-range" || e.name() == b"table:named-expression" => {}
            Ok(Event::End(ref e)) if e.name() == b"table:named-expressions" => break,
            Err(e) => return Err(OdsError::Xml(e)),
            Ok(e) => {
                return Err(OdsError::Mismatch {
                    expected: "table:named-expressions",
                    found: format!("{:?}", e),
                })
            }
        }
    }
    Ok(defined_names)
}
<commit_msg>Fix boolean detection and missing repeated cells in ODS (#124)<commit_after>//! A module to parse Open Document Spreadsheets
//!
//! # Reference
//! OASIS Open Document Format for Office Application 1.2 (ODF 1.2)
//! http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.pdf

use std::io::{BufReader, Read, Seek};
use std::collections::HashMap;
use std::borrow::Cow;

use zip::read::{ZipArchive, ZipFile};
use zip::result::ZipError;
use quick_xml::Reader as XmlReader;
use quick_xml::events::Event;
use quick_xml::events::attributes::Attributes;

use {DataType, Metadata, Range, Reader};
use vba::VbaProject;
use std::marker::PhantomData;

const MIMETYPE: &'static [u8] = b"application/vnd.oasis.opendocument.spreadsheet";

type OdsReader<'a> = XmlReader<BufReader<ZipFile<'a>>>;

/// An enum for ods specific errors
#[derive(Debug, Fail)]
pub enum OdsError {
    /// Io error
    #[fail(display = "{}", _0)]
    Io(#[cause] ::std::io::Error),
    /// Zip error
    #[fail(display = "{}", _0)]
    Zip(#[cause] ::zip::result::ZipError),
    /// Xml error
    #[fail(display = "{}", _0)]
    Xml(#[cause] ::quick_xml::Error),
    /// Error while parsing string
    #[fail(display = "{}", _0)]
    Parse(#[cause] ::std::string::ParseError),
    /// Error while parsing integer
    #[fail(display = "{}", _0)]
    ParseInt(#[cause] ::std::num::ParseIntError),
    /// Error while parsing float
    #[fail(display = "{}", _0)]
    ParseFloat(#[cause] ::std::num::ParseFloatError),

    /// Invalid MIME
    #[fail(display = "Invalid MIME type: {:?}", _0)]
    InvalidMime(Vec<u8>),
    /// File not found
    #[fail(display = "Cannot find '{}' file", _0)]
    FileNotFound(&'static str),
    /// Unexpected end of file
    #[fail(display = "Expecting {} found EOF", _0)]
    Eof(&'static str),
    /// Unexpexted error
    #[fail(display = "Expecting {} found {}", expected, found)]
    Mismatch {
        /// Expected
        expected: &'static str,
        /// Found
        found: String,
    },
}

from_err!(::std::io::Error, OdsError, Io);
from_err!(::zip::result::ZipError, OdsError, Zip);
from_err!(::quick_xml::Error, OdsError, Xml);
from_err!(::std::string::ParseError, OdsError, Parse);
from_err!(::std::num::ParseFloatError, OdsError, ParseFloat);

/// An OpenDocument Spreadsheet document parser
///
/// # Reference
/// OASIS Open Document Format for Office Application 1.2 (ODF 1.2)
/// http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.pdf
pub struct Ods<RS>
where
    RS: Read + Seek,
{
    sheets: HashMap<String, (Range<DataType>, Range<String>)>,
    metadata: Metadata,
    marker: PhantomData<RS>,
}

impl<RS: Read + Seek> Reader for Ods<RS> {
    type RS = RS;
    type Error = OdsError;

    fn new(reader: RS) -> Result<Self, OdsError>
    where
        RS: Read + Seek,
    {
        let mut zip = ZipArchive::new(reader)?;

        // check mimetype
        match zip.by_name("mimetype") {
            Ok(mut f) => {
                let mut buf = [0u8; 46];
                f.read_exact(&mut buf)?;
                if &buf[..] != MIMETYPE {
                    return Err(OdsError::InvalidMime(buf.to_vec()));
                }
            }
            Err(ZipError::FileNotFound) => return Err(OdsError::FileNotFound("mimetype")),
            Err(e) => return Err(OdsError::Zip(e)),
        }

        let (sheets, defined_names) = parse_content(zip)?;
        let metadata = Metadata {
            sheets: sheets.keys().map(|k| k.to_string()).collect(),
            names: defined_names,
        };

        Ok(Ods {
            sheets: sheets,
            metadata: metadata,
            marker: PhantomData,
        })
    }

    /// Gets `VbaProject`
    fn vba_project(&mut self) -> Option<Result<Cow<VbaProject>, OdsError>> {
        None
    }

    /// Read sheets from workbook.xml and get their corresponding path from relationships
    fn metadata(&self) -> &Metadata {
        &self.metadata
    }

    /// Read worksheet data in corresponding worksheet path
    fn worksheet_range(&mut self, name: &str) -> Option<Result<Range<DataType>, OdsError>> {
        self.sheets.get(name).map(|r| Ok(r.0.to_owned()))
    }

    /// Read worksheet data in corresponding worksheet path
    fn worksheet_formula(&mut self, name: &str) -> Option<Result<Range<String>, OdsError>> {
        self.sheets.get(name).map(|r| Ok(r.1.to_owned()))
    }
}

/// Parses content.xml and store the result in `self.content`
fn parse_content<RS: Read + Seek>(
    mut zip: ZipArchive<RS>,
) -> Result<
    (
        HashMap<String, (Range<DataType>, Range<String>)>,
        Vec<(String, String)>,
    ),
    OdsError,
> {
    let mut reader = match zip.by_name("content.xml") {
        Ok(f) => {
            let mut r = XmlReader::from_reader(BufReader::new(f));
            r.check_end_names(false)
                .trim_text(true)
                .check_comments(false)
                .expand_empty_elements(true);
            r
        }
        Err(ZipError::FileNotFound) => return Err(OdsError::FileNotFound("content.xml")),
        Err(e) => return Err(OdsError::Zip(e)),
    };
    let mut buf = Vec::new();
    let mut sheets = HashMap::new();
    let mut defined_names = Vec::new();
    loop {
        match reader.read_event(&mut buf) {
            Ok(Event::Start(ref e)) if e.name() == b"table:table" => if let Some(ref a) =
                e.attributes()
                    .filter_map(|a| a.ok())
                    .find(|a| a.key == b"table:name")
            {
                let name = a.unescape_and_decode_value(&reader).map_err(OdsError::Xml)?;
                let (range, formulas) = read_table(&mut reader)?;
                sheets.insert(name, (range, formulas));
            },
            Ok(Event::Start(ref e)) if e.name() == b"table:named-expressions" => {
                defined_names = read_named_expressions(&mut reader)?;
            }
            Ok(Event::Eof) => break,
            Err(e) => return Err(OdsError::Xml(e)),
            _ => (),
        }
        buf.clear();
    }
    Ok((sheets, defined_names))
}

fn read_table(reader: &mut OdsReader) -> Result<(Range<DataType>, Range<String>), OdsError> {
    let mut cells = Vec::new();
    let mut formulas = Vec::new();
    let mut cols = Vec::new();
    let mut buf = Vec::new();
    let mut row_buf = Vec::new();
    let mut cell_buf = Vec::new();
    cols.push(0);
    loop {
        match reader.read_event(&mut buf) {
            Ok(Event::Start(ref e)) if e.name() == b"table:table-row" => {
                read_row(
                    reader,
                    &mut row_buf,
                    &mut cell_buf,
                    &mut cells,
                    &mut formulas,
                )?;
                cols.push(cells.len());
            }
            Ok(Event::End(ref e)) if e.name() == b"table:table" => break,
            Err(e) => return Err(OdsError::Xml(e)),
            Ok(_) => (),
        }
        buf.clear();
    }
    Ok((get_range(cells, &cols), get_range(formulas, &cols)))
}

fn get_range<T: Default + Clone + PartialEq>(mut cells: Vec<T>, cols: &[usize]) -> Range<T> {
    // find smallest area with non empty Cells
    let mut row_min = None;
    let mut row_max = 0;
    let mut col_min = ::std::usize::MAX;
    let mut col_max = 0;
    {
        for (i, w) in cols.windows(2).enumerate() {
            let row = &cells[w[0]..w[1]];
            if let Some(p) = row.iter().position(|c| c != &T::default()) {
                if row_min.is_none() {
                    row_min = Some(i);
                }
                row_max = i;
                if p < col_min {
                    col_min = p;
                }
                if let Some(p) = row.iter().rposition(|c| c != &T::default()) {
                    if p > col_max {
                        col_max = p;
                    }
                }
            }
        }
    }
    let row_min = match row_min {
        Some(min) => min,
        _ => return Range::default(),
    };

    // rebuild cells into its smallest non empty area
    let cells_len = (row_max + 1 - row_min) * (col_max + 1 - col_min);
    if cells.len() != cells_len {
        let mut new_cells = Vec::with_capacity(cells_len);
        let empty_cells = vec![T::default(); col_max + 1];
        for w in cols.windows(2).skip(row_min).take(row_max + 1) {
            let row = &cells[w[0]..w[1]];
            if row.len() < col_max + 1 {
                new_cells.extend_from_slice(&row[col_min..]);
                new_cells.extend_from_slice(&empty_cells[row.len()..]);
            } else if row.len() == col_max + 1 {
                new_cells.extend_from_slice(&row[col_min..]);
            } else {
                new_cells.extend_from_slice(&row[col_min..col_max + 1]);
            }
        }
        cells = new_cells;
    }
    Range {
        start: (row_min as u32, col_min as u32),
        end: (row_max as u32, col_max as u32),
        inner: cells,
    }
}

fn read_row(
    reader: &mut OdsReader,
    row_buf: &mut Vec<u8>,
    cell_buf: &mut Vec<u8>,
    cells: &mut Vec<DataType>,
    formulas: &mut Vec<String>,
) -> Result<(), OdsError> {
    loop {
        row_buf.clear();
        match reader.read_event(row_buf) {
            Ok(Event::Start(ref e)) if e.name() == b"table:table-cell" => {
                let mut repeats = 1;
                for a in e.attributes() {
                    let a = a?;
                    if a.key == b"table:number-columns-repeated" {
                        repeats = reader.decode(&a.value)
                            .parse()
                            .map_err(OdsError::ParseInt)?;
                        break;
                    }
                }

                let (value, formula, is_closed) = get_datatype(reader, e.attributes(), cell_buf)?;
                for _ in 0..repeats {
                    cells.push(value.clone());
                    formulas.push(formula.clone());
                }
                if !is_closed {
                    reader.read_to_end(b"table:table-cell", cell_buf)?;
                }
            }
            Ok(Event::End(ref e)) if e.name() == b"table:table-row" => break,
            Err(e) => return Err(OdsError::Xml(e)),
            Ok(e) => {
                return Err(OdsError::Mismatch {
                    expected: "table-cell",
                    found: format!("{:?}", e),
                })
            }
        }
    }
    Ok(())
}

/// Converts table-cell element into a `DataType`
///
/// ODF 1.2-19.385
fn get_datatype(
    reader: &mut OdsReader,
    atts: Attributes,
    buf: &mut Vec<u8>,
) -> Result<(DataType, String, bool), OdsError> {
    let mut is_string = false;
    let mut is_value_set = false;
    let mut val = DataType::Empty;
    let mut formula = String::new();
    for a in atts {
        let a = a?;
        match a.key {
            b"office:value" if !is_value_set => {
                let v = reader.decode(&a.value);
                val = DataType::Float(v.parse().map_err(OdsError::ParseFloat)?);
                is_value_set = true;
            }
            b"office:string-value" | b"office:date-value" | b"office:time-value"
                if !is_value_set =>
            {
                val = DataType::String(a.unescape_and_decode_value(reader).map_err(OdsError::Xml)?);
                is_value_set = true;
            }
            b"office:boolean-value" if !is_value_set => {
                let b = &*a.value == b"TRUE" || &*a.value == b"true";
                val = DataType::Bool(b);
                is_value_set = true;
            }
            b"office:value-type" if !is_value_set => is_string = &*a.value == b"string",
            b"table:formula" => {
                formula = a.unescape_and_decode_value(reader).map_err(OdsError::Xml)?;
            }
            _ => (),
        }
    }
    if !is_value_set && is_string {
        // If the value type is string and the office:string-value attribute
        // is not present, the element content defines the value.
        loop {
            buf.clear();
            match reader.read_event(buf) {
                Ok(Event::Text(ref e)) => {
                    return Ok((
                        DataType::String(e.unescape_and_decode(reader).map_err(OdsError::Xml)?),
                        formula,
                        false,
                    ));
                }
                Ok(Event::End(ref e)) if e.name() == b"table:table-cell" => {
                    return Ok((DataType::String("".to_string()), formula, true));
                }
                Err(e) => return Err(OdsError::Xml(e)),
                Ok(Event::Eof) => return Err(OdsError::Eof("table:table-cell")),
                _ => (),
            }
        }
    } else {
        Ok((val, formula, false))
    }
}

fn read_named_expressions(reader: &mut OdsReader) -> Result<Vec<(String, String)>, OdsError> {
    let mut defined_names = Vec::new();
    let mut buf = Vec::new();
    loop {
        buf.clear();
        match reader.read_event(&mut buf) {
            Ok(Event::Start(ref e))
                if e.name() == b"table:named-range" || e.name() == b"table:named-expression" =>
            {
                let mut name = String::new();
                let mut formula = String::new();
                for a in e.attributes() {
                    let a = a.map_err(OdsError::Xml)?;
                    match a.key {
                        b"table:name" => {
                            name = a.unescape_and_decode_value(reader).map_err(OdsError::Xml)?
                        }
                        b"table:cell-range-address" | b"table:expression" => {
                            formula = a.unescape_and_decode_value(reader).map_err(OdsError::Xml)?
                        }
                        _ => (),
                    }
                }
                defined_names.push((name, formula));
            }
            Ok(Event::End(ref e))
                if e.name() == b"table:named-range" || e.name() == b"table:named-expression" => {}
            Ok(Event::End(ref e)) if e.name() == b"table:named-expressions" => break,
            Err(e) => return Err(OdsError::Xml(e)),
            Ok(e) => {
                return Err(OdsError::Mismatch {
                    expected: "table:named-expressions",
                    found: format!("{:?}", e),
                })
            }
        }
    }
    Ok(defined_names)
}
<|endoftext|>


<commit_before>#![deny(intra_doc_link_resolution_failure)]

extern crate proc_macro;
extern crate protobuf;

use std::collections::hash_map::HashMap;
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};

use protobuf::descriptor::*;
use protobuf::Message;

use protobuf::prelude::*;

mod amend_io_error_util;
pub mod case_convert;
mod compiler_plugin;
mod customize;
mod enums;
mod extensions;
mod field;
mod file;
pub(crate) mod file_and_mod;
mod file_descriptor;
mod inside;
mod map;
mod message;
mod oneof;
mod protobuf_abs_path;
mod protobuf_ident;
mod protobuf_rel_path;
mod rust_name;
mod rust_types_values;
mod serde;
mod well_known_types;

pub(crate) mod rust;
pub(crate) mod scope;
pub(crate) mod strx;
pub(crate) mod syntax;

use customize::customize_from_rustproto_for_file;
pub use customize::Customize;

pub mod code_writer;

use self::code_writer::CodeWriter;
use self::enums::*;
use self::extensions::*;
use self::message::*;
#[doc(hidden)]
pub use amend_io_error_util::amend_io_error;
use map::map_entry;
use scope::FileScope;
use scope::RootScope;

use crate::file::proto_path_to_fn_file_descriptor;
use inside::protobuf_crate_path;
pub use protobuf_abs_path::ProtobufAbsolutePath;
pub use protobuf_ident::ProtobufIdent;
pub use protobuf_rel_path::ProtobufRelativePath;

use crate::rust::EXPR_VEC_NEW;
use crate::scope::WithScope;
use crate::well_known_types::gen_well_known_types_mod;
#[doc(hidden)]
pub use file::proto_name_to_rs;

fn escape_byte(s: &mut String, b: u8) {
    if b == b'\n' {
        write!(s, "\\n").unwrap();
    } else if b == b'\r' {
        write!(s, "\\r").unwrap();
    } else if b == b'\t' {
        write!(s, "\\t").unwrap();
    } else if b == b'\\' || b == b'"' {
        write!(s, "\\{}", b as char).unwrap();
    } else if b == b'\0' {
        write!(s, "\\0").unwrap();
    // ASCII printable except space
    } else if b > 0x20 && b < 0x7f {
        write!(s, "{}", b as char).unwrap();
    } else {
        write!(s, "\\x{:02x}", b).unwrap();
    }
}

fn write_file_descriptor(
    file_descriptor: &FileDescriptorProto,
    customize: &Customize,
    w: &mut CodeWriter,
) {
    w.write_line("/// `FileDescriptor` object which allows dynamic access to files");
    w.pub_fn(
        &format!(
            "file_descriptor() -> &'static {}::reflect::FileDescriptor",
            protobuf_crate_path(customize)
        ),
        |w| {
            w.lazy_static(
                "file_descriptor_lazy",
                &format!(
                    "{}::reflect::FileDescriptor",
                    protobuf_crate_path(customize)
                ),
                &format!("{}", protobuf_crate_path(customize)),
            );
            w.block("file_descriptor_lazy.get(|| {", "})", |w| {
                w.write_line(&format!("let mut deps = {};", EXPR_VEC_NEW));
                for f in &file_descriptor.dependency {
                    w.write_line(&format!(
                        "deps.push({}());",
                        proto_path_to_fn_file_descriptor(f, customize)
                    ));
                }

                let scope = FileScope { file_descriptor };

                w.write_line(&format!("let mut messages = {};", EXPR_VEC_NEW));
                for m in scope.find_messages() {
                    if map_entry(&m).is_some() {
                        continue;
                    }
                    w.write_line(&format!(
                        "messages.push(<{} as {}::Message>::descriptor_static());",
                        m.rust_name_to_file(),
                        protobuf_crate_path(customize),
                    ));
                }

                w.write_line(&format!("let mut enums = {};", EXPR_VEC_NEW));
                for e in scope.find_enums() {
                    w.write_line(&format!(
                        "enums.push(<{} as {}::ProtobufEnum>::enum_descriptor_static());",
                        e.rust_name_to_file(),
                        protobuf_crate_path(customize),
                    ));
                }

                w.write_line(&format!(
                    "{}::reflect::FileDescriptor::new(",
                    protobuf_crate_path(&customize),
                ));
                w.indented(|w| {
                    w.write_line(&format!("file_descriptor_proto(),"));
                    w.write_line(&format!("deps,"));
                    w.write_line(&format!("messages,"));
                    w.write_line(&format!("enums,"));
                });
                w.write_line(")");
            });
        },
    );
}

fn write_file_descriptor_data(
    file: &FileDescriptorProto,
    customize: &Customize,
    w: &mut CodeWriter,
) {
    let fdp_bytes = file.write_to_bytes().unwrap();
    w.write_line("static file_descriptor_proto_data: &'static [u8] = b\"\\");
    w.indented(|w| {
        const MAX_LINE_LEN: usize = 72;

        let mut s = String::new();
        for &b in &fdp_bytes {
            let prev_len = s.len();
            escape_byte(&mut s, b);
            let truncate = s.len() > MAX_LINE_LEN;
            if truncate {
                s.truncate(prev_len);
            }
            if truncate || s.len() == MAX_LINE_LEN {
                write!(s, "\\").unwrap();
                w.write_line(&s);
                s.clear();
            }
            if truncate {
                escape_byte(&mut s, b);
            }
        }
        if !s.is_empty() {
            write!(s, "\\").unwrap();
            w.write_line(&s);
            s.clear();
        }
    });
    w.write_line("\";");
    w.write_line("");
    w.write_line("/// `FileDescriptorProto` object which was a source for this generated file");
    w.pub_fn(
        &format!(
            "file_descriptor_proto() -> &'static {}::descriptor::FileDescriptorProto",
            protobuf_crate_path(customize)
        ),
        |w| {
            w.lazy_static(
                "file_descriptor_proto_lazy",
                &format!(
                    "{}::descriptor::FileDescriptorProto",
                    protobuf_crate_path(customize)
                ),
                &format!("{}", protobuf_crate_path(customize)),
            );
            w.block("file_descriptor_proto_lazy.get(|| {", "})", |w| {
                w.write_line(&format!(
                    "{}::parse_from_bytes(file_descriptor_proto_data).unwrap()",
                    protobuf_crate_path(customize)
                ));
            });
        },
    );
    w.write_line("");
    write_file_descriptor(file, &customize, w);
}

fn gen_file(
    file: &FileDescriptorProto,
    _files_map: &HashMap<&Path, &FileDescriptorProto>,
    root_scope: &RootScope,
    customize: &Customize,
    parser: &str,
) -> Option<compiler_plugin::GenResult> {
    // TODO: use it
    let mut customize = customize.clone();
    // options specified in invocation have precedence over options specified in file
    customize.update_with(&customize_from_rustproto_for_file(
        file.options.get_message(),
    ));

    let scope = FileScope {
        file_descriptor: file,
    }
    .to_scope();
    let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
        file.options.get_message().get_optimize_for() == file_options::OptimizeMode::LITE_RUNTIME
    });

    let mut v = Vec::new();

    {
        let mut w = CodeWriter::new(&mut v);

        w.write_generated_by("rust-protobuf", env!("CARGO_PKG_VERSION"), parser);

        w.write_line("");
        w.write_line(&format!("//! Generated file from `{}`", file.get_name()));
        if customize.inside_protobuf != Some(true) {
            w.write_line("");
            w.write_line("/// Generated files are compatible only with the same version");
            w.write_line("/// of protobuf runtime.");
            w.write_line(&format!(
                "const _PROTOBUF_VERSION_CHECK: () = {}::{};",
                protobuf_crate_path(&customize),
                protobuf::VERSION_IDENT
            ));
        }

        static NESTED_TYPE_NUMBER: protobuf::rt::LazyV2<i32> = protobuf::rt::LazyV2::INIT;
        let message_type_number = *NESTED_TYPE_NUMBER.get(|| {
            protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
                .get_field_by_name("message_type")
                .expect("`message_type` must exist")
                .proto()
                .get_number()
        });

        let mut path = vec![message_type_number, 0];
        for (id, message) in scope.get_messages().iter().enumerate() {
            // ignore map entries, because they are not used in map fields
            if map_entry(message).is_none() {
                path[1] = id as i32;

                w.write_line("");
                MessageGen::new(
                    message,
                    &root_scope,
                    &customize,
                    &path,
                    file.source_code_info.as_ref(),
                )
                .write(&mut w);
            }
        }

        static ENUM_TYPE_NUMBER: protobuf::rt::LazyV2<i32> = protobuf::rt::LazyV2::INIT;
        let enum_type_number = *ENUM_TYPE_NUMBER.get(|| {
            protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
                .get_field_by_name("enum_type")
                .expect("`enum_type` must exist")
                .proto()
                .get_number()
        });

        let mut path = vec![enum_type_number, 0];
        for (id, enum_type) in scope.get_enums().iter().enumerate() {
            path[1] = id as i32;

            w.write_line("");
            EnumGen::new(
                enum_type,
                &customize,
                root_scope,
                &path,
                file.source_code_info.as_ref(),
            )
            .write(&mut w);
        }

        write_extensions(file, &root_scope, &mut w, &customize);

        if !lite_runtime {
            w.write_line("");
            write_file_descriptor_data(file, &customize, &mut w);
        }
    }

    Some(compiler_plugin::GenResult {
        name: proto_name_to_rs(file.get_name()),
        content: v,
    })
}

// This function is also used externally by cargo plugin
// https://github.com/plietar/rust-protobuf-build
// So be careful changing its signature.
pub fn gen(
    file_descriptors: &[FileDescriptorProto],
    parser: &str,
    files_to_generate: &[PathBuf],
    customize: &Customize,
) -> Vec<compiler_plugin::GenResult> {
    let root_scope = RootScope {
        file_descriptors: file_descriptors,
    };

    let mut results: Vec<compiler_plugin::GenResult> = Vec::new();
    let files_map: HashMap<&Path, &FileDescriptorProto> = file_descriptors
        .iter()
        .map(|f| (Path::new(f.get_name()), f))
        .collect();

    for file_name in files_to_generate {
        let file = files_map.get(file_name.as_path()).expect(&format!(
            "file not found in file descriptors: {:?}, files: {:?}",
            file_name,
            files_map.keys()
        ));
        results.extend(gen_file(file, &files_map, &root_scope, customize, parser));
    }

    if customize.inside_protobuf.unwrap_or(false) {
        results.push(gen_well_known_types_mod(file_descriptors));
    }

    results
}

pub fn gen_and_write(
    file_descriptors: &[FileDescriptorProto],
    parser: &str,
    files_to_generate: &[PathBuf],
    out_dir: &Path,
    customize: &Customize,
) -> io::Result<()> {
    match out_dir.metadata() {
        Ok(m) => {
            if !m.is_dir() {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("{} is not a directory", out_dir.display()),
                ));
            }
        }
        Err(e) => {
            return Err(amend_io_error(
                e,
                format!("{} does not exist or not accessible", out_dir.display()),
            ));
        }
    }

    let results = gen(file_descriptors, parser, files_to_generate, customize);

    for r in &results {
        let mut file_path = out_dir.to_owned();
        file_path.push(&r.name);
        let mut file_writer = File::create(&file_path)
            .map_err(|e| amend_io_error(e, format!("failed to create {:?}", file_path)))?;
        file_writer
            .write_all(&r.content)
            .map_err(|e| amend_io_error(e, format!("failed to write to {:?}", file_path)))?;
        file_writer
            .flush()
            .map_err(|e| amend_io_error(e, format!("failed to flush {:?}", file_path)))?;
    }

    Ok(())
}

pub fn protoc_gen_rust_main() {
    compiler_plugin::plugin_main(|r| {
        let customize = Customize::parse_from_parameter(r.parameter).expect("parse options");
        gen(
            r.file_descriptors,
            "protoc --rust-out=...",
            r.files_to_generate,
            &customize,
        )
    });
}
<commit_msg>Generate modern parse function<commit_after>#![deny(intra_doc_link_resolution_failure)]

extern crate proc_macro;
extern crate protobuf;

use std::collections::hash_map::HashMap;
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::{Path, PathBuf};

use protobuf::descriptor::*;
use protobuf::Message;

use protobuf::prelude::*;

mod amend_io_error_util;
pub mod case_convert;
mod compiler_plugin;
mod customize;
mod enums;
mod extensions;
mod field;
mod file;
pub(crate) mod file_and_mod;
mod file_descriptor;
mod inside;
mod map;
mod message;
mod oneof;
mod protobuf_abs_path;
mod protobuf_ident;
mod protobuf_rel_path;
mod rust_name;
mod rust_types_values;
mod serde;
mod well_known_types;

pub(crate) mod rust;
pub(crate) mod scope;
pub(crate) mod strx;
pub(crate) mod syntax;

use customize::customize_from_rustproto_for_file;
pub use customize::Customize;

pub mod code_writer;

use self::code_writer::CodeWriter;
use self::enums::*;
use self::extensions::*;
use self::message::*;
#[doc(hidden)]
pub use amend_io_error_util::amend_io_error;
use map::map_entry;
use scope::FileScope;
use scope::RootScope;

use crate::file::proto_path_to_fn_file_descriptor;
use inside::protobuf_crate_path;
pub use protobuf_abs_path::ProtobufAbsolutePath;
pub use protobuf_ident::ProtobufIdent;
pub use protobuf_rel_path::ProtobufRelativePath;

use crate::rust::EXPR_VEC_NEW;
use crate::scope::WithScope;
use crate::well_known_types::gen_well_known_types_mod;
#[doc(hidden)]
pub use file::proto_name_to_rs;

fn escape_byte(s: &mut String, b: u8) {
    if b == b'\n' {
        write!(s, "\\n").unwrap();
    } else if b == b'\r' {
        write!(s, "\\r").unwrap();
    } else if b == b'\t' {
        write!(s, "\\t").unwrap();
    } else if b == b'\\' || b == b'"' {
        write!(s, "\\{}", b as char).unwrap();
    } else if b == b'\0' {
        write!(s, "\\0").unwrap();
    // ASCII printable except space
    } else if b > 0x20 && b < 0x7f {
        write!(s, "{}", b as char).unwrap();
    } else {
        write!(s, "\\x{:02x}", b).unwrap();
    }
}

fn write_file_descriptor(
    file_descriptor: &FileDescriptorProto,
    customize: &Customize,
    w: &mut CodeWriter,
) {
    w.write_line("/// `FileDescriptor` object which allows dynamic access to files");
    w.pub_fn(
        &format!(
            "file_descriptor() -> &'static {}::reflect::FileDescriptor",
            protobuf_crate_path(customize)
        ),
        |w| {
            w.lazy_static(
                "file_descriptor_lazy",
                &format!(
                    "{}::reflect::FileDescriptor",
                    protobuf_crate_path(customize)
                ),
                &format!("{}", protobuf_crate_path(customize)),
            );
            w.block("file_descriptor_lazy.get(|| {", "})", |w| {
                w.write_line(&format!("let mut deps = {};", EXPR_VEC_NEW));
                for f in &file_descriptor.dependency {
                    w.write_line(&format!(
                        "deps.push({}());",
                        proto_path_to_fn_file_descriptor(f, customize)
                    ));
                }

                let scope = FileScope { file_descriptor };

                w.write_line(&format!("let mut messages = {};", EXPR_VEC_NEW));
                for m in scope.find_messages() {
                    if map_entry(&m).is_some() {
                        continue;
                    }
                    w.write_line(&format!(
                        "messages.push(<{} as {}::Message>::descriptor_static());",
                        m.rust_name_to_file(),
                        protobuf_crate_path(customize),
                    ));
                }

                w.write_line(&format!("let mut enums = {};", EXPR_VEC_NEW));
                for e in scope.find_enums() {
                    w.write_line(&format!(
                        "enums.push(<{} as {}::ProtobufEnum>::enum_descriptor_static());",
                        e.rust_name_to_file(),
                        protobuf_crate_path(customize),
                    ));
                }

                w.write_line(&format!(
                    "{}::reflect::FileDescriptor::new(",
                    protobuf_crate_path(&customize),
                ));
                w.indented(|w| {
                    w.write_line(&format!("file_descriptor_proto(),"));
                    w.write_line(&format!("deps,"));
                    w.write_line(&format!("messages,"));
                    w.write_line(&format!("enums,"));
                });
                w.write_line(")");
            });
        },
    );
}

fn write_file_descriptor_data(
    file: &FileDescriptorProto,
    customize: &Customize,
    w: &mut CodeWriter,
) {
    let fdp_bytes = file.write_to_bytes().unwrap();
    w.write_line("static file_descriptor_proto_data: &'static [u8] = b\"\\");
    w.indented(|w| {
        const MAX_LINE_LEN: usize = 72;

        let mut s = String::new();
        for &b in &fdp_bytes {
            let prev_len = s.len();
            escape_byte(&mut s, b);
            let truncate = s.len() > MAX_LINE_LEN;
            if truncate {
                s.truncate(prev_len);
            }
            if truncate || s.len() == MAX_LINE_LEN {
                write!(s, "\\").unwrap();
                w.write_line(&s);
                s.clear();
            }
            if truncate {
                escape_byte(&mut s, b);
            }
        }
        if !s.is_empty() {
            write!(s, "\\").unwrap();
            w.write_line(&s);
            s.clear();
        }
    });
    w.write_line("\";");
    w.write_line("");
    w.write_line("/// `FileDescriptorProto` object which was a source for this generated file");
    w.pub_fn(
        &format!(
            "file_descriptor_proto() -> &'static {}::descriptor::FileDescriptorProto",
            protobuf_crate_path(customize)
        ),
        |w| {
            w.lazy_static(
                "file_descriptor_proto_lazy",
                &format!(
                    "{}::descriptor::FileDescriptorProto",
                    protobuf_crate_path(customize)
                ),
                &format!("{}", protobuf_crate_path(customize)),
            );
            w.block("file_descriptor_proto_lazy.get(|| {", "})", |w| {
                w.write_line(&format!(
                    "{}::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()",
                    protobuf_crate_path(customize)
                ));
            });
        },
    );
    w.write_line("");
    write_file_descriptor(file, &customize, w);
}

fn gen_file(
    file: &FileDescriptorProto,
    _files_map: &HashMap<&Path, &FileDescriptorProto>,
    root_scope: &RootScope,
    customize: &Customize,
    parser: &str,
) -> Option<compiler_plugin::GenResult> {
    // TODO: use it
    let mut customize = customize.clone();
    // options specified in invocation have precedence over options specified in file
    customize.update_with(&customize_from_rustproto_for_file(
        file.options.get_message(),
    ));

    let scope = FileScope {
        file_descriptor: file,
    }
    .to_scope();
    let lite_runtime = customize.lite_runtime.unwrap_or_else(|| {
        file.options.get_message().get_optimize_for() == file_options::OptimizeMode::LITE_RUNTIME
    });

    let mut v = Vec::new();

    {
        let mut w = CodeWriter::new(&mut v);

        w.write_generated_by("rust-protobuf", env!("CARGO_PKG_VERSION"), parser);

        w.write_line("");
        w.write_line(&format!("//! Generated file from `{}`", file.get_name()));
        if customize.inside_protobuf != Some(true) {
            w.write_line("");
            w.write_line("/// Generated files are compatible only with the same version");
            w.write_line("/// of protobuf runtime.");
            w.write_line(&format!(
                "const _PROTOBUF_VERSION_CHECK: () = {}::{};",
                protobuf_crate_path(&customize),
                protobuf::VERSION_IDENT
            ));
        }

        static NESTED_TYPE_NUMBER: protobuf::rt::LazyV2<i32> = protobuf::rt::LazyV2::INIT;
        let message_type_number = *NESTED_TYPE_NUMBER.get(|| {
            protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
                .get_field_by_name("message_type")
                .expect("`message_type` must exist")
                .proto()
                .get_number()
        });

        let mut path = vec![message_type_number, 0];
        for (id, message) in scope.get_messages().iter().enumerate() {
            // ignore map entries, because they are not used in map fields
            if map_entry(message).is_none() {
                path[1] = id as i32;

                w.write_line("");
                MessageGen::new(
                    message,
                    &root_scope,
                    &customize,
                    &path,
                    file.source_code_info.as_ref(),
                )
                .write(&mut w);
            }
        }

        static ENUM_TYPE_NUMBER: protobuf::rt::LazyV2<i32> = protobuf::rt::LazyV2::INIT;
        let enum_type_number = *ENUM_TYPE_NUMBER.get(|| {
            protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
                .get_field_by_name("enum_type")
                .expect("`enum_type` must exist")
                .proto()
                .get_number()
        });

        let mut path = vec![enum_type_number, 0];
        for (id, enum_type) in scope.get_enums().iter().enumerate() {
            path[1] = id as i32;

            w.write_line("");
            EnumGen::new(
                enum_type,
                &customize,
                root_scope,
                &path,
                file.source_code_info.as_ref(),
            )
            .write(&mut w);
        }

        write_extensions(file, &root_scope, &mut w, &customize);

        if !lite_runtime {
            w.write_line("");
            write_file_descriptor_data(file, &customize, &mut w);
        }
    }

    Some(compiler_plugin::GenResult {
        name: proto_name_to_rs(file.get_name()),
        content: v,
    })
}

// This function is also used externally by cargo plugin
// https://github.com/plietar/rust-protobuf-build
// So be careful changing its signature.
pub fn gen(
    file_descriptors: &[FileDescriptorProto],
    parser: &str,
    files_to_generate: &[PathBuf],
    customize: &Customize,
) -> Vec<compiler_plugin::GenResult> {
    let root_scope = RootScope {
        file_descriptors: file_descriptors,
    };

    let mut results: Vec<compiler_plugin::GenResult> = Vec::new();
    let files_map: HashMap<&Path, &FileDescriptorProto> = file_descriptors
        .iter()
        .map(|f| (Path::new(f.get_name()), f))
        .collect();

    for file_name in files_to_generate {
        let file = files_map.get(file_name.as_path()).expect(&format!(
            "file not found in file descriptors: {:?}, files: {:?}",
            file_name,
            files_map.keys()
        ));
        results.extend(gen_file(file, &files_map, &root_scope, customize, parser));
    }

    if customize.inside_protobuf.unwrap_or(false) {
        results.push(gen_well_known_types_mod(file_descriptors));
    }

    results
}

pub fn gen_and_write(
    file_descriptors: &[FileDescriptorProto],
    parser: &str,
    files_to_generate: &[PathBuf],
    out_dir: &Path,
    customize: &Customize,
) -> io::Result<()> {
    match out_dir.metadata() {
        Ok(m) => {
            if !m.is_dir() {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("{} is not a directory", out_dir.display()),
                ));
            }
        }
        Err(e) => {
            return Err(amend_io_error(
                e,
                format!("{} does not exist or not accessible", out_dir.display()),
            ));
        }
    }

    let results = gen(file_descriptors, parser, files_to_generate, customize);

    for r in &results {
        let mut file_path = out_dir.to_owned();
        file_path.push(&r.name);
        let mut file_writer = File::create(&file_path)
            .map_err(|e| amend_io_error(e, format!("failed to create {:?}", file_path)))?;
        file_writer
            .write_all(&r.content)
            .map_err(|e| amend_io_error(e, format!("failed to write to {:?}", file_path)))?;
        file_writer
            .flush()
            .map_err(|e| amend_io_error(e, format!("failed to flush {:?}", file_path)))?;
    }

    Ok(())
}

pub fn protoc_gen_rust_main() {
    compiler_plugin::plugin_main(|r| {
        let customize = Customize::parse_from_parameter(r.parameter).expect("parse options");
        gen(
            r.file_descriptors,
            "protoc --rust-out=...",
            r.files_to_generate,
            &customize,
        )
    });
}
<|endoftext|>