<commit_before>#![crate_name = "rustyredis"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;
use std::i64::parse_bytes;

// TODO: might need custom parse_bytes
// TODO: need custom readline for bulk items

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(i64),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String, //this probably needs to be changed somehow
  reply: RedisObject,
  pos: uint, //might be needed in future, with dealing with multiple replies
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int, // async flag?
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &str> {
    match parse_bytes(s.as_bytes(), 10) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn create_string(&self, mut buf: BufReader, len: uint) -> Result<RedisObject, &str> {
    match buf.read_to_string() {
      Ok(s) => {
        if len + 2 != s.len() { // include \r\n
          return Err("Invalid string for create_string: lengths do not matchup");
        }
        let ns = s.as_slice().trim();
        Ok(RedisString(ns.to_string()))
      },
      Err(_) => Err("Invalid string for create_string") // would be nice to not ignore this error
    }
  }

  fn process_line_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => self.reply = RedisStatus(nns.to_string()),
          RedisReplyError => self.reply = RedisError(nns.to_string()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => self.reply = n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();
        let mut len: uint = 0;
        match parse_bytes(nns.as_bytes(), 10){
          Some(n) => {
            if n == -1{
              self.rstack[self.ridx as uint].kind = RedisReplyNil;
            }
            else{
              len = n as uint;
            }
          },
          None => { return Err("Invalid length in reply for process_bulk_item") }
        };

        match self.rstack[self.ridx as uint].kind {
          RedisReplyString => match self.create_string(reader, len) {
            Ok(s) => self.reply = s,
            Err(e) => return Err(e)
          },
          RedisReplyNil => self.reply = RedisNil,
          _ => return Err("Invalid type for process_bulk_item")
        }
        Ok(())
      }
      Err(e) => Err(e.desc)
    }
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    match slice.char_at(0) {
      '-' => kind = RedisReplyError,
      '+' => kind = RedisReplyStatus,
      ':' => kind = RedisReplyInteger,
      '$' => kind = RedisReplyString,
      '*' => kind = RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    }

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }
    self.buf.truncate(0);
    self.len = 0;
    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, cmd: &str, args: &[&str]) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    let mut len = cmd.len();
    c = c.append("$");
    c = c.append(len.to_string().as_slice());
    c = c.append("\r\n");
    c = c.append(cmd);
    c = c.append("\r\n");
    argc = argc + 1;

    for arg in args.iter(){
      len = arg.len();
      c = c.append("$");
      c = c.append(len.to_string().as_slice());
      c = c.append("\r\n");
      c = c.append(*arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_string().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn check_error(&self) -> bool {
    match self.err {
      RedisNoError => false,
      _ => true
    }
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); }
      _ => ()
    }
  }

  fn buffer_read(&mut self) {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); },
      Err(e) => { self.set_error(RedisIoError, e.desc); }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();

        if self.check_error() {
          return Err("Error. Check error members.");
        }
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found. Check error members.")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, cmd: &str, args: &[&str]) -> Result<Option<RedisObject>, &str> {
    self.obuf = self.format_command(cmd, args);
    self.block_for_reply()
  }
}

#[cfg(test)]
mod test {
  #[test]
  fn test_connect(){
    let _ = ::RedisContext::connect("127.0.0.1", 6379);
  }

  #[test]
  fn test_command(){
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("PING", []);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisStatus(s) => assert!(s.eq(&"PONG".to_string())),
          _ => fail!("Didn't return correct reply type.")
        },
        None => fail!("Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }
  }

  #[test]
  fn test_reply_types() {
    // Integer
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("APPEND", ["mykey", "test"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 4),
          _ => fail!("INTEGER: Didn't return correct reply type.")
        },
        None => fail!("INTEGER: Didn't return anything.")
      },
      Err(e) => fail!("INTEGER: {}", e)
    }

    // String
    let r = c.command("GET", ["mykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisString(s) => assert!(s.eq(&"test".to_string())),
          _ => fail!("STRING: Didn't return correct reply type.")
        },
        None => fail!("STRING: Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }

    // cleanup
    let r = c.command("DEL", ["mykey"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 1),
          _ => fail!("DELETE: cleanup failed")
        },
        None => fail!("DELETE: cleanup failed")
      },
      Err(_) => fail!("DELETE: cleanup failed")
    }
  }

  #[test]
  fn test_nil_reply() {
    let mut context = ::RedisContext::connect("127.0.0.1", 6379);
    let r = context.command("GET", ["nomykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          super::RedisNil => return,
          _ => fail!("NIL: Didn't return correct reply type.")
        },
        None => fail!("NIL: Didn't return anything."),
      },
      Err(e) => fail!("{}", e)
    }
  }
}

<commit_msg>Update TODO<commit_after>#![crate_name = "rustyredis"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;
use std::i64::parse_bytes;

// TODO: need custom readline for bulk items

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(i64),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String, //this probably needs to be changed somehow
  reply: RedisObject,
  pos: uint, //might be needed in future, with dealing with multiple replies
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int, // async flag?
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &str> {
    match parse_bytes(s.as_bytes(), 10) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn create_string(&self, mut buf: BufReader, len: uint) -> Result<RedisObject, &str> {
    match buf.read_to_string() {
      Ok(s) => {
        if len + 2 != s.len() { // include \r\n
          return Err("Invalid string for create_string: lengths do not matchup");
        }
        let ns = s.as_slice().trim();
        Ok(RedisString(ns.to_string()))
      },
      Err(_) => Err("Invalid string for create_string") // would be nice to not ignore this error
    }
  }

  fn process_line_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => self.reply = RedisStatus(nns.to_string()),
          RedisReplyError => self.reply = RedisError(nns.to_string()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => self.reply = n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();
        let mut len: uint = 0;
        match parse_bytes(nns.as_bytes(), 10){
          Some(n) => {
            if n == -1{
              self.rstack[self.ridx as uint].kind = RedisReplyNil;
            }
            else{
              len = n as uint;
            }
          },
          None => { return Err("Invalid length in reply for process_bulk_item") }
        };

        match self.rstack[self.ridx as uint].kind {
          RedisReplyString => match self.create_string(reader, len) {
            Ok(s) => self.reply = s,
            Err(e) => return Err(e)
          },
          RedisReplyNil => self.reply = RedisNil,
          _ => return Err("Invalid type for process_bulk_item")
        }
        Ok(())
      }
      Err(e) => Err(e.desc)
    }
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    match slice.char_at(0) {
      '-' => kind = RedisReplyError,
      '+' => kind = RedisReplyStatus,
      ':' => kind = RedisReplyInteger,
      '$' => kind = RedisReplyString,
      '*' => kind = RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    }

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }
    self.buf.truncate(0);
    self.len = 0;
    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, cmd: &str, args: &[&str]) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    let mut len = cmd.len();
    c = c.append("$");
    c = c.append(len.to_string().as_slice());
    c = c.append("\r\n");
    c = c.append(cmd);
    c = c.append("\r\n");
    argc = argc + 1;

    for arg in args.iter(){
      len = arg.len();
      c = c.append("$");
      c = c.append(len.to_string().as_slice());
      c = c.append("\r\n");
      c = c.append(*arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_string().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn check_error(&self) -> bool {
    match self.err {
      RedisNoError => false,
      _ => true
    }
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); }
      _ => ()
    }
  }

  fn buffer_read(&mut self) {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); },
      Err(e) => { self.set_error(RedisIoError, e.desc); }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();

        if self.check_error() {
          return Err("Error. Check error members.");
        }
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found. Check error members.")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, cmd: &str, args: &[&str]) -> Result<Option<RedisObject>, &str> {
    self.obuf = self.format_command(cmd, args);
    self.block_for_reply()
  }
}

#[cfg(test)]
mod test {
  #[test]
  fn test_connect(){
    let _ = ::RedisContext::connect("127.0.0.1", 6379);
  }

  #[test]
  fn test_command(){
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("PING", []);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisStatus(s) => assert!(s.eq(&"PONG".to_string())),
          _ => fail!("Didn't return correct reply type.")
        },
        None => fail!("Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }
  }

  #[test]
  fn test_reply_types() {
    // Integer
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("APPEND", ["mykey", "test"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 4),
          _ => fail!("INTEGER: Didn't return correct reply type.")
        },
        None => fail!("INTEGER: Didn't return anything.")
      },
      Err(e) => fail!("INTEGER: {}", e)
    }

    // String
    let r = c.command("GET", ["mykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisString(s) => assert!(s.eq(&"test".to_string())),
          _ => fail!("STRING: Didn't return correct reply type.")
        },
        None => fail!("STRING: Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }

    // cleanup
    let r = c.command("DEL", ["mykey"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 1),
          _ => fail!("DELETE: cleanup failed")
        },
        None => fail!("DELETE: cleanup failed")
      },
      Err(_) => fail!("DELETE: cleanup failed")
    }
  }

  #[test]
  fn test_nil_reply() {
    let mut context = ::RedisContext::connect("127.0.0.1", 6379);
    let r = context.command("GET", ["nomykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          super::RedisNil => return,
          _ => fail!("NIL: Didn't return correct reply type.")
        },
        None => fail!("NIL: Didn't return anything."),
      },
      Err(e) => fail!("{}", e)
    }
  }
}

<|endoftext|>


<commit_before><commit_msg>Add meat and potatoes of expression matching<commit_after>use expr::Expression;
use tokenizer::parse_string;

fn get_prefixes<T: Clone+Copy>(v: &Vec<T>) -> Vec<Vec<T>> {
    let prefixes: Vec<Vec<T>> = v.iter().scan(Vec::new(), |pv, c| {
        pv.push(*c);
        Some(pv.clone())
    }).collect();

    // Need to stick the empty string on top of it.
    let mut result = vec![Vec::new()];
    for prefix in prefixes.iter() {
        result.push(prefix.clone())
    }
    result
}

fn drop_n<T: Clone>(v: Vec<T>, n: usize) -> Vec<T> {
    v.iter().skip(n).map(|x| x.clone()).collect()
}

#[allow(dead_code)]
fn match_expr_slow(e: Expression, s: Vec<char>) -> bool {
    match e {
        Expression::Char(c) => s.len() == 1 && c == s[0],
        Expression::Numeral => {
            let numerals: Vec<_> = (('0' as u8)..(('9' as u8) + 1)).map(|c| c as char).collect();
            s.len() == 1 && numerals.contains(&s[0])
        },
        Expression::Lowercase => {
            let lowers: Vec<_> = (('a' as u8)..(('z' as u8) + 1)).map(|c| c as char).collect();
            s.len() == 1 && lowers.contains(&s[0])
        },
        Expression::Uppercase => {
            let uppers: Vec<_> = (('A' as u8)..(('Z' as u8) + 1)).map(|c| c as char).collect();
            s.len() == 1 && uppers.contains(&s[0])
        },

        Expression::Wildcard => s.len() == 1,

        Expression::Any(exprs) => {
            if exprs.is_empty() {
                s.is_empty()
            } else {
                exprs.iter().any(move |e| match_expr(e.clone(), s.clone()))
            }
        },

        Expression::None(exprs) => !match_expr(Expression::Any(exprs), s),
        Expression::All(exprs) => {

            // Only the empty string matches empty exprs...
            if exprs.is_empty() {
                return s.is_empty();
            }

            // If s is empty, then maybe it can satisfy each of the exprs in sequence...
            if s.is_empty() {
                return exprs.iter().all(|expr| match_expr(expr.clone(), s.clone()))
            }

            // We can short-circuit this for All's that have only one expr...
            if exprs.len() == 1 {
                return match_expr(exprs[0].clone(), s);
            }

            // Go through each prefix -- if it satisfies the expression AND the
            // remaining part of the string satisfies the rest of the expressions, then
            // return true.

            let expr = exprs.first().unwrap(); // Expressions are non-empty
            for pre in get_prefixes(&s) {
                let rest_of_s = drop_n(s.clone(), pre.len());
                let this_is_good = match_expr(expr.clone(), pre);
                let rest_is_good =
                    match_expr(Expression::All(drop_n(exprs.clone(), 1)), rest_of_s);

                if this_is_good && rest_is_good { return true }
            }

            // If we get to here, it means that we couldn't match this expr...
            false
        },

        Expression::NoneOrMore(expr_box) => {
            // Match it as many times as possible, and if we can't, that's OK.
            for pre in get_prefixes(&s) {
                let rest_of_s = drop_n(s.clone(), pre.len());

                if match_expr((*expr_box).clone(), pre) {
                    return match_expr(Expression::NoneOrMore(expr_box), rest_of_s);
                }
            }

            // We better have matched it none times...
            s.is_empty()
        },

        Expression::OneOrMore(expr_box) => {
            // Match it as many times as possible, but we need to match it at least once.
            if s.is_empty() {
                return false;
            }

            for pre in get_prefixes(&s) {
                let rest_of_s = drop_n(s.clone(), pre.len());

                // If we checked it once, then we need none or more...
                if match_expr((*expr_box).clone(), pre) {
                    return match_expr(Expression::NoneOrMore(expr_box), rest_of_s);
                }
            }

            // We didn't match it
            false
        },

        // Either it's empty (none) or it exactly matches the expr (one)
        Expression::NoneOrOne(expr_box) =>
            s.is_empty() || match_expr((*expr_box).clone(), s.clone())
    }
}

fn match_expr_fast(e: Expression, _s: Vec<char>) -> bool {
    let mut expr_stack = vec![e];
    let mut s = _s.clone();

    loop {
//        println!("{:?}", (expr_stack.clone(), s.clone()));
//        ::std::thread::sleep(::std::time::Duration::new(1, 0));

        let e = expr_stack.pop().unwrap();

        match e {
            Expression::Char(c) => {
                if s.len() == 0 || s[0] != c {
                    return false
                }
                s = drop_n(s.clone(), 1);
            },

            Expression::Numeral => {
                let numerals: Vec<_> = (('0' as u8)..(('9' as u8) + 1))
                    .map(|c| c as char)
                    .collect();
                if s.len() == 0 || !(numerals.contains(&s[0])) {
                    return false;
                }
                s = drop_n(s.clone(), 1);
            },

            Expression::Lowercase => {
                let lowers: Vec<_> = (('a' as u8)..(('z' as u8) + 1))
                    .map(|c| c as char)
                    .collect();
                if s.len() == 0 || !(lowers.contains(&s[0])) {
                    return false;
                }
                s = drop_n(s.clone(), 1);
            },

            Expression::Uppercase => {
                let uppers: Vec<_> = (('A' as u8)..(('Z' as u8) + 1))
                    .map(|c| c as char)
                    .collect();
                if s.len() == 0 || !(uppers.contains(&s[0])) {
                    return false;
                }
                s = drop_n(s.clone(), 1);
            },

            Expression::Wildcard => {
                if s.len() == 0 {
                    return false;
                }
                s = drop_n(s.clone(), 1);
            }

            Expression::None(exprs) => {
                // We have to match at least some character...
                if !exprs.is_empty() {
                    if s.is_empty() {
                        return false;
                    } else {
                        return exprs.iter().all(|expr| {
                            !match_expr(expr.clone(), vec![s[0]])
                        });
                    }
                }
            },

            Expression::Any(exprs) => {
                if exprs.len() <= 1 {
                    for expr in exprs {
                        expr_stack.push(expr);
                    }
                } else {
                    return exprs.iter().any(|expr| {
                        let mut stack = expr_stack.clone();
                        stack.push(expr.clone());
                        stack.reverse();
                        match_expr(Expression::All(stack), s.clone())
                    });
                }
            },

            Expression::All(exprs) => {
                let mut exprs_rev = exprs.clone();
                exprs_rev.reverse();
                for expr in exprs_rev {
                    expr_stack.push(expr.clone());
                }
            },

            Expression::NoneOrMore(expr_box) => {
                if !(s.is_empty()) {
                    // More?
                    let more = {
                        let mut stack = expr_stack.clone();
                        stack.push(Expression::NoneOrMore(expr_box.clone()));
                        stack.push((*expr_box).clone());
                        stack.reverse();
                        match_expr(Expression::All(stack), s.clone())
                    };

                    if more { return true; }

                    let mut stack = expr_stack.clone();
                    stack.reverse();
                    return match_expr(Expression::All(stack), s.clone());
                }
            },

            Expression::OneOrMore(expr_box) => {
                let mut stack = expr_stack.clone();
                stack.push(Expression::NoneOrMore(expr_box.clone()));
                stack.push((*expr_box).clone());
                stack.reverse();
                return match_expr(Expression::All(stack), s.clone());
            },

            Expression::NoneOrOne(expr_box) => {
                // One?
                let one = {
                    let mut stack = expr_stack.clone();
                    stack.push((*expr_box).clone());
                    stack.reverse();
                    match_expr(Expression::All(stack), s.clone())
                };

                if one { return true; }

                // None?
                let mut stack = expr_stack.clone();
                stack.reverse();
                return match_expr(Expression::All(stack), s.clone());
            },
        }

        if expr_stack.is_empty() {
            return s.is_empty();
        }
    }
}

fn match_expr(e: Expression, s: Vec<char>) -> bool {
    match_expr_fast(e, s)
}

pub trait SatisfiesRegex : Sized {
    // Returns None on success and an error otherwise.
    fn is_gracefully_satisfied_by(self, s: String)
                                  -> Option<&'static str>;
    fn is_satisfied_by(self, s: String) -> bool {
        None == self.is_gracefully_satisfied_by(s)
    }

    fn is_not_satisfied_by(self, s: String) -> bool { !self.is_satisfied_by(s) }
}

impl SatisfiesRegex for String {
    fn is_gracefully_satisfied_by(self, s: String)
                                  -> Option<&'static str> {
        let tokens = match parse_string(self) {
            Err(e) => return Some(e),
            Ok(t) => t
        };

        let expr = match Expression::new(tokens) {
            Err(e) => return Some(e),
            Ok(ex) => ex
        };

        if match_expr(expr, s.chars().collect()) {
            None
        } else {
            Some("String does not match regex")
        }
    }
}

impl<'a> SatisfiesRegex for &'a str {
    fn is_gracefully_satisfied_by(self, s: String)
                                  -> Option<&'static str> {
        String::from(self).is_gracefully_satisfied_by(s)
    }
}

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

    #[test]
    fn it_can_match_literals() {
        assert!("aaaaa".is_satisfied_by(String::from("aaaaa")));
        assert!("aaaaa".is_not_satisfied_by(String::from("abaaa")));
        assert!("hello".is_satisfied_by(String::from("hello")));
        assert!("it's me".is_satisfied_by(String::from("it's me")));

        // These characters aren't special.
        assert!("!@#$%^&&".is_satisfied_by(String::from("!@#$%^&&")));
        assert!("\\*\\*\\*\\*".is_satisfied_by(String::from("****")));
        assert!("\\*\\*\\*\\*".is_not_satisfied_by(String::from("help")));
    }

    #[test]
    fn it_can_match_wildcards() {
        assert!(".....".is_satisfied_by(String::from("hello")));
        assert!(".....".is_satisfied_by(String::from("great")));
        assert!(".u.e".is_satisfied_by(String::from("puce")));
        assert!(".u.e".is_satisfied_by(String::from("lute")));

        assert!("....".is_not_satisfied_by(String::from("sorry")));
        assert!(".u.e".is_not_satisfied_by(String::from("flute")));
    }

    #[test]
    fn it_can_match_none_or_more() {
        assert!(".*".is_satisfied_by(String::from("everything")));
        assert!(".*".is_satisfied_by(String::from("seriously, everything")));
        assert!(".*".is_satisfied_by(String::from("I can do so many weird things here")));
        assert!(".*".is_satisfied_by(String::from("M4yb3 l33t sp33k?")));
        assert!(".*".is_satisfied_by(String::from("Even the empty string:")));
        assert!(".*".is_satisfied_by(String::from("")));
        assert!(".*".is_satisfied_by(String::from("... wow")));

        // Actually, we should be able to catch the empty string always with char*:
        assert!("a*".is_satisfied_by(String::from("")));
        assert!("\\+*".is_satisfied_by(String::from("")));
        assert!("!*".is_satisfied_by(String::from("")));
        assert!("#*".is_satisfied_by(String::from("")));

        // Maybe we should try a few more::
        assert!("ab*a".is_satisfied_by(String::from("aa")));
        assert!("ab*a".is_satisfied_by(String::from("abba")));
        assert!("ab*a".is_satisfied_by(String::from("aba")));
        assert!("ab*a".is_satisfied_by(String::from("abbbbbbbbbbbbbbbbbbbbbbbbbbbbba")));

        assert!("ab*".is_satisfied_by(String::from("a")));
        assert!("ab*".is_satisfied_by(String::from("abb")));
        assert!("ab*".is_satisfied_by(String::from("ab")));
        assert!("ab*".is_satisfied_by(String::from("abbbbbbbbbbbbbbbbbbbbbbbbbbbbb")));

        assert!("b*a".is_satisfied_by(String::from("a")));
        assert!("b*a".is_satisfied_by(String::from("bba")));
        assert!("b*a".is_satisfied_by(String::from("ba")));
        assert!("b*a".is_satisfied_by(String::from("bbbbbbbbbbbbbbbbbbbbbbbbbbbbba")));

        assert!("b*a".is_not_satisfied_by(String::from("aa")));
        assert!("b*a".is_not_satisfied_by(String::from("ab")));
        assert!("b*a".is_not_satisfied_by(String::from("bab")));
        assert!("b*a".is_not_satisfied_by(String::from("bbbabbbbbbbbbbbbbbbbbbbbbbbbb")));

        // Only the empty string satisfies this...
        assert!("*".is_satisfied_by(String::from("")));
        assert!("*".is_not_satisfied_by(String::from("a")));
        assert!("*".is_not_satisfied_by(String::from("c")));
        assert!("*".is_not_satisfied_by(String::from("anything else, really")));

        // Just playing with escaped special chars now
        assert!("\\+*".is_satisfied_by(String::from("++++++++++++++++++++++++++")));
        assert!("\\+*".is_satisfied_by(String::from("+")));
        assert!("\\?*".is_satisfied_by(String::from("??????????????????????????")));
        assert!("\\?*".is_satisfied_by(String::from("?")));
        assert!("\\**".is_satisfied_by(String::from("**************************")));
        assert!("\\**".is_satisfied_by(String::from("*")));

        assert!("0-9*".is_satisfied_by(String::from("0-")));
        assert!("0-9*".is_satisfied_by(String::from("0-9")));
        assert!("0-9*".is_satisfied_by(String::from("0-99999999")));
        assert!("0-9*".is_not_satisfied_by(String::from("7")));
    }

    #[test]
    fn it_can_match_one_or_more() {
        assert!(".+".is_satisfied_by(String::from("Basically anything")));
        assert!(".+".is_satisfied_by(String::from("well, not anything")));
        assert!(".+".is_satisfied_by(String::from("anything except (!) for the empty string")));
        assert!(".+".is_not_satisfied_by(String::from("")));
        assert!(".+".is_satisfied_by(String::from("Even single letters count:")));
        assert!(".+".is_satisfied_by(String::from("t")));
        assert!(".+".is_satisfied_by(String::from("See?")));

        assert!("ab+a".is_not_satisfied_by(String::from("aa")));
        assert!("ab+a".is_satisfied_by(String::from("abba")));
        assert!("ab+a".is_satisfied_by(String::from("aba")));
        assert!("ab+a".is_satisfied_by(String::from("abbbbbbbbbbbbbbbbbbbbbbbbbbbbba")));

        assert!("ab+".is_not_satisfied_by(String::from("a")));
        assert!("ab+".is_satisfied_by(String::from("abb")));
        assert!("ab+".is_satisfied_by(String::from("ab")));
        assert!("ab+".is_satisfied_by(String::from("abbbbbbbbbbbbbbbbbbbbbbbbbbbbb")));

        assert!("b+a".is_not_satisfied_by(String::from("a")));
        assert!("b+a".is_satisfied_by(String::from("bba")));
        assert!("b+a".is_satisfied_by(String::from("ba")));
        assert!("b+a".is_satisfied_by(String::from("bbbbbbbbbbbbbbbbbbbbbbbbbbbbba")));

        assert!("b+a".is_not_satisfied_by(String::from("aa")));
        assert!("b+a".is_not_satisfied_by(String::from("ab")));
        assert!("b+a".is_not_satisfied_by(String::from("bab")));
        assert!("b+a".is_not_satisfied_by(String::from("bbbabbbbbbbbbbbbbbbbbbbbbbbbb")));

        assert!("b+ab++".is_satisfied_by(String::from("bab")));
        assert!("b+ab++".is_satisfied_by(String::from("bbbbbabbb")));
        assert!("b+ab++".is_not_satisfied_by(String::from("bbbbbaabbb")));

        // Only the empty string satisfies this...
        assert!("+".is_satisfied_by(String::from("")));
        assert!("+".is_not_satisfied_by(String::from("a")));
        assert!("+".is_not_satisfied_by(String::from("c")));
        assert!("+".is_not_satisfied_by(String::from("anything else, really")));

        // Just playing with escaped special chars now
        assert!("\\++".is_satisfied_by(String::from("++++++++++++++++++++++++++")));
        assert!("\\++".is_satisfied_by(String::from("+")));

        assert!("0-9+".is_not_satisfied_by(String::from("0-")));
        assert!("0-9+".is_satisfied_by(String::from("0-9")));
        assert!("0-9+".is_satisfied_by(String::from("0-99999999")));
        assert!("0-9+".is_not_satisfied_by(String::from("7")));

        // Let's mix some together
        assert!("o*-9+".is_satisfied_by(String::from("-9")));
        assert!("o*-9+".is_satisfied_by(String::from("-99999999")));
        assert!("o*-9+".is_satisfied_by(String::from("oooooooo-9")));
        assert!("o*-9+".is_satisfied_by(String::from("oooooooo-999999")));
        assert!("o*-9+".is_not_satisfied_by(String::from("o-")));
    }

    #[test]
    fn it_can_match_none_or_one() {
        assert!(".?".is_not_satisfied_by(String::from("words")));
        assert!(".?".is_not_satisfied_by(String::from("not letters")));
        assert!(".?".is_satisfied_by(String::from("")));
        assert!(".?".is_satisfied_by(String::from("a")));
        assert!(".?".is_satisfied_by(String::from("z")));
        assert!(".?".is_satisfied_by(String::from("!")));
        assert!(".?".is_satisfied_by(String::from("+")));

        assert!("ab?a".is_satisfied_by(String::from("aa")));
        assert!("ab?a".is_not_satisfied_by(String::from("abba")));
        assert!("ab?a".is_satisfied_by(String::from("aba")));
        assert!("ab?a".is_not_satisfied_by(String::from("abbbbbbbbbbbbbbbbbbbbbbbbbbbbba")));

        assert!("ab?".is_satisfied_by(String::from("a")));
        assert!("ab?".is_not_satisfied_by(String::from("abb")));
        assert!("ab?".is_satisfied_by(String::from("ab")));
        assert!("ab?".is_not_satisfied_by(String::from("abbbbbbbbbbbbbbbbbbbbbbbbbbbbb")));

        assert!("b?a".is_satisfied_by(String::from("a")));
        assert!("b?a".is_not_satisfied_by(String::from("bba")));
        assert!("b?a".is_satisfied_by(String::from("ba")));
        assert!("b?a".is_not_satisfied_by(String::from("bbbbbbbbbbbbbbbbbbbbbbbbbbbbba")));

        assert!("b?a".is_not_satisfied_by(String::from("aa")));
        assert!("b?a".is_not_satisfied_by(String::from("ab")));
        assert!("b?a".is_not_satisfied_by(String::from("bab")));
        assert!("b?a".is_not_satisfied_by(String::from("bbbabbbbbbbbbbbbbbbbbbbbbbbbb")));

        assert!("b?ab??".is_satisfied_by(String::from("bab")));
        assert!("b?ab??".is_satisfied_by(String::from("ab")));
        assert!("b?ab??".is_satisfied_by(String::from("ba")));
        assert!("b?ab??".is_satisfied_by(String::from("a")));
        assert!("b?ab??".is_not_satisfied_by(String::from("bbbbbabbb")));
        assert!("b?ab??".is_not_satisfied_by(String::from("bbbbbaabbb")));

        // Only the empty string satisfies this...
        assert!("?".is_satisfied_by(String::from("")));
        assert!("?".is_not_satisfied_by(String::from("a")));
        assert!("?".is_not_satisfied_by(String::from("c")));
        assert!("?".is_not_satisfied_by(String::from("anything else, really")));

        // Just playing with escaped special chars now
        assert!("\\??".is_not_satisfied_by(String::from("??????????????????????????")));
        assert!("\\??".is_satisfied_by(String::from("?")));
        assert!("\\??".is_satisfied_by(String::from("")));

        assert!("0-9?".is_satisfied_by(String::from("0-")));
        assert!("0-9?".is_satisfied_by(String::from("0-9")));
        assert!("0-9?".is_not_satisfied_by(String::from("0-99999999")));
        assert!("0-9?".is_not_satisfied_by(String::from("7")));
        assert!("0-9?".is_not_satisfied_by(String::from("")));

        // Let's mix some together
        assert!("o*-9?".is_satisfied_by(String::from("-9")));
        assert!("o+-9?".is_not_satisfied_by(String::from("o-99999999")));
        assert!("o*-9?".is_satisfied_by(String::from("oooooooo-9")));
        assert!("o*-9?".is_not_satisfied_by(String::from("oooooooo-999999")));
        assert!("o*-9?".is_satisfied_by(String::from("o-")));
    }

    #[test]
    fn matches_anything_in_brackets() {
        // Basics?
        assert!("[]".is_satisfied_by(String::from("")));
        assert!("[]".is_not_satisfied_by(String::from("a")));
        assert!("[a]".is_not_satisfied_by(String::from("")));
        assert!("[a]".is_satisfied_by(String::from("a")));
        assert!("[a]".is_not_satisfied_by(String::from("aa")));
        assert!("a[]".is_not_satisfied_by(String::from("")));
        assert!("a[]".is_satisfied_by(String::from("a")));
        assert!("a[]".is_not_satisfied_by(String::from("aa")));
        assert!("[]a".is_not_satisfied_by(String::from("")));
        assert!("[]a".is_satisfied_by(String::from("a")));
        assert!("[]a".is_not_satisfied_by(String::from("aa")));

        assert!("[a]*".is_satisfied_by(String::from("aa")));
        assert!("[a]*".is_satisfied_by(String::from("")));
        assert!("[a]*".is_satisfied_by(String::from("aaaaaaaaa")));

        assert!("[ab]*".is_satisfied_by(String::from("abaabbbbabaaaab")));
        assert!("[ab]*".is_satisfied_by(String::from("")));
        assert!("[ab]*".is_satisfied_by(String::from("aaaaaaaaaa")));
        assert!("[ab]*".is_satisfied_by(String::from("bbbbbbbbbb")));
        assert!("[ab]*".is_not_satisfied_by(String::from("bbbcbbbbbb")));

        // Check ranges
        assert!("[0-9]*".is_satisfied_by(String::from("8675309")));
        assert!("[ a-z]*".is_satisfied_by(String::from("now i can write things")));
        assert!("[ a-zA-Z]*".is_satisfied_by(String::from("now I can write things")));
        assert!("[ :a-z]+".is_satisfied_by(String::from("alphabet: abcdefghijklmnopqrstuvxyz")));
        assert!("[a-z]*".is_satisfied_by(String::from("")));
        assert!("[a-z+]*".is_satisfied_by(String::from(""))); // Ignore special characters in brackets

        assert!("[ a-z]*".is_not_satisfied_by(String::from("now I can write things")));
        assert!("[a-z]*".is_not_satisfied_by(String::from("8675309")));
        assert!("[a-z]+".is_not_satisfied_by(String::from("")));

        // Malformed regexes never match
        assert!("[[]]".is_not_satisfied_by(String::from("")));
        assert!("[[]a]".is_not_satisfied_by(String::from("abcd")));
        assert!("[[bc]]".is_not_satisfied_by(String::from("Anything??")));
        assert!("[+-]zzzz]".is_not_satisfied_by(String::from("Everything!~!~!")));

        assert!("[aa]".is_satisfied_by(String::from("a")));
        assert!("[aa]".is_not_satisfied_by(String::from("")));

        // We ignore special characters inside...
        assert!("[a?]".is_not_satisfied_by(String::from("")));
        assert!("[a?]".is_satisfied_by(String::from("a")));
        assert!("[a?]".is_satisfied_by(String::from("?")));
    }

    #[test]
    fn inversely_matches_anything_in_brackets() {
        // Basics?
        assert!("[^]".is_satisfied_by(String::from("")));
        assert!("[^]".is_not_satisfied_by(String::from("a")));
        assert!("[^a]".is_not_satisfied_by(String::from("")));
        assert!("[^a]".is_not_satisfied_by(String::from("a")));
        assert!("[^a]".is_not_satisfied_by(String::from("aa")));
        assert!("a[^]".is_not_satisfied_by(String::from("")));
        assert!("a[^]".is_satisfied_by(String::from("a")));
        assert!("a[^]".is_not_satisfied_by(String::from("aa")));
        assert!("[^]a".is_not_satisfied_by(String::from("")));
        assert!("[^]a".is_satisfied_by(String::from("a")));
        assert!("[^]a".is_not_satisfied_by(String::from("aa")));

        assert!("[^a]*".is_not_satisfied_by(String::from("aa")));
        assert!("[^a]*".is_satisfied_by(String::from("")));
        assert!("[^a]*".is_not_satisfied_by(String::from("aaaaaaaaa")));
        assert!("[^a]*".is_satisfied_by(String::from("bbbbbbbbb")));

        assert!("[^ab]*".is_not_satisfied_by(String::from("abaabbbbabaaaab")));
        assert!("[^ab]*".is_satisfied_by(String::from("")));
        assert!("[^ab]*".is_not_satisfied_by(String::from("aaaaaaaaaa")));
        assert!("[^ab]*".is_not_satisfied_by(String::from("bbbbbbbbbb")));
        assert!("[^ab]*".is_not_satisfied_by(String::from("bbbcbbbbbb")));
        assert!("[^ab]*".is_satisfied_by(String::from("cdcdcdcdcdcd")));

        // Check ranges
        assert!("[^0-9]*".is_satisfied_by(String::from("now I can write things")));
        assert!("[^ a-z]*".is_not_satisfied_by(String::from("now i can write things")));
        assert!("[^ a-zA-Z]*".is_satisfied_by(String::from("8675309")));
        assert!("[^ :a-z]+".is_satisfied_by(String::from("ALPHABET")));
        assert!("[^a-z]*".is_satisfied_by(String::from("")));
        assert!("[^a-z+]*".is_satisfied_by(String::from(""))); // Ignore special characters in brackets

        assert!("[^a-z]*".is_satisfied_by(String::from("NOW I CAN WRITE THINGS")));
        assert!("[^a-z]*".is_satisfied_by(String::from("8675309")));
        assert!("[^a-z]+".is_not_satisfied_by(String::from("")));

        // Malformed regexes never match
        assert!("[^[^]]".is_not_satisfied_by(String::from("")));
        assert!("[^[^]a]".is_not_satisfied_by(String::from("abcd")));
        assert!("[^[^bc]]".is_not_satisfied_by(String::from("Anything??")));
        assert!("[^+-]zzzz]".is_not_satisfied_by(String::from("Everything!~!~!")));

        assert!("[^aa]".is_not_satisfied_by(String::from("a")));
        assert!("[^aa]".is_not_satisfied_by(String::from("")));
        assert!("[^aa]".is_satisfied_by(String::from("b")));
        assert!("[^aa]".is_satisfied_by(String::from("~")));

        // We ignore special characters inside...
        assert!("[^a?]".is_not_satisfied_by(String::from("")));
        assert!("[^a?]".is_satisfied_by(String::from("c")));
        assert!("[^a?]".is_not_satisfied_by(String::from("a")));
        assert!("[^a?]".is_not_satisfied_by(String::from("?")));
    }

    #[test]
    fn mildly_complex_queries() {
        assert!("(1[-.]?)?".is_satisfied_by("".to_string()));
        assert!("(1[-.]?)?".is_satisfied_by("1".to_string()));
        assert!("(1[-.]?)?".is_satisfied_by("1-".to_string()));
        assert!("(1[-.]?)?".is_satisfied_by("1.".to_string()));
        assert!("(1[-.]?)?".is_not_satisfied_by("11".to_string()));
    }
}
<|endoftext|>


<commit_before>//! The module describes all possible replies from MPD server.
//!
//! Also it contains most generic parser, which can handle
//! all possible server replies.

use error::{ParseError, ServerError};
use std::str::FromStr;

/// All possible MPD server replies
#[derive(Debug, Clone, PartialEq)]
pub enum Reply {
    /// `OK` and `list_OK` replies
    Ok,
    /// `ACK` reply (server error)
    Ack(ServerError),
    /// a data pair reply (in `field: value` format)
    Pair(String, String),
}

impl FromStr for Reply {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Reply, ParseError> {
        if s == "OK" || s == "list_OK" {
            Ok(Reply::Ok)
        } else {
            if let Ok(ack) = s.parse::<ServerError>() {
                Ok(Reply::Ack(ack))
            } else {
                let mut splits = s.splitn(2, ':');
                match (splits.next(), splits.next()) {
                    (Some(a), Some(b)) => Ok(Reply::Pair(a.to_owned(), b.trim().to_owned())),
                    _ => Err(ParseError::BadPair),
                }
            }
        }
    }
}
<commit_msg>Use `else if` instead of a `if` nested in an `else`.<commit_after>//! The module describes all possible replies from MPD server.
//!
//! Also it contains most generic parser, which can handle
//! all possible server replies.

use error::{ParseError, ServerError};
use std::str::FromStr;

/// All possible MPD server replies
#[derive(Debug, Clone, PartialEq)]
pub enum Reply {
    /// `OK` and `list_OK` replies
    Ok,
    /// `ACK` reply (server error)
    Ack(ServerError),
    /// a data pair reply (in `field: value` format)
    Pair(String, String),
}

impl FromStr for Reply {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Reply, ParseError> {
        if s == "OK" || s == "list_OK" {
            Ok(Reply::Ok)
        } else if let Ok(ack) = s.parse::<ServerError>() {
            Ok(Reply::Ack(ack))
        } else {
            let mut splits = s.splitn(2, ':');
            match (splits.next(), splits.next()) {
                (Some(a), Some(b)) => Ok(Reply::Pair(a.to_owned(), b.trim().to_owned())),
                _ => Err(ParseError::BadPair),
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::Graph;
use crate::Operation;
use crate::OperationDescription;
use crate::Result;
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::collections::HashSet;
use std::ops::Deref;
use std::ops::DerefMut;
use std::rc::Rc;

/// Joins left and right using the separator.  If either left or right is the
/// empty string, the separator is left out.
fn join(sep: &str, left: &str, right: &str) -> String {
    match (left, right) {
        ("", _) => right.to_string(),
        (_, "") => left.to_string(),
        _ => format!("{}{}{}", left, sep, right),
    }
}

// TODO: Include other with_* functions
/// A `Scope` object represents a set of related TensorFlow ops that have the
/// same properties such as a common name prefix.
///
/// A Scope object is a container for TensorFlow Op properties. Op constructors
/// get a Scope object as a mandatory first argument and the constructed op
/// acquires the properties in the object.
///
/// A simple example:
///
/// ```
/// # use tensorflow::Scope;
/// # use tensorflow::Tensor;
/// # use tensorflow::ops;
/// let mut root = Scope::new_root_scope();
/// let c1 = ops::constant(Tensor::new(&[1, 2]).with_values(&[1, 1])?, &mut root)?;
/// let c2 = ops::constant(Tensor::new(&[2, 1]).with_values(&[41, 1])?, &mut root)?;
/// let m = ops::mat_mul(c1, c2, &mut root)?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// # Scope hierarchy
///
/// The Scope class provides various `with_*` functions that create a new scope.
/// The new scope typically has one property changed while other properties are
/// inherited from the parent scope.
/// `new_sub_scope(name)` method appends `name` to the prefix of names for ops
/// created within the scope, and `with_op_name()` changes the suffix which
/// otherwise defaults to the type of the op.
///
/// Name examples:
///
/// ```
/// # use tensorflow::DataType;
/// # use tensorflow::Scope;
/// # use tensorflow::Shape;
/// # use tensorflow::Tensor;
/// # use tensorflow::Variable;
/// # use tensorflow::ops;
/// let mut root = Scope::new_root_scope();
/// let mut linear = root.new_sub_scope("linear");
/// let w = Variable::builder()
///   .const_initial_value(
///     Tensor::new(&[2, 2])
///       .with_values(&[0.0f32, 0.0, 0.0, 0.0])?)
///   .build(&mut linear.with_op_name("W"))?;
/// assert_eq!(w.name(), "linear/W");
/// let b = Variable::builder()
///   .const_initial_value(
///     Tensor::new(&[2])
///       .with_values(&[0.0f32, 0.0])?)
///   .build(&mut linear.with_op_name("b"))?;
/// assert_eq!(b.name(), "linear/b");
/// let x = ops::constant(
///   Tensor::new(&[2, 2])
///     .with_values(&[1.0f32, 2.0, 3.0, 4.0])?,
///    &mut linear)?;
/// assert_eq!(x.name()?, "linear/Const");
/// let m = ops::mat_mul(x, w.output().clone(), &mut linear)?;
/// assert_eq!(m.name()?, "linear/MatMul");
/// let r = ops::bias_add(m, b.output().clone(), &mut linear)?;
/// assert_eq!(r.name()?, "linear/BiasAdd");
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// # Scope lifetime
///
/// A new scope is created by calling `Scope::new_root_scope`. This creates some
/// resources that are shared by all the child scopes that inherit from this
/// scope, directly or transitively. For instance, a new scope creates a new
/// Graph object to which operations are added when the new scope or its
/// children are used by an Op constructor.
#[derive(Debug)]
pub struct Scope {
    graph: Rc<RefCell<Graph>>,
    name: String,
    children_names: Rc<RefCell<HashSet<String>>>,
    op_name: String,
    op_names: Rc<RefCell<HashMap<String, i32>>>,
    device: String,
    control_deps: Vec<Operation>,
}

impl Scope {
    /// Return a new scope.
    /// This creates a new graph and all operations constructed in this graph
    /// should use the returned object as the "root" scope.
    pub fn new_root_scope() -> Scope {
        Scope {
            graph: Rc::new(RefCell::new(Graph::new())),
            name: "".to_string(),
            children_names: Rc::new(RefCell::new(HashSet::new())),
            op_name: "".to_string(),
            op_names: Rc::new(RefCell::new(HashMap::new())),
            device: "".to_string(),
            control_deps: Vec::new(),
        }
    }

    /// Adds a suffix if necessary to create a unique subscope name.
    fn uniquify(&self, name: &str) -> String {
        let refcell: &RefCell<_> = self.children_names.borrow();
        let mut set = refcell.borrow_mut();
        if set.insert(name.to_string()) {
            return name.to_string();
        }
        let mut i = 1;
        loop {
            let unique_name = format!("{}_{}", &name, i);
            if set.insert(unique_name.clone()) {
                return unique_name;
            }
            i += 1;
        }
    }

    /// Return a new scope. Ops created with this scope will have
    /// `name/child_scope_name` as the prefix. The actual name will be unique
    /// in the current scope. All other properties are inherited from the current
    /// scope. If `child_scope_name` is empty, the `/` is elided.
    pub fn new_sub_scope(&self, name: &str) -> Scope {
        let self_name: &str = &self.name;
        let (new_name, copy_names) = match (self_name, name) {
            (_, "") => (self.name.clone(), true),
            ("", _) => (self.uniquify(name), false),
            _ => (format!("{}/{}", self.name, self.uniquify(name)), false),
        };
        Scope {
            graph: self.graph.clone(),
            name: new_name,
            children_names: Rc::new(RefCell::new(HashSet::new())),
            op_name: self.op_name.clone(),
            op_names: if copy_names {
                self.op_names.clone()
            } else {
                Rc::new(RefCell::new(HashMap::new()))
            },
            device: self.device.clone(),
            control_deps: self.control_deps.clone(),
        }
    }

    /// Return a new scope. All ops created within the returned scope will have
    /// names of the form `scope_name/name[_suffix]`
    pub fn with_op_name(&self, name: &str) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: name.to_string(),
            op_names: self.op_names.clone(),
            device: self.device.clone(),
            control_deps: self.control_deps.clone(),
        }
    }

    /// Return a unique name, using default_name if an op name has not been
    /// specified.
    pub fn get_unique_name_for_op(&self, default_name: &str) -> String {
        let name = if self.op_name == "" {
            default_name
        } else {
            &self.op_name
        };
        let map: &RefCell<_> = self.op_names.borrow();
        let mut map = map.borrow_mut();
        let mut name_string = name.to_string();
        loop {
            match map.entry(name_string.clone()) {
                Entry::Vacant(e) => {
                    e.insert(0);
                    return join("/", &self.name, &name_string);
                }
                Entry::Occupied(mut e) => {
                    *e.get_mut() += 1;
                    name_string = format!("{}_{}", name, *e.get());
                }
            }
        }
    }

    /// Return a new scope. All ops created within the returned scope will have
    /// their device field set to `device`.
    pub fn with_device(&self, device: &str) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: self.op_name.clone(),
            op_names: self.op_names.clone(),
            device: device.to_string(),
            control_deps: self.control_deps.clone(),
        }
    }

    /// Return a new scope. All ops created within the returned scope will have
    /// as control dependencies the union of operations in `control_deps`
    /// and the control dependencies of the current scope.
    pub fn with_control_dependencies(&self, control_deps: &[Operation]) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: self.op_name.clone(),
            op_names: self.op_names.clone(),
            device: self.device.clone(),
            control_deps: self
                .control_deps
                .iter()
                .chain(control_deps.iter())
                .cloned()
                .collect(),
        }
    }

    /// Return a new scope. All ops created within the returned scope will have
    /// no control dependencies on other operations.
    pub fn with_no_control_dependencies(&self) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: self.op_name.clone(),
            op_names: self.op_names.clone(),
            device: self.device.clone(),
            control_deps: vec![],
        }
    }

    pub(crate) fn new_operation<F: FnOnce(&mut OperationDescription) -> Result<()>>(
        &mut self,
        op_type: &str,
        f: F,
    ) -> Result<Operation> {
        let name = self.get_unique_name_for_op(op_type);
        let r: &RefCell<Graph> = self.graph.borrow();
        let mut graph = r.borrow_mut();
        let mut nd = graph.new_operation(op_type, &name)?;
        nd.set_device(&self.device)?;
        for control_dep in &self.control_deps {
            nd.add_control_input(control_dep);
        }
        f(&mut nd)?;
        Ok(nd.finish()?)
    }

    /// Returns the graph being built by the scope.
    pub fn graph(&self) -> impl Deref<Target = Graph> + '_ {
        let r: &RefCell<Graph> = self.graph.borrow();
        r.borrow()
    }

    /// Returns the graph being built by the scope.
    pub fn graph_mut(&mut self) -> impl DerefMut<Target = Graph> + '_ {
        let r: &RefCell<Graph> = self.graph.borrow();
        r.borrow_mut()
    }
}

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

    #[test]
    fn smoke() {
        let mut scope = Scope::new_root_scope();
        let mut graph = scope.graph_mut();
        let mut c = graph.new_operation("Const", "Const").unwrap();
        c.set_attr_tensor("value", 3.0f32.into()).unwrap();
        c.set_attr_type("dtype", DataType::Float).unwrap();
        c.finish().unwrap();
    }

    #[test]
    fn uniquification() {
        let scope = Scope::new_root_scope();
        assert_eq!(&scope.new_sub_scope("foo").name, "foo");
        assert_eq!(&scope.new_sub_scope("foo").name, "foo_1");
        let foo_1 = scope.new_sub_scope("foo");
        assert_eq!(&foo_1.name, "foo_2");
        assert_eq!(&foo_1.new_sub_scope("bar").name, "foo_2/bar");
        assert_eq!(&foo_1.new_sub_scope("bar").name, "foo_2/bar_1");
        assert_eq!(&foo_1.new_sub_scope("bar").name, "foo_2/bar_2");
    }

    #[test]
    fn get_unique_name_for_op() {
        let scope = Scope::new_root_scope();
        assert_eq!(scope.get_unique_name_for_op("Add"), "Add");
        assert_eq!(scope.get_unique_name_for_op("Add"), "Add_1");
        let foo = scope.new_sub_scope("foo");
        assert_eq!(foo.get_unique_name_for_op("Add"), "foo/Add");
        assert_eq!(foo.get_unique_name_for_op("Add"), "foo/Add_1");
        let bar = foo.with_op_name("bar");
        assert_eq!(bar.get_unique_name_for_op("Add"), "foo/bar");
        assert_eq!(bar.get_unique_name_for_op("Add"), "foo/bar_1");
    }

    #[test]
    fn device() {
        assert_eq!(
            Scope::new_root_scope()
                .with_device("foo")
                .new_operation("NoOp", |_| Ok(()))
                .unwrap()
                .device()
                .unwrap(),
            "foo"
        );
    }

    #[test]
    fn control_dependencies() {
        let mut scope = Scope::new_root_scope();
        let dep = scope.new_operation("NoOp", |_| Ok(())).unwrap();
        let dep_clone = dep.clone();
        let mut scope2 = scope.with_control_dependencies(&[dep]);
        assert_eq!(
            scope2
                .new_operation("NoOp", |_| Ok(()))
                .unwrap()
                .control_inputs()
                .iter()
                .map(|n| n.name().unwrap())
                .collect::<Vec<_>>(),
            vec![dep_clone.name().unwrap()]
        );
        let mut scope3 = scope2.with_no_control_dependencies();
        assert_eq!(
            scope3
                .new_operation("NoOp", |_| Ok(()))
                .unwrap()
                .control_inputs()
                .len(),
            0
        );
    }
}
<commit_msg>Add Scope::with_kernel_label<commit_after>use crate::Graph;
use crate::Operation;
use crate::OperationDescription;
use crate::Result;
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::collections::HashSet;
use std::ops::Deref;
use std::ops::DerefMut;
use std::rc::Rc;

/// Joins left and right using the separator.  If either left or right is the
/// empty string, the separator is left out.
fn join(sep: &str, left: &str, right: &str) -> String {
    match (left, right) {
        ("", _) => right.to_string(),
        (_, "") => left.to_string(),
        _ => format!("{}{}{}", left, sep, right),
    }
}

// TODO: Include other with_* functions
/// A `Scope` object represents a set of related TensorFlow ops that have the
/// same properties such as a common name prefix.
///
/// A Scope object is a container for TensorFlow Op properties. Op constructors
/// get a Scope object as a mandatory first argument and the constructed op
/// acquires the properties in the object.
///
/// A simple example:
///
/// ```
/// # use tensorflow::Scope;
/// # use tensorflow::Tensor;
/// # use tensorflow::ops;
/// let mut root = Scope::new_root_scope();
/// let c1 = ops::constant(Tensor::new(&[1, 2]).with_values(&[1, 1])?, &mut root)?;
/// let c2 = ops::constant(Tensor::new(&[2, 1]).with_values(&[41, 1])?, &mut root)?;
/// let m = ops::mat_mul(c1, c2, &mut root)?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// # Scope hierarchy
///
/// The Scope class provides various `with_*` functions that create a new scope.
/// The new scope typically has one property changed while other properties are
/// inherited from the parent scope.
/// `new_sub_scope(name)` method appends `name` to the prefix of names for ops
/// created within the scope, and `with_op_name()` changes the suffix which
/// otherwise defaults to the type of the op.
///
/// Name examples:
///
/// ```
/// # use tensorflow::DataType;
/// # use tensorflow::Scope;
/// # use tensorflow::Shape;
/// # use tensorflow::Tensor;
/// # use tensorflow::Variable;
/// # use tensorflow::ops;
/// let mut root = Scope::new_root_scope();
/// let mut linear = root.new_sub_scope("linear");
/// let w = Variable::builder()
///   .const_initial_value(
///     Tensor::new(&[2, 2])
///       .with_values(&[0.0f32, 0.0, 0.0, 0.0])?)
///   .build(&mut linear.with_op_name("W"))?;
/// assert_eq!(w.name(), "linear/W");
/// let b = Variable::builder()
///   .const_initial_value(
///     Tensor::new(&[2])
///       .with_values(&[0.0f32, 0.0])?)
///   .build(&mut linear.with_op_name("b"))?;
/// assert_eq!(b.name(), "linear/b");
/// let x = ops::constant(
///   Tensor::new(&[2, 2])
///     .with_values(&[1.0f32, 2.0, 3.0, 4.0])?,
///    &mut linear)?;
/// assert_eq!(x.name()?, "linear/Const");
/// let m = ops::mat_mul(x, w.output().clone(), &mut linear)?;
/// assert_eq!(m.name()?, "linear/MatMul");
/// let r = ops::bias_add(m, b.output().clone(), &mut linear)?;
/// assert_eq!(r.name()?, "linear/BiasAdd");
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// # Scope lifetime
///
/// A new scope is created by calling `Scope::new_root_scope`. This creates some
/// resources that are shared by all the child scopes that inherit from this
/// scope, directly or transitively. For instance, a new scope creates a new
/// Graph object to which operations are added when the new scope or its
/// children are used by an Op constructor.
#[derive(Debug)]
pub struct Scope {
    graph: Rc<RefCell<Graph>>,
    name: String,
    children_names: Rc<RefCell<HashSet<String>>>,
    op_name: String,
    op_names: Rc<RefCell<HashMap<String, i32>>>,
    device: String,
    control_deps: Vec<Operation>,
    kernel_label: String,
}

impl Scope {
    /// Return a new scope.
    /// This creates a new graph and all operations constructed in this graph
    /// should use the returned object as the "root" scope.
    pub fn new_root_scope() -> Scope {
        Scope {
            graph: Rc::new(RefCell::new(Graph::new())),
            name: "".to_string(),
            children_names: Rc::new(RefCell::new(HashSet::new())),
            op_name: "".to_string(),
            op_names: Rc::new(RefCell::new(HashMap::new())),
            device: "".to_string(),
            control_deps: Vec::new(),
            kernel_label: "".to_string(),
        }
    }

    /// Adds a suffix if necessary to create a unique subscope name.
    fn uniquify(&self, name: &str) -> String {
        let refcell: &RefCell<_> = self.children_names.borrow();
        let mut set = refcell.borrow_mut();
        if set.insert(name.to_string()) {
            return name.to_string();
        }
        let mut i = 1;
        loop {
            let unique_name = format!("{}_{}", &name, i);
            if set.insert(unique_name.clone()) {
                return unique_name;
            }
            i += 1;
        }
    }

    /// Return a new scope. Ops created with this scope will have
    /// `name/child_scope_name` as the prefix. The actual name will be unique
    /// in the current scope. All other properties are inherited from the current
    /// scope. If `child_scope_name` is empty, the `/` is elided.
    pub fn new_sub_scope(&self, name: &str) -> Scope {
        let self_name: &str = &self.name;
        let (new_name, copy_names) = match (self_name, name) {
            (_, "") => (self.name.clone(), true),
            ("", _) => (self.uniquify(name), false),
            _ => (format!("{}/{}", self.name, self.uniquify(name)), false),
        };
        Scope {
            graph: self.graph.clone(),
            name: new_name,
            children_names: Rc::new(RefCell::new(HashSet::new())),
            op_name: self.op_name.clone(),
            op_names: if copy_names {
                self.op_names.clone()
            } else {
                Rc::new(RefCell::new(HashMap::new()))
            },
            device: self.device.clone(),
            control_deps: self.control_deps.clone(),
            kernel_label: "".to_string(),
        }
    }

    /// Return a new scope. All ops created within the returned scope will have
    /// names of the form `scope_name/name[_suffix]`
    pub fn with_op_name(&self, name: &str) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: name.to_string(),
            op_names: self.op_names.clone(),
            device: self.device.clone(),
            control_deps: self.control_deps.clone(),
            kernel_label: "".to_string(),
        }
    }

    /// Return a unique name, using default_name if an op name has not been
    /// specified.
    pub fn get_unique_name_for_op(&self, default_name: &str) -> String {
        let name = if self.op_name == "" {
            default_name
        } else {
            &self.op_name
        };
        let map: &RefCell<_> = self.op_names.borrow();
        let mut map = map.borrow_mut();
        let mut name_string = name.to_string();
        loop {
            match map.entry(name_string.clone()) {
                Entry::Vacant(e) => {
                    e.insert(0);
                    return join("/", &self.name, &name_string);
                }
                Entry::Occupied(mut e) => {
                    *e.get_mut() += 1;
                    name_string = format!("{}_{}", name, *e.get());
                }
            }
        }
    }

    /// Return a new scope. All ops created within the returned scope will have
    /// their device field set to `device`.
    pub fn with_device(&self, device: &str) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: self.op_name.clone(),
            op_names: self.op_names.clone(),
            device: device.to_string(),
            control_deps: self.control_deps.clone(),
            kernel_label: "".to_string(),
        }
    }

    /// Return a new scope. All ops created within the returned scope will have
    /// as control dependencies the union of operations in `control_deps`
    /// and the control dependencies of the current scope.
    pub fn with_control_dependencies(&self, control_deps: &[Operation]) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: self.op_name.clone(),
            op_names: self.op_names.clone(),
            device: self.device.clone(),
            control_deps: self
                .control_deps
                .iter()
                .chain(control_deps.iter())
                .cloned()
                .collect(),
            kernel_label: "".to_string(),
        }
    }

    /// Return a new scope. All ops created within the returned scope will have
    /// no control dependencies on other operations.
    pub fn with_no_control_dependencies(&self) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: self.op_name.clone(),
            op_names: self.op_names.clone(),
            device: self.device.clone(),
            control_deps: vec![],
            kernel_label: "".to_string(),
        }
    }

    /// Return a new scope. All ops created with the new scope will have
    /// kernel_label as the value for their '_kernel' attribute;
    pub fn with_kernel_label(&self, kernel_label: &str) -> Scope {
        Scope {
            graph: self.graph.clone(),
            name: self.name.clone(),
            children_names: self.children_names.clone(),
            op_name: self.op_name.clone(),
            op_names: self.op_names.clone(),
            device: self.device.clone(),
            control_deps: self.control_deps.clone(),
            kernel_label: kernel_label.to_string(),
        }
    }

    pub(crate) fn new_operation<F: FnOnce(&mut OperationDescription) -> Result<()>>(
        &mut self,
        op_type: &str,
        f: F,
    ) -> Result<Operation> {
        let name = self.get_unique_name_for_op(op_type);
        let r: &RefCell<Graph> = self.graph.borrow();
        let mut graph = r.borrow_mut();
        let mut nd = graph.new_operation(op_type, &name)?;
        nd.set_device(&self.device)?;
        for control_dep in &self.control_deps {
            nd.add_control_input(control_dep);
        }
        if !self.kernel_label.is_empty() {
            nd.set_attr_string("_kernel", &self.kernel_label)?;
        }
        f(&mut nd)?;
        Ok(nd.finish()?)
    }

    /// Returns the graph being built by the scope.
    pub fn graph(&self) -> impl Deref<Target = Graph> + '_ {
        let r: &RefCell<Graph> = self.graph.borrow();
        r.borrow()
    }

    /// Returns the graph being built by the scope.
    pub fn graph_mut(&mut self) -> impl DerefMut<Target = Graph> + '_ {
        let r: &RefCell<Graph> = self.graph.borrow();
        r.borrow_mut()
    }
}

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

    #[test]
    fn smoke() {
        let mut scope = Scope::new_root_scope();
        let mut graph = scope.graph_mut();
        let mut c = graph.new_operation("Const", "Const").unwrap();
        c.set_attr_tensor("value", 3.0f32.into()).unwrap();
        c.set_attr_type("dtype", DataType::Float).unwrap();
        c.finish().unwrap();
    }

    #[test]
    fn uniquification() {
        let scope = Scope::new_root_scope();
        assert_eq!(&scope.new_sub_scope("foo").name, "foo");
        assert_eq!(&scope.new_sub_scope("foo").name, "foo_1");
        let foo_1 = scope.new_sub_scope("foo");
        assert_eq!(&foo_1.name, "foo_2");
        assert_eq!(&foo_1.new_sub_scope("bar").name, "foo_2/bar");
        assert_eq!(&foo_1.new_sub_scope("bar").name, "foo_2/bar_1");
        assert_eq!(&foo_1.new_sub_scope("bar").name, "foo_2/bar_2");
    }

    #[test]
    fn get_unique_name_for_op() {
        let scope = Scope::new_root_scope();
        assert_eq!(scope.get_unique_name_for_op("Add"), "Add");
        assert_eq!(scope.get_unique_name_for_op("Add"), "Add_1");
        let foo = scope.new_sub_scope("foo");
        assert_eq!(foo.get_unique_name_for_op("Add"), "foo/Add");
        assert_eq!(foo.get_unique_name_for_op("Add"), "foo/Add_1");
        let bar = foo.with_op_name("bar");
        assert_eq!(bar.get_unique_name_for_op("Add"), "foo/bar");
        assert_eq!(bar.get_unique_name_for_op("Add"), "foo/bar_1");
    }

    #[test]
    fn device() {
        assert_eq!(
            Scope::new_root_scope()
                .with_device("foo")
                .new_operation("NoOp", |_| Ok(()))
                .unwrap()
                .device()
                .unwrap(),
            "foo"
        );
    }

    #[test]
    fn kernel_label() {
        assert_eq!(
            Scope::new_root_scope()
                .with_kernel_label("foo")
                .new_operation("NoOp", |_| Ok(()))
                .unwrap()
                .get_attr_string("_kernel")
                .unwrap(),
            "foo"
        );
    }

    #[test]
    fn control_dependencies() {
        let mut scope = Scope::new_root_scope();
        let dep = scope.new_operation("NoOp", |_| Ok(())).unwrap();
        let dep_clone = dep.clone();
        let mut scope2 = scope.with_control_dependencies(&[dep]);
        assert_eq!(
            scope2
                .new_operation("NoOp", |_| Ok(()))
                .unwrap()
                .control_inputs()
                .iter()
                .map(|n| n.name().unwrap())
                .collect::<Vec<_>>(),
            vec![dep_clone.name().unwrap()]
        );
        let mut scope3 = scope2.with_no_control_dependencies();
        assert_eq!(
            scope3
                .new_operation("NoOp", |_| Ok(()))
                .unwrap()
                .control_inputs()
                .len(),
            0
        );
    }
}
<|endoftext|>