<commit_before>use cmd::*;
use util;

#[deriving(Show, Clone)]
// Helper struct to efficently adress the different parts
// of the message.
struct ASlice {
    start: uint,
    end: uint
}

impl ASlice {
    #[inline]
    fn slice_vec<'a, T>(&self, vec: &'a Vec<T>) -> &'a[T] {
        vec.slice(self.start, self.end)
    }
}

/// IRC message
// TODO: do not use vecs for that, better [u8, ..510] and slices to that
// or just safe offsets in the message parts fields…
#[deriving(Show, Clone)]
pub struct RawMessage {
    raw_message: Vec<u8>,
    prefix: Option<ASlice>,
    command: ASlice,
    params: Vec<ASlice>
}

/// Searches a slice for the first occurence of needle
fn position<T: PartialEq>(this: &[T], needle: &[T]) -> Option<uint> {
    for i in range(0, this.len()) {
        if this.slice_from(i).starts_with(needle) {
            return Some(i)
        }
    }
    None
}

impl RawMessage {
    /// Creates a new message
    pub fn new(command: Command,
                params: &[&str],
                prefix: Option<&str>) -> RawMessage {
        let mut raw_message = Vec::with_capacity(20);
        let msg_prefix = prefix.map(|p| {
            raw_message.push(b':');
            raw_message.push_all(p.as_bytes());
            raw_message.push(b' ');
            ASlice { start: 1, end: p.as_bytes().len() + 1 }
        });
        let cmd = command.to_bytes();
        let cmd_bytes = cmd.as_slice();
        let msg_command = ASlice{ start: raw_message.len(),
                                    end: raw_message.len() + cmd_bytes.len() };
        raw_message.push_all(cmd_bytes);
        let mut start = msg_command.end;
        let num_params = params.len();
        let msg_params = params.iter().enumerate().map( |(i, &param)| {
            let bytes = param.as_bytes();
            raw_message.push(b' ');
            let offset = if i + 1 == num_params {
                raw_message.push(b':');
                1
            } else { 0 };
            raw_message.push_all(bytes);
            let end = start + 1 + bytes.len() + offset;
            let slice = ASlice { start: start + 1 + offset, end: end };
            start = end;
            slice
        }).collect();
        RawMessage {
            raw_message: raw_message,
            prefix: msg_prefix,
            command: msg_command,
            params: msg_params
        }
    }

    /// Parses a message. Extracts the prefix, command and the params
    pub fn parse(mut message: &[u8]) -> Result<RawMessage, &'static str> {
        // Check for message prefix (starts with : and ends with space)
        let raw_message = Vec::from_slice(message);
        let prefix = if message.starts_with([b':']) {
            let prefix_end = match message.position_elem(&b' ') {
                Some(v) => v,
                None => return Err("RawMessage does not contain a command.")
            };
            message = message.slice_from(prefix_end + 1);
            Some(ASlice{ start: 1, end: prefix_end })
        } else {
            None
        };
        let cmd_start = prefix.map(|v| v.end + 1).unwrap_or(0);
        let trailing = match position(message, " :".as_bytes()) {
            Some(trailing_pos) => {
                message = message.slice_to(trailing_pos);
                Some(ASlice {
                    start: cmd_start + trailing_pos + 2,
                    end: raw_message.len() })
            },
            None => None
        };
        let mut middle_iter = message.split(|&x| x == b' ');
        let command = match middle_iter.next() {
            Some(cmd) =>
                ASlice { start: cmd_start,
                           end: cmd_start + cmd.len() },
            None => return Err("RawMessage does not contain a command.")
        };
        let mut start = command.end + 1;
        let mut params: Vec<ASlice> = middle_iter.map(|p| {
            let slice = ASlice { start: start, end: start + p.len() };
            start = slice.end + 1;
            slice
        }).collect();
        if trailing.is_some() {
            params.push(trailing.unwrap())
        }
        Ok(RawMessage {
            raw_message: raw_message,
            prefix: prefix,
            command: command,
            params: params
        })
    }

    pub fn receivers_do_or_else(&self, then: |util::Receiver|, else_: ||) {
        let params = self.params();
        if params.len() > 0 {
            for recv in params[0].as_slice().split(|c| *c == b',') {
                then(util::verify_receiver(recv))
            }
        } else {
            else_()
        }
    }

    /// Returns the message prefix
    /// It might contain non-utf8 chars and thus only bytes are returned.
    pub fn prefix<'a>(&'a self) -> Option<&'a[u8]> {
        self.prefix.map(|p| p.slice_vec(&self.raw_message))
    }

    /// Sets the message prefix
    /// For all purposes of this library &str should be fine since only
    /// ASCII chars will be used for the prefix.
    pub fn set_prefix(&mut self, prefix: &str) {
        let bytes = prefix.as_bytes();
        let offset = match self.prefix {
            Some(ref mut old_prefix) => {
                self.raw_message = Vec::from_slice(b":")
                    .append(bytes)
                    .append(self.raw_message.slice_from(old_prefix.end));
                let offset = prefix.len() - old_prefix.end + 1;
                old_prefix.end += offset;
                offset
            },
            None => {
                self.raw_message = Vec::from_slice(b":")
                    .append(bytes)
                    .append(b" ")
                    .append(self.raw_message.as_slice());
                prefix.len() + 2
            }
        };
        self.command.start += offset;
        self.command.end += offset;
        for param in self.params.mut_iter() {
            param.start += offset;
            param.end += offset;
        }
    }

    /// Returns the message command
    pub fn command<'a>(&'a self) -> Command<'a> {
        Command::from_bytes(self.command.slice_vec(&self.raw_message))
    }

    /// Returns the parameters of the command
    /// *Note* since the IRC protocol does not define any encoding
    /// raw bytes are returned.
    pub fn params<'a>(&'a self) -> Vec<&'a[u8]> {
        self.params.iter().map(
            |slice| slice.slice_vec(&self.raw_message)
        ).collect()
    }

    /// Returns the raw message
    pub fn as_slice<'a>(&'a self) -> &'a[u8] {
        self.raw_message.as_slice()
    }

    /// Returns the message as an string for debugging/logging
    pub fn to_string(&self) -> String {
        String::from_utf8_lossy(self.raw_message.as_slice()).into_string()
    }
}

#[cfg(test)]
mod tests {
	use super::{RawMessage};
	use cmd::{JOIN};
	/// Test the nickname validation function
	#[test]
	fn test_message_parser() {
        let m = RawMessage::parse(":prefix JOIN #channel".as_bytes()).unwrap();
        assert_eq!(m.prefix().unwrap(), b"prefix")
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
	}
	/// Test the prefix setter
	#[test]
	fn test_prefix_setter() {
        let mut m = RawMessage::parse(":prefix JOIN #channel".as_bytes()).unwrap();
        m.set_prefix("new prefix");
        assert_eq!(String::from_utf8_lossy(m.prefix().unwrap()).to_owned(),
                   String::from_str("new prefix").to_owned())
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
        assert_eq!(m.as_slice(), b":new prefix JOIN #channel")
	}
	/// Test message creation
	#[test]
	fn test_msg_new() {
        let m = RawMessage::new(JOIN, &["#channel"], Some("prefix"));
        assert_eq!(m.prefix().unwrap(), b"prefix")
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
        assert_eq!(m.as_slice(), b":prefix JOIN :#channel")
	}
}<commit_msg>simplified function<commit_after>use cmd::*;
use util;

#[deriving(Show, Clone)]
// Helper struct to efficently adress the different parts
// of the message.
struct ASlice {
    start: uint,
    end: uint
}

impl ASlice {
    #[inline]
    fn slice_vec<'a, T>(&self, vec: &'a Vec<T>) -> &'a[T] {
        vec.slice(self.start, self.end)
    }
}

/// IRC message
// TODO: do not use vecs for that, better [u8, ..510] and slices to that
// or just safe offsets in the message parts fields…
#[deriving(Show, Clone)]
pub struct RawMessage {
    raw_message: Vec<u8>,
    prefix: Option<ASlice>,
    command: ASlice,
    params: Vec<ASlice>
}

/// Searches a slice for the first occurence of needle
fn position<T: PartialEq>(this: &[T], needle: &[T]) -> Option<uint> {
    this.windows(needle.len()).position(|v| v == needle)
}

impl RawMessage {
    /// Creates a new message
    pub fn new(command: Command,
                params: &[&str],
                prefix: Option<&str>) -> RawMessage {
        let mut raw_message = Vec::with_capacity(20);
        let msg_prefix = prefix.map(|p| {
            raw_message.push(b':');
            raw_message.push_all(p.as_bytes());
            raw_message.push(b' ');
            ASlice { start: 1, end: p.as_bytes().len() + 1 }
        });
        let cmd = command.to_bytes();
        let cmd_bytes = cmd.as_slice();
        let msg_command = ASlice{ start: raw_message.len(),
                                    end: raw_message.len() + cmd_bytes.len() };
        raw_message.push_all(cmd_bytes);
        let mut start = msg_command.end;
        let num_params = params.len();
        let msg_params = params.iter().enumerate().map( |(i, &param)| {
            let bytes = param.as_bytes();
            raw_message.push(b' ');
            let offset = if i + 1 == num_params {
                raw_message.push(b':');
                1
            } else { 0 };
            raw_message.push_all(bytes);
            let end = start + 1 + bytes.len() + offset;
            let slice = ASlice { start: start + 1 + offset, end: end };
            start = end;
            slice
        }).collect();
        RawMessage {
            raw_message: raw_message,
            prefix: msg_prefix,
            command: msg_command,
            params: msg_params
        }
    }

    /// Parses a message. Extracts the prefix, command and the params
    pub fn parse(mut message: &[u8]) -> Result<RawMessage, &'static str> {
        // Check for message prefix (starts with : and ends with space)
        let raw_message = Vec::from_slice(message);
        let prefix = if message.starts_with([b':']) {
            let prefix_end = match message.position_elem(&b' ') {
                Some(v) => v,
                None => return Err("RawMessage does not contain a command.")
            };
            message = message.slice_from(prefix_end + 1);
            Some(ASlice{ start: 1, end: prefix_end })
        } else {
            None
        };
        let cmd_start = prefix.map(|v| v.end + 1).unwrap_or(0);
        let trailing = match position(message, " :".as_bytes()) {
            Some(trailing_pos) => {
                message = message.slice_to(trailing_pos);
                Some(ASlice {
                    start: cmd_start + trailing_pos + 2,
                    end: raw_message.len() })
            },
            None => None
        };
        let mut middle_iter = message.split(|&x| x == b' ');
        let command = match middle_iter.next() {
            Some(cmd) =>
                ASlice { start: cmd_start,
                           end: cmd_start + cmd.len() },
            None => return Err("RawMessage does not contain a command.")
        };
        let mut start = command.end + 1;
        let mut params: Vec<ASlice> = middle_iter.map(|p| {
            let slice = ASlice { start: start, end: start + p.len() };
            start = slice.end + 1;
            slice
        }).collect();
        if trailing.is_some() {
            params.push(trailing.unwrap())
        }
        Ok(RawMessage {
            raw_message: raw_message,
            prefix: prefix,
            command: command,
            params: params
        })
    }

    pub fn receivers_do_or_else(&self, then: |util::Receiver|, else_: ||) {
        let params = self.params();
        if params.len() > 0 {
            for recv in params[0].as_slice().split(|c| *c == b',') {
                then(util::verify_receiver(recv))
            }
        } else {
            else_()
        }
    }

    /// Returns the message prefix
    /// It might contain non-utf8 chars and thus only bytes are returned.
    pub fn prefix<'a>(&'a self) -> Option<&'a[u8]> {
        self.prefix.map(|p| p.slice_vec(&self.raw_message))
    }

    /// Sets the message prefix
    /// For all purposes of this library &str should be fine since only
    /// ASCII chars will be used for the prefix.
    pub fn set_prefix(&mut self, prefix: &str) {
        let bytes = prefix.as_bytes();
        let offset = match self.prefix {
            Some(ref mut old_prefix) => {
                self.raw_message = Vec::from_slice(b":")
                    .append(bytes)
                    .append(self.raw_message.slice_from(old_prefix.end));
                let offset = prefix.len() - old_prefix.end + 1;
                old_prefix.end += offset;
                offset
            },
            None => {
                self.raw_message = Vec::from_slice(b":")
                    .append(bytes)
                    .append(b" ")
                    .append(self.raw_message.as_slice());
                prefix.len() + 2
            }
        };
        self.command.start += offset;
        self.command.end += offset;
        for param in self.params.mut_iter() {
            param.start += offset;
            param.end += offset;
        }
    }

    /// Returns the message command
    pub fn command<'a>(&'a self) -> Command<'a> {
        Command::from_bytes(self.command.slice_vec(&self.raw_message))
    }

    /// Returns the parameters of the command
    /// *Note* since the IRC protocol does not define any encoding
    /// raw bytes are returned.
    pub fn params<'a>(&'a self) -> Vec<&'a[u8]> {
        self.params.iter().map(
            |slice| slice.slice_vec(&self.raw_message)
        ).collect()
    }

    /// Returns the raw message
    pub fn as_slice<'a>(&'a self) -> &'a[u8] {
        self.raw_message.as_slice()
    }

    /// Returns the message as an string for debugging/logging
    pub fn to_string(&self) -> String {
        String::from_utf8_lossy(self.raw_message.as_slice()).into_string()
    }
}

#[cfg(test)]
mod tests {
	use super::{RawMessage};
	use cmd::{JOIN};
	/// Test the nickname validation function
	#[test]
	fn test_message_parser() {
        let m = RawMessage::parse(":prefix JOIN #channel".as_bytes()).unwrap();
        assert_eq!(m.prefix().unwrap(), b"prefix")
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
	}
	/// Test the prefix setter
	#[test]
	fn test_prefix_setter() {
        let mut m = RawMessage::parse(":prefix JOIN #channel".as_bytes()).unwrap();
        m.set_prefix("new prefix");
        assert_eq!(String::from_utf8_lossy(m.prefix().unwrap()).to_owned(),
                   String::from_str("new prefix").to_owned())
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
        assert_eq!(m.as_slice(), b":new prefix JOIN #channel")
	}
	/// Test message creation
	#[test]
	fn test_msg_new() {
        let m = RawMessage::new(JOIN, &["#channel"], Some("prefix"));
        assert_eq!(m.prefix().unwrap(), b"prefix")
        assert!(match m.command() {JOIN => true, _ => false})
        assert_eq!(m.params()[0], b"#channel")
        assert_eq!(m.as_slice(), b":prefix JOIN :#channel")
	}
}<|endoftext|>


<commit_before>use std::collections;
use std::io::{Writer, MemWriter, MemReader, IoResult};
use std::collections::HashMap;
use std::result::{Ok, Err};

pub static CQL_VERSION:u8 = 0x02;

pub enum Consistency {
  Any = 0x0000,
  One = 0x0001,
  Two = 0x0002,
  Three = 0x0003,
  Quorum = 0x0004,
  All = 0x0005,
  LocalQuorum = 0x0006,
  EachQuorum = 0x0007,
  UnknownConsistency,
}

pub type CqlHashMap = collections::HashMap<String, String>;

pub enum Request {
  Startup(CqlHashMap),
  Credential(Vec<String>), // not used in v2
  Options,
  Query(String, Consistency)
}

impl Request {
  pub fn opcode(&self) -> u8 {
    match *self {
      Startup(_) => 0x01,
      Credential(_) => 0x04,
      Options => 0x05,
      Query(_, _) => 0x07
    }
  }
}

#[deriving(Show)]
pub enum Response {
  Error(u32, String),
  Ready,
  Supported,
  Result(ResultBody),
  Authenticate(String),
  Unknown,
  Empty
}

#[deriving(Show)]
pub enum ResultBody {
  Void,
  Rows(Vec<Row>),
  SetKeyspace(String),
  Prepared,
  SchemaChange(String, String, String)
}

#[deriving(Show)]
pub struct ColumnSpec {
  name: String,
  col_type: u16//ColumnType
}

#[deriving(Show)]
pub struct Row {
  columns: HashMap<String, Column>
}

pub enum ColumnType {
  Custom = 0,
  Ascii = 1,
  Bigint = 2,
  Blob = 3,
  Boolean = 4,
  Counter = 5,
  Decimal = 6,
  Double = 7,
  Float = 8,
  Int = 9,
  Text = 10,
  Timestamp = 11,
  Uuid = 12,
  Varchar = 13,
  Varint = 14,
  Timeuuid = 15,
  Inet = 16,
  List = 17,
  Map = 18,
  Set = 19
}

#[deriving(Show)]
pub enum Column {
  CqlString(String),
  CqlInt(i32),
  CqlLong(i64),
  CqlFloat(f32),
  CqlDouble(f64)
}
#[doc(hidden)]
pub trait WriteMessage {
  fn write_message(&mut self, &Request) -> IoResult<()>;
}

impl<W: Writer> WriteMessage for W {
  fn write_message(&mut self, message: &Request) -> IoResult<()> {
    let mut header = MemWriter::new();

    try!(header.write_u8(CQL_VERSION));
    try!(header.write_u8(0x00));
    try!(header.write_i8(1));
    try!(header.write_u8(message.opcode()));

    let mut buf = MemWriter::new();

    match *message {
      Startup(ref hash_map) => {
        // try!(body.write(hash_map.as_cql_binary()));
        try!(buf.write_be_u16(hash_map.len() as u16));
        for (key, val) in hash_map.iter() {
          try!(buf.write_be_u16(key.len() as u16));
          try!(buf.write_str(key.as_slice()));
          try!(buf.write_be_u16(val.len() as u16));
          try!(buf.write_str(val.as_slice()));
        }
      }
      Query(ref query, consistency) => {
        try!(buf.write_be_u32(query.len() as u32));
        try!(buf.write_str(query.as_slice()));
        try!(buf.write_be_u16(consistency as u16));
        try!(buf.write_u8(0u as u8));
      }
      _ => ()
    }

    let header = header.unwrap();
    let buf = buf.unwrap();

    try!(self.write(header.as_slice()));
    try!(self.write_be_u32(buf.len() as u32));
    try!(self.write(buf.as_slice()));

    Ok(())
  }
}

#[doc(hidden)]
pub trait ReadMessage {
  fn read_message(&mut self) -> IoResult<Response>;
}

impl<R: Reader> ReadMessage for R {
  fn read_message(&mut self) -> IoResult<Response> {
    let _version = try!(self.read_u8());
    let _flags = try!(self.read_u8());
    let _stream = try!(self.read_i8());
    let opcode = try!(self.read_u8());
    let len = try!(self.read_be_u32());

    let mut buf = MemReader::new(try!(self.read_exact(len as uint)));

    let ret = match opcode {
      0 => try!(read_error_response(&mut buf)),
      2 => Ready,
      3 => Authenticate("test".to_string()),
      6 => Supported,
      8 => try!(read_result(&mut buf)),
      _ => Empty
    };

    Ok(ret)
  }
}
//   PrepareOpcode = 0x09,
//   ExecuteOpcode = 0x0A,
//   RegisterOpcode = 0x0B,
//   EventOpcode = 0x0C,
//   BatchOpcode = 0x0D,
//   AuthChallengeOpcode = 0x0E,
//   AuthResponseOpcode = 0x0F,
//   AuthSuccessOpcode = 0x10,
//
//   UnknownOpcode

fn read_error_response(buf: &mut MemReader) -> IoResult<Response> {
  let code = try!(buf.read_be_u32());
  let len = try!(buf.read_be_u16());
  let string_bytes = try!(buf.read_exact(len as uint));
  let res = String::from_utf8(string_bytes);
  Ok(match res {
    Ok(string) => Error(code, string),
    Err(_) => Error(code, "couldn't parse".to_string())
  })
}

fn read_result(buf: &mut MemReader) -> IoResult<Response> {
  let result_type = try!(buf.read_be_u32());

  let body = match result_type {
    2 => {
      let flags = try!(buf.read_be_u32());
      let column_count = try!(buf.read_be_u32());
      //assume global column spec
      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let keyspace = String::from_utf8(string_bytes).unwrap();

      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let table = String::from_utf8(string_bytes).unwrap();

      println!("The flags are {}, and column count is {}", flags, column_count);
      println!("The keyspace is {}, and table is {}", keyspace, table);

      let mut column_specs = vec!();

      for _ in range(0, column_count) {
        let len = try!(buf.read_be_u16());
        let string_bytes = try!(buf.read_exact(len as uint));
        let name = String::from_utf8(string_bytes).unwrap();
        let col_type = try!(buf.read_be_u16());
        let spec = ColumnSpec { name: name, col_type: col_type };
        println!("Found spec: {}", spec);
        column_specs.push(spec);
      }

      let row_count = try!(buf.read_be_u32());
      let mut rows = vec!();
      println!("Row count: {}", row_count);

      for _ in range(0, row_count) {
        let mut columns = HashMap::new();
        for col_spec in column_specs.iter() {
          let len = try!(buf.read_be_u32());
          println!("num of bytes for col is {}", len);
          let col_val = match col_spec.col_type {
            8 => {
              let val = try!(buf.read_be_f32());
              CqlFloat(val)
            }
            9 => {
              let val = try!(buf.read_be_i32());
              CqlInt(val)
            },
            _ => {
              let val_bytes = try!(buf.read_exact(len as uint));
              let name = String::from_utf8(val_bytes).unwrap();
              CqlString(name)
            }
          };
          println!("Found col_val: {}", col_val);
          columns.insert(col_spec.name.clone(), col_val);
        }
        rows.push(Row { columns: columns});
      }
      Rows(rows)
    },
    3 => {
      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let name = String::from_utf8(string_bytes).unwrap();
      SetKeyspace(name)
    },
    4 => Prepared,
    5 => {
      // dedup this - map over range?
      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let change = String::from_utf8(string_bytes).unwrap();

      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let keyspace = String::from_utf8(string_bytes).unwrap();

      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let table = String::from_utf8(string_bytes).unwrap();
      SchemaChange(change, keyspace, table)
    },
    _ => Void,
  };

  Ok(Result(body))
}
<commit_msg>formatting<commit_after>use std::collections;
use std::io::{Writer, MemWriter, MemReader, IoResult};
use std::collections::HashMap;
use std::result::{Ok, Err};

pub static CQL_VERSION:u8 = 0x02;

pub enum Consistency {
  Any = 0x0000,
  One = 0x0001,
  Two = 0x0002,
  Three = 0x0003,
  Quorum = 0x0004,
  All = 0x0005,
  LocalQuorum = 0x0006,
  EachQuorum = 0x0007,
  UnknownConsistency,
}

pub type CqlHashMap = HashMap<String, String>;

pub enum Request {
  Startup(CqlHashMap),
  Credential(Vec<String>), // not used in v2
  Options,
  Query(String, Consistency)
}

impl Request {
  pub fn opcode(&self) -> u8 {
    match *self {
      Startup(_) => 0x01,
      Credential(_) => 0x04,
      Options => 0x05,
      Query(_, _) => 0x07
    }
  }
}

#[deriving(Show)]
pub enum Response {
  Error(u32, String),
  Ready,
  Supported,
  Result(ResultBody),
  Authenticate(String),
  Unknown,
  Empty
}

#[deriving(Show)]
pub enum ResultBody {
  Void,
  Rows(Vec<Row>),
  SetKeyspace(String),
  Prepared,
  SchemaChange(String, String, String)
}

#[deriving(Show)]
pub struct ColumnSpec {
  name: String,
  col_type: u16//ColumnType
}

#[deriving(Show)]
pub struct Row {
  columns: HashMap<String, Column>
}

pub enum ColumnType {
  Custom = 0,
  Ascii = 1,
  Bigint = 2,
  Blob = 3,
  Boolean = 4,
  Counter = 5,
  Decimal = 6,
  Double = 7,
  Float = 8,
  Int = 9,
  Text = 10,
  Timestamp = 11,
  Uuid = 12,
  Varchar = 13,
  Varint = 14,
  Timeuuid = 15,
  Inet = 16,
  List = 17,
  Map = 18,
  Set = 19
}

#[deriving(Show)]
pub enum Column {
  CqlString(String),
  CqlInt(i32),
  CqlLong(i64),
  CqlFloat(f32),
  CqlDouble(f64)
}
#[doc(hidden)]
pub trait WriteMessage {
  fn write_message(&mut self, &Request) -> IoResult<()>;
}

impl<W: Writer> WriteMessage for W {
  fn write_message(&mut self, message: &Request) -> IoResult<()> {
    let mut header = MemWriter::new();

    try!(header.write_u8(CQL_VERSION));
    try!(header.write_u8(0x00));
    try!(header.write_i8(1));
    try!(header.write_u8(message.opcode()));

    let mut buf = MemWriter::new();

    match *message {
      Startup(ref hash_map) => {
        // try!(body.write(hash_map.as_cql_binary()));
        try!(buf.write_be_u16(hash_map.len() as u16));
        for (key, val) in hash_map.iter() {
          try!(buf.write_be_u16(key.len() as u16));
          try!(buf.write_str(key.as_slice()));
          try!(buf.write_be_u16(val.len() as u16));
          try!(buf.write_str(val.as_slice()));
        }
      },
      Query(ref query, consistency) => {
        try!(buf.write_be_u32(query.len() as u32));
        try!(buf.write_str(query.as_slice()));
        try!(buf.write_be_u16(consistency as u16));
        try!(buf.write_u8(0u as u8));
      },
      _ => ()
    }

    let header = header.unwrap();
    let buf = buf.unwrap();

    try!(self.write(header.as_slice()));
    try!(self.write_be_u32(buf.len() as u32));
    try!(self.write(buf.as_slice()));

    Ok(())
  }
}

#[doc(hidden)]
pub trait ReadMessage {
  fn read_message(&mut self) -> IoResult<Response>;
}

impl<R: Reader> ReadMessage for R {
  fn read_message(&mut self) -> IoResult<Response> {
    let _version = try!(self.read_u8());
    let _flags = try!(self.read_u8());
    let _stream = try!(self.read_i8());
    let opcode = try!(self.read_u8());
    let len = try!(self.read_be_u32());

    let mut buf = MemReader::new(try!(self.read_exact(len as uint)));

    let ret = match opcode {
      0 => try!(read_error_response(&mut buf)),
      2 => Ready,
      3 => Authenticate("test".to_string()),
      6 => Supported,
      8 => try!(read_result(&mut buf)),
      _ => Empty
    };

    Ok(ret)
  }
}
//   PrepareOpcode = 0x09,
//   ExecuteOpcode = 0x0A,
//   RegisterOpcode = 0x0B,
//   EventOpcode = 0x0C,
//   BatchOpcode = 0x0D,
//   AuthChallengeOpcode = 0x0E,
//   AuthResponseOpcode = 0x0F,
//   AuthSuccessOpcode = 0x10,
//
//   UnknownOpcode

fn read_error_response(buf: &mut MemReader) -> IoResult<Response> {
  let code = try!(buf.read_be_u32());
  let len = try!(buf.read_be_u16());
  let string_bytes = try!(buf.read_exact(len as uint));
  let res = String::from_utf8(string_bytes);
  Ok(match res {
    Ok(string) => Error(code, string),
    Err(_) => Error(code, "couldn't parse".to_string())
  })
}

fn read_result(buf: &mut MemReader) -> IoResult<Response> {
  let result_type = try!(buf.read_be_u32());

  let body = match result_type {
    2 => {
      let flags = try!(buf.read_be_u32());
      let column_count = try!(buf.read_be_u32());
      //assume global column spec
      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let keyspace = String::from_utf8(string_bytes).unwrap();

      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let table = String::from_utf8(string_bytes).unwrap();

      println!("The flags are {}, and column count is {}", flags, column_count);
      println!("The keyspace is {}, and table is {}", keyspace, table);

      let mut column_specs = vec!();

      for _ in range(0, column_count) {
        let len = try!(buf.read_be_u16());
        let string_bytes = try!(buf.read_exact(len as uint));
        let name = String::from_utf8(string_bytes).unwrap();
        let col_type = try!(buf.read_be_u16());
        let spec = ColumnSpec { name: name, col_type: col_type };
        println!("Found spec: {}", spec);
        column_specs.push(spec);
      }

      let row_count = try!(buf.read_be_u32());
      let mut rows = vec!();
      println!("Row count: {}", row_count);

      for _ in range(0, row_count) {
        let mut columns = HashMap::new();
        for col_spec in column_specs.iter() {
          let len = try!(buf.read_be_u32());
          println!("num of bytes for col is {}", len);
          let col_val = match col_spec.col_type {
            8 => {
              let val = try!(buf.read_be_f32());
              CqlFloat(val)
            }
            9 => {
              let val = try!(buf.read_be_i32());
              CqlInt(val)
            },
            _ => {
              let val_bytes = try!(buf.read_exact(len as uint));
              let name = String::from_utf8(val_bytes).unwrap();
              CqlString(name)
            }
          };
          println!("Found col_val: {}", col_val);
          columns.insert(col_spec.name.clone(), col_val);
        }
        rows.push(Row { columns: columns});
      }
      Rows(rows)
    },
    3 => {
      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let name = String::from_utf8(string_bytes).unwrap();
      SetKeyspace(name)
    },
    4 => Prepared,
    5 => {
      // dedup this - map over range?
      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let change = String::from_utf8(string_bytes).unwrap();

      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let keyspace = String::from_utf8(string_bytes).unwrap();

      let len = try!(buf.read_be_u16());
      let string_bytes = try!(buf.read_exact(len as uint));
      let table = String::from_utf8(string_bytes).unwrap();
      SchemaChange(change, keyspace, table)
    },
    _ => Void,
  };

  Ok(Result(body))
}
<|endoftext|>


<commit_before>use basetypes::*;

pub struct BoardGeometry {
    grid: [u8; 120],
    piece_grid_deltas: [[i8; 8]; 5],
    piece_longrange: [bool; 5],
    pub attacks: [[u64; 64]; 5],
    pub blockers_and_beyond: [[u64; 64]; 5],
    pub squares_at_line: [[u64; 64]; 64],
    pub squares_between_including: [[u64; 64]; 64],
    pub squares_behind_blocker: [[u64; 64]; 64],
}

impl BoardGeometry {
    pub fn new() -> BoardGeometry {
        // We use 10x12 grid (8x8 with guarding markers, 2 at top and
        // bottom, 1 at the sides), so that we can detect out-of-board
        // movements. Each cell in the grid contains the corresponding
        // square number (from 0 to 63) or 0xff (the guarding marker).
        let mut grid = [0xffu8; 120];
        for i in 0..64 {
            grid[BoardGeometry::grid_index_from_square(i)] = i as u8;
        }

        // "piece_deltas" represent the change in the grid-index when
        // sliding a particular piece by one square in a particular
        // direction. We are not concerned with pawns here.
        let mut piece_grid_deltas = [[0i8; 8]; 5];
        piece_grid_deltas[QUEEN] = [-11, -10, -9, -1, 1, 9, 10, 11];
        piece_grid_deltas[ROOK] = [0, -10, 0, -1, 1, 0, 10, 0];
        piece_grid_deltas[BISHOP] = [-11, 0, -9, 0, 0, 9, 0, 11];
        piece_grid_deltas[KNIGHT] = [-21, -19, -12, -8, 8, 12, 19, 21];
        piece_grid_deltas[KING] = [-11, -10, -9, -1, 1, 9, 10, 11];

        // All pieces except knights and kings are long-range (They
        // can slide by more than one square). We are not concerned
        // with pawns here.
        let mut piece_longrange = [true; 5];
        piece_longrange[KNIGHT] = false;
        piece_longrange[KING] = false;

        let mut g = BoardGeometry {
            grid: grid,
            piece_grid_deltas: piece_grid_deltas,
            piece_longrange: piece_longrange,
            attacks: [[0u64; 64]; 5],
            blockers_and_beyond: [[0u64; 64]; 5],
            squares_at_line: [[0u64; 64]; 64],
            squares_between_including: [[0u64; 64]; 64],
            squares_behind_blocker: [[0u64; 64]; 64],
        };

        // "attacks" and "blockers_and_beyond" fields hold attack and
        // blockers bitsets for each piece on each possible square.
        // For example:
        //
        // g.attacks[QUEEN][D4]  g.blockers_and_beyond[QUEEN][D4]
        // . . . 1 . . . 1       . . . . . . . .
        // 1 . . 1 . . 1 .       . . . 1 . . 1 .
        // . 1 . 1 . 1 . .       . 1 . 1 . 1 . .
        // . . 1 1 1 . . .       . . 1 1 1 . . .
        // 1 1 1 Q 1 1 1 1       . 1 1 Q 1 1 1 .
        // . . 1 1 1 . . .       . . 1 1 1 . . .
        // . 1 . 1 . 1 . .       . 1 . 1 . 1 . .
        // 1 . . 1 . . 1 .       . . . . . . . .
        //
        // g.attacks[KNIGHT][D4] g.blockers_and_beyond[KNIGHT][D4]
        // . . . . . . . .       . . . . . . . .
        // . . . . . . . .       . . . . . . . .
        // . . 1 . 1 . . .       . . . . . . . .
        // . 1 . . . 1 . .       . . . . . . . .
        // . . . N . . . .       . . . N . . . .
        // . 1 . . . 1 . .       . . . . . . . .
        // . . 1 . 1 . . .       . . . . . . . .
        // . . . . . . . .       . . . . . . . .
        g.fill_attack_and_blockers_and_beyond_arrays();

        // The "squares_behind_blocker" field holds bitsets that
        // describe all squares hidden behind a blocker from the
        // attacker's position. For example:
        //
        // g.squares_behind_blocker[B2][F6]
        // . . . . . . . 1
        // . . . . . . 1 .
        // . . . . . B . .
        // . . . . . . . .
        // . . . . . . . .
        // . . . . . . . .
        // . A . . . . . .
        // . . . . . . . .
        //
        // The "squares_between_including" field holds bitsets that
        // describe all squares between an attacker an a blocker
        // including the attacker's and blocker's fields
        // themselves. For example:
        //
        // g.squares_between_including[B2][F6]
        // . . . . . . . .
        // . . . . . . . .
        // . . . . . 1 . .
        // . . . . 1 . . .
        // . . . 1 . . . .
        // . . 1 . . . . .
        // . 1 . . . . . .
        // . . . . . . . .
        g.fill_squares_between_including_and_squares_behind_blocker_arrays();

        // The "squares_at_line" field holds bitsets that describe all
        // squares lying at the line determined by the attacker and
        // the blocker. For example:
        //
        // g.squares_at_line[B2][F6]
        // . . . . . . . 1
        // . . . . . . 1 .
        // . . . . . 1 . .
        // . . . . 1 . . .
        // . . . 1 . . . .
        // . . 1 . . . . .
        // . 1 . . . . . .
        // 1 . . . . . . .
        g.fill_squares_at_line_array();

        g
    }

    fn grid_index(&self, i: Square) -> usize {
        Self::grid_index_from_square(i)
    }

    #[inline(always)]
    fn grid_index_from_square(i: Square) -> usize {
        ((i / 8) * 10 + (i % 8) + 21)
    }

    fn fill_attack_and_blockers_and_beyond_arrays(&mut self) {
        for piece_type in 0..5 {
            for square in 0..64 {
                let mut attack = 0u64;
                let mut blockers = 0u64;
                for move_direction in 0..8 {
                    let delta = self.piece_grid_deltas[piece_type][move_direction];
                    if delta != 0 {
                        let mut last_mask = 0u64;
                        let mut curr_grid_index = self.grid_index(square);
                        loop {
                            curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                            let curr_square = self.grid[curr_grid_index] as Square;
                            if curr_square != 0xff {
                                last_mask = 1 << curr_square;
                                attack |= last_mask;
                                blockers |= last_mask;
                                if self.piece_longrange[piece_type] {
                                    continue;
                                }
                            }
                            blockers &= !last_mask;
                            break;
                        }
                    }
                }
                self.attacks[piece_type][square] = attack;
                self.blockers_and_beyond[piece_type][square] = blockers;
            }
        }
    }

    fn fill_squares_between_including_and_squares_behind_blocker_arrays(&mut self) {
        for attacker in 0..64 {
            for blocker in 0..64 {
                // Try to find a grid-index increment (delta) that
                // will generate all squares at the line. If the
                // attacker and the blocker happens not to lie at a
                // straight line, then and we simply proceed to the
                // next attacker/blocker pair.
                let rank_diff = rank(blocker) as i8 - rank(attacker) as i8;
                let file_diff = file(blocker) as i8 - file(attacker) as i8;
                let delta = match (rank_diff, file_diff) {
                    (0, 0) => continue,
                    (0, f) => f.signum(),
                    (r, 0) => 10 * r.signum(),
                    (r, f) if r == f => 10 * r.signum() + r.signum(),
                    (r, f) if r == -f => 10 * r.signum() - r.signum(),
                    _ => continue,
                };

                // Starting from the attacker's square update
                // "squares_between_including" until the blocker's
                // square is encountered, then switch to updating
                // "squares_behind_blocker" until the end of the board
                // is reached.
                let mut squares_between_including = 0u64;
                let mut squares_behind_blocker = 0u64;
                let mut curr_grid_index = self.grid_index(attacker);
                let mut blocker_encountered = false;
                loop {
                    let curr_square = self.grid[curr_grid_index] as Square;
                    match curr_square {
                        0xff => {
                            break;
                        }
                        x if x == blocker => {
                            squares_between_including |= 1 << curr_square;
                            blocker_encountered = true;
                        }
                        _ => {
                            if blocker_encountered {
                                squares_behind_blocker |= 1 << curr_square;
                            } else {
                                squares_between_including |= 1 << curr_square;
                            }
                        }
                    }
                    curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                }
                assert!(blocker_encountered);
                self.squares_between_including[attacker][blocker] = squares_between_including;
                self.squares_behind_blocker[attacker][blocker] = squares_behind_blocker;
            }
        }
    }

    fn fill_squares_at_line_array(&mut self) {
        for a in 0..64 {
            for b in 0..64 {
                self.squares_at_line[a][b] = self.squares_between_including[a][b] |
                                             self.squares_behind_blocker[a][b] |
                                             self.squares_behind_blocker[b][a];
            }
        }
    }
}

// The StateInfo struct stores information needed to restore a Position
// object to its previous state when we retract a move. Whenever a move
// is made on the board (by calling Position::do_move), a StateInfo
// object must be passed as a parameter.

// struct StateInfo {
//   Key pawnKey, materialKey;
//   Value npMaterial[COLOR_NB];
//   int castlingRights, rule50, pliesFromNull;
//   Score psq;
//   Square epSquare;

//   Key key;
//   Bitboard checkersBB;
//   PieceType capturedType;
//   StateInfo* previous;
// };

pub fn generate_normal_moves(bg: &BoardGeometry, board: &Board, checkers: u64, us: Color) {

}

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

    #[test]
    fn test_attack_sets() {
        use basetypes::*;
        let g = BoardGeometry::new();
        assert_eq!(g.attacks[KING][A1], 0b11 << 8 | 0b10);
        assert_eq!(g.blockers_and_beyond[KING][A1], 0);
        assert_eq!(g.attacks[ROOK][A1],
                   0b11111110 | 1 << 8 | 1 << 16 | 1 << 24 | 1 << 32 | 1 << 40 | 1 << 48 | 1 << 56);
        assert_eq!(g.blockers_and_beyond[ROOK][A1],
                   0b01111110 | 1 << 8 | 1 << 16 | 1 << 24 | 1 << 32 | 1 << 40 | 1 << 48 | 0 << 56);
        assert_eq!(g.attacks[KING][D4], g.attacks[KING][E4] >> 1);
        assert_eq!(g.attacks[KING][D4], g.attacks[KING][D5] >> 8);
        assert_eq!(g.attacks[KNIGHT][D4], g.attacks[KNIGHT][D5] >> 8);
        assert_eq!(g.attacks[KNIGHT][D4] & g.attacks[KING][D5], 1 << C6 | 1 << E6);
        assert_eq!(g.attacks[ROOK][D4] | g.attacks[BISHOP][D4], g.attacks[QUEEN][D4]);
        assert_eq!(g.attacks[ROOK][D4] & g.attacks[BISHOP][D4], 0);
        assert_eq!(g.attacks[KING][D4] & g.attacks[QUEEN][D4], g.attacks[KING][D4]);
        assert_eq!(g.attacks[BISHOP][E1] & g.attacks[KNIGHT][H1], 1 << F2 | 1 << G3);
    }

    #[test]
    fn test_line_sets() {
        use basetypes::*;
        let g = BoardGeometry::new();
        assert_eq!(g.squares_at_line[B1][G1], 0b11111111);
        assert_eq!(g.squares_at_line[G8][B8], 0b11111111 << 56);
        assert_eq!(g.squares_between_including[B1][G1], 0b01111110);
        assert_eq!(g.squares_between_including[G8][B8], 0b01111110 << 56);
        assert_eq!(g.squares_behind_blocker[B1][G1], 1 << H1);
        assert_eq!(g.squares_behind_blocker[G8][B8], 1 << A8);
        assert_eq!(g.squares_behind_blocker[A1][G7], 1 << H8);
        assert_eq!(g.squares_behind_blocker[H1][B7], 1 << A8);
        assert_eq!(g.squares_behind_blocker[B7][G2], 1 << H1);
        assert_eq!(g.squares_behind_blocker[G7][B2], 1 << A1);
        assert_eq!(g.squares_behind_blocker[D7][D7], 0);
        assert_eq!(g.squares_behind_blocker[D7][F8], 0);
        assert_eq!(g.squares_between_including[A1][A4] | g.squares_behind_blocker[A1][A4],
                   g.squares_at_line[A1][A4]);
    }
}
<commit_msg>Added unimplemented generate_moves function.<commit_after>use basetypes::*;

pub struct BoardGeometry {
    grid: [u8; 120],
    piece_grid_deltas: [[i8; 8]; 5],
    piece_longrange: [bool; 5],
    pub attacks: [[u64; 64]; 5],
    pub blockers_and_beyond: [[u64; 64]; 5],
    pub squares_at_line: [[u64; 64]; 64],
    pub squares_between_including: [[u64; 64]; 64],
    pub squares_behind_blocker: [[u64; 64]; 64],
}

impl BoardGeometry {
    pub fn new() -> BoardGeometry {
        // We use 10x12 grid (8x8 with guarding markers, 2 at top and
        // bottom, 1 at the sides), so that we can detect out-of-board
        // movements. Each cell in the grid contains the corresponding
        // square number (from 0 to 63) or 0xff (the guarding marker).
        let mut grid = [0xffu8; 120];
        for i in 0..64 {
            grid[BoardGeometry::grid_index_from_square(i)] = i as u8;
        }

        // "piece_deltas" represent the change in the grid-index when
        // sliding a particular piece by one square in a particular
        // direction. We are not concerned with pawns here.
        let mut piece_grid_deltas = [[0i8; 8]; 5];
        piece_grid_deltas[QUEEN] = [-11, -10, -9, -1, 1, 9, 10, 11];
        piece_grid_deltas[ROOK] = [0, -10, 0, -1, 1, 0, 10, 0];
        piece_grid_deltas[BISHOP] = [-11, 0, -9, 0, 0, 9, 0, 11];
        piece_grid_deltas[KNIGHT] = [-21, -19, -12, -8, 8, 12, 19, 21];
        piece_grid_deltas[KING] = [-11, -10, -9, -1, 1, 9, 10, 11];

        // All pieces except knights and kings are long-range (They
        // can slide by more than one square). We are not concerned
        // with pawns here.
        let mut piece_longrange = [true; 5];
        piece_longrange[KNIGHT] = false;
        piece_longrange[KING] = false;

        let mut bg = BoardGeometry {
            grid: grid,
            piece_grid_deltas: piece_grid_deltas,
            piece_longrange: piece_longrange,
            attacks: [[0u64; 64]; 5],
            blockers_and_beyond: [[0u64; 64]; 5],
            squares_at_line: [[0u64; 64]; 64],
            squares_between_including: [[0u64; 64]; 64],
            squares_behind_blocker: [[0u64; 64]; 64],
        };

        // "attacks" and "blockers_and_beyond" fields hold attack and
        // blockers bitsets for each piece on each possible square.
        // For example:
        //
        // g.attacks[QUEEN][D4]  g.blockers_and_beyond[QUEEN][D4]
        // . . . 1 . . . 1       . . . . . . . .
        // 1 . . 1 . . 1 .       . . . 1 . . 1 .
        // . 1 . 1 . 1 . .       . 1 . 1 . 1 . .
        // . . 1 1 1 . . .       . . 1 1 1 . . .
        // 1 1 1 Q 1 1 1 1       . 1 1 Q 1 1 1 .
        // . . 1 1 1 . . .       . . 1 1 1 . . .
        // . 1 . 1 . 1 . .       . 1 . 1 . 1 . .
        // 1 . . 1 . . 1 .       . . . . . . . .
        //
        // g.attacks[KNIGHT][D4] g.blockers_and_beyond[KNIGHT][D4]
        // . . . . . . . .       . . . . . . . .
        // . . . . . . . .       . . . . . . . .
        // . . 1 . 1 . . .       . . . . . . . .
        // . 1 . . . 1 . .       . . . . . . . .
        // . . . N . . . .       . . . N . . . .
        // . 1 . . . 1 . .       . . . . . . . .
        // . . 1 . 1 . . .       . . . . . . . .
        // . . . . . . . .       . . . . . . . .
        bg.fill_attack_and_blockers_and_beyond_arrays();

        // The "squares_behind_blocker" field holds bitsets that
        // describe all squares hidden behind a blocker from the
        // attacker's position. For example:
        //
        // g.squares_behind_blocker[B2][F6]
        // . . . . . . . 1
        // . . . . . . 1 .
        // . . . . . B . .
        // . . . . . . . .
        // . . . . . . . .
        // . . . . . . . .
        // . A . . . . . .
        // . . . . . . . .
        //
        // The "squares_between_including" field holds bitsets that
        // describe all squares between an attacker an a blocker
        // including the attacker's and blocker's fields
        // themselves. For example:
        //
        // g.squares_between_including[B2][F6]
        // . . . . . . . .
        // . . . . . . . .
        // . . . . . 1 . .
        // . . . . 1 . . .
        // . . . 1 . . . .
        // . . 1 . . . . .
        // . 1 . . . . . .
        // . . . . . . . .
        bg.fill_squares_between_including_and_squares_behind_blocker_arrays();

        // The "squares_at_line" field holds bitsets that describe all
        // squares lying at the line determined by the attacker and
        // the blocker. For example:
        //
        // g.squares_at_line[B2][F6]
        // . . . . . . . 1
        // . . . . . . 1 .
        // . . . . . 1 . .
        // . . . . 1 . . .
        // . . . 1 . . . .
        // . . 1 . . . . .
        // . 1 . . . . . .
        // 1 . . . . . . .
        bg.fill_squares_at_line_array();

        bg
    }

    fn grid_index(&self, i: Square) -> usize {
        Self::grid_index_from_square(i)
    }

    #[inline(always)]
    fn grid_index_from_square(i: Square) -> usize {
        ((i / 8) * 10 + (i % 8) + 21)
    }

    fn fill_attack_and_blockers_and_beyond_arrays(&mut self) {
        for piece_type in 0..5 {
            for square in 0..64 {
                let mut attack = 0u64;
                let mut blockers = 0u64;
                for move_direction in 0..8 {
                    let delta = self.piece_grid_deltas[piece_type][move_direction];
                    if delta != 0 {
                        let mut last_mask = 0u64;
                        let mut curr_grid_index = self.grid_index(square);
                        loop {
                            curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                            let curr_square = self.grid[curr_grid_index] as Square;
                            if curr_square != 0xff {
                                last_mask = 1 << curr_square;
                                attack |= last_mask;
                                blockers |= last_mask;
                                if self.piece_longrange[piece_type] {
                                    continue;
                                }
                            }
                            blockers &= !last_mask;
                            break;
                        }
                    }
                }
                self.attacks[piece_type][square] = attack;
                self.blockers_and_beyond[piece_type][square] = blockers;
            }
        }
    }

    fn fill_squares_between_including_and_squares_behind_blocker_arrays(&mut self) {
        for attacker in 0..64 {
            for blocker in 0..64 {
                // Try to find a grid-index increment (delta) that
                // will generate all squares at the line. If the
                // attacker and the blocker happens not to lie at a
                // straight line, then and we simply proceed to the
                // next attacker/blocker pair.
                let rank_diff = rank(blocker) as i8 - rank(attacker) as i8;
                let file_diff = file(blocker) as i8 - file(attacker) as i8;
                let delta = match (rank_diff, file_diff) {
                    (0, 0) => continue,
                    (0, f) => f.signum(),
                    (r, 0) => 10 * r.signum(),
                    (r, f) if r == f => 10 * r.signum() + r.signum(),
                    (r, f) if r == -f => 10 * r.signum() - r.signum(),
                    _ => continue,
                };

                // Starting from the attacker's square update
                // "squares_between_including" until the blocker's
                // square is encountered, then switch to updating
                // "squares_behind_blocker" until the end of the board
                // is reached.
                let mut squares_between_including = 0u64;
                let mut squares_behind_blocker = 0u64;
                let mut curr_grid_index = self.grid_index(attacker);
                let mut blocker_encountered = false;
                loop {
                    let curr_square = self.grid[curr_grid_index] as Square;
                    match curr_square {
                        0xff => {
                            break;
                        }
                        x if x == blocker => {
                            squares_between_including |= 1 << curr_square;
                            blocker_encountered = true;
                        }
                        _ => {
                            if blocker_encountered {
                                squares_behind_blocker |= 1 << curr_square;
                            } else {
                                squares_between_including |= 1 << curr_square;
                            }
                        }
                    }
                    curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                }
                assert!(blocker_encountered);
                self.squares_between_including[attacker][blocker] = squares_between_including;
                self.squares_behind_blocker[attacker][blocker] = squares_behind_blocker;
            }
        }
    }

    fn fill_squares_at_line_array(&mut self) {
        for a in 0..64 {
            for b in 0..64 {
                self.squares_at_line[a][b] = self.squares_between_including[a][b] |
                                             self.squares_behind_blocker[a][b] |
                                             self.squares_behind_blocker[b][a];
            }
        }
    }
}

// The StateInfo struct stores information needed to restore a Position
// object to its previous state when we retract a move. Whenever a move
// is made on the board (by calling Position::do_move), a StateInfo
// object must be passed as a parameter.

// struct StateInfo {
//   Key pawnKey, materialKey;
//   Value npMaterial[COLOR_NB];
//   int castlingRights, rule50, pliesFromNull;
//   Score psq;
//   Square epSquare;

//   Key key;
//   Bitboard checkersBB;
//   PieceType capturedType;
//   StateInfo* previous;
// };

pub fn generate_moves(bg: &BoardGeometry,
                      board: &Board,
                      checkers: u64,
                      us: Color,
                      move_stack: &mut [Move])
                      -> usize {
    0
}

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

    #[test]
    fn test_attack_sets() {
        use basetypes::*;
        let g = BoardGeometry::new();
        assert_eq!(g.attacks[KING][A1], 0b11 << 8 | 0b10);
        assert_eq!(g.blockers_and_beyond[KING][A1], 0);
        assert_eq!(g.attacks[ROOK][A1],
                   0b11111110 | 1 << 8 | 1 << 16 | 1 << 24 | 1 << 32 | 1 << 40 | 1 << 48 | 1 << 56);
        assert_eq!(g.blockers_and_beyond[ROOK][A1],
                   0b01111110 | 1 << 8 | 1 << 16 | 1 << 24 | 1 << 32 | 1 << 40 | 1 << 48 | 0 << 56);
        assert_eq!(g.attacks[KING][D4], g.attacks[KING][E4] >> 1);
        assert_eq!(g.attacks[KING][D4], g.attacks[KING][D5] >> 8);
        assert_eq!(g.attacks[KNIGHT][D4], g.attacks[KNIGHT][D5] >> 8);
        assert_eq!(g.attacks[KNIGHT][D4] & g.attacks[KING][D5],
                   1 << C6 | 1 << E6);
        assert_eq!(g.attacks[ROOK][D4] | g.attacks[BISHOP][D4],
                   g.attacks[QUEEN][D4]);
        assert_eq!(g.attacks[ROOK][D4] & g.attacks[BISHOP][D4], 0);
        assert_eq!(g.attacks[KING][D4] & g.attacks[QUEEN][D4],
                   g.attacks[KING][D4]);
        assert_eq!(g.attacks[BISHOP][E1] & g.attacks[KNIGHT][H1],
                   1 << F2 | 1 << G3);
    }

    #[test]
    fn test_line_sets() {
        use basetypes::*;
        let g = BoardGeometry::new();
        assert_eq!(g.squares_at_line[B1][G1], 0b11111111);
        assert_eq!(g.squares_at_line[G8][B8], 0b11111111 << 56);
        assert_eq!(g.squares_between_including[B1][G1], 0b01111110);
        assert_eq!(g.squares_between_including[G8][B8], 0b01111110 << 56);
        assert_eq!(g.squares_behind_blocker[B1][G1], 1 << H1);
        assert_eq!(g.squares_behind_blocker[G8][B8], 1 << A8);
        assert_eq!(g.squares_behind_blocker[A1][G7], 1 << H8);
        assert_eq!(g.squares_behind_blocker[H1][B7], 1 << A8);
        assert_eq!(g.squares_behind_blocker[B7][G2], 1 << H1);
        assert_eq!(g.squares_behind_blocker[G7][B2], 1 << A1);
        assert_eq!(g.squares_behind_blocker[D7][D7], 0);
        assert_eq!(g.squares_behind_blocker[D7][F8], 0);
        assert_eq!(g.squares_between_including[A1][A4] | g.squares_behind_blocker[A1][A4],
                   g.squares_at_line[A1][A4]);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Servo, the mighty web browser engine from the future.
//
// This is a very simple library that wires all of Servo's components
// together as type `Browser`, along with a generic client
// implementing the `WindowMethods` trait, to create a working web
// browser.
//
// The `Browser` type is responsible for configuring a
// `Constellation`, which does the heavy lifting of coordinating all
// of Servo's internal subsystems, including the `ScriptTask` and the
// `LayoutTask`, as well maintains the navigation context.
//
// The `Browser` is fed events from a generic type that implements the
// `WindowMethods` trait.
#![feature(libc, rustc_private, thread_local)]
#![cfg_attr(not(test), feature(path))]

extern crate compositing;
extern crate devtools;
extern crate devtools_traits;
extern crate net;
extern crate net_traits;
extern crate msg;
extern crate profile;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate url;
extern crate webdriver_server;

use compositing::CompositorEventListener;
use compositing::windowing::WindowEvent;

use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorTask, Constellation};

use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::ConstellationChan;

use script::dom::bindings::codegen::RegisterBindings;

use net::image_cache_task::{ImageCacheTaskFactory, LoadPlaceholder};
use net::storage_task::StorageTaskFactory;
use net::resource_task::new_resource_task;
use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::StorageTask;

use gfx::font_cache_task::FontCacheTask;
use profile::mem;
use profile::time;
use util::opts;
use util::taskpool::TaskPool;

use std::rc::Rc;
use std::sync::mpsc::Sender;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
impl Browser  {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
    where Window: WindowMethods + 'static {
        ::util::opts::set_experimental_enabled(opts::get().enable_experimental);

        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        // Create the global vtables used by the (generated) DOM
        // bindings to implement JS proxies.
        RegisterBindings::RegisterProxyHandlers();

        // Use this thread pool to load-balance simple tasks, such as
        // image decoding.
        let shared_task_pool = TaskPool::new(8);

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let time_profiler_chan = time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        if let Some(port) = opts.webdriver_port {
            webdriver_server::start_server(port);
        }

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      devtools_chan,
                                                      mem_profiler_chan.clone(),
                                                      shared_task_pool);

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan.clone(),
                                                time_profiler_chan,
                                                mem_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_event(&mut self, event: WindowEvent) -> bool {
        self.compositor.handle_event(event)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}
fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy+Send>,
                        time_profiler_chan: time::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        mem_profiler_chan: mem::ProfilerChan,
                        shared_task_pool: TaskPool) -> ConstellationChan {
    use std::env;

    // Create a Servo instance.
    let resource_task = new_resource_task(opts.user_agent.clone());

    // If we are emitting an output file, then we need to block on
    // image load or we risk emitting an output file missing the
    // image.
    let image_cache_task: ImageCacheTask = if opts.output_file.is_some() {
        ImageCacheTaskFactory::new_sync(resource_task.clone(), shared_task_pool,
                                        time_profiler_chan.clone(), LoadPlaceholder::Preload)
    } else {
        ImageCacheTaskFactory::new(resource_task.clone(), shared_task_pool,
                                   time_profiler_chan.clone(), LoadPlaceholder::Preload)
    };

    let font_cache_task = FontCacheTask::new(resource_task.clone());
    let storage_task: StorageTask = StorageTaskFactory::new();

    let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
    script::script_task::ScriptTask>::start(
        compositor_proxy.clone_compositor_proxy(),
        resource_task,
        image_cache_task,
        font_cache_task,
        time_profiler_chan.clone(),
        mem_profiler_chan.clone(),
        devtools_chan,
        storage_task);

    // Send the URL command to the constellation.
    let cwd = env::current_dir().unwrap();
    let url = match url::Url::parse(&opts.url) {
        Ok(url) => url,
        Err(url::ParseError::RelativeUrlWithoutBase)
        => url::Url::from_file_path(&*cwd.join(&opts.url)).unwrap(),
        Err(_) => panic!("URL parsing failed"),
    };

    {
        let ConstellationChan(ref chan) = constellation_chan;
        chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
    }

    constellation_chan
}
<commit_msg>Auto merge of #5689 - Ms2ger:warnings, r=larsbergstrom<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Servo, the mighty web browser engine from the future.
//
// This is a very simple library that wires all of Servo's components
// together as type `Browser`, along with a generic client
// implementing the `WindowMethods` trait, to create a working web
// browser.
//
// The `Browser` type is responsible for configuring a
// `Constellation`, which does the heavy lifting of coordinating all
// of Servo's internal subsystems, including the `ScriptTask` and the
// `LayoutTask`, as well maintains the navigation context.
//
// The `Browser` is fed events from a generic type that implements the
// `WindowMethods` trait.
#![feature(libc, thread_local)]
#![cfg_attr(not(test), feature(path))]

extern crate compositing;
extern crate devtools;
extern crate devtools_traits;
extern crate net;
extern crate net_traits;
extern crate msg;
extern crate profile;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate url;
extern crate webdriver_server;

use compositing::CompositorEventListener;
use compositing::windowing::WindowEvent;

use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorTask, Constellation};

use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::ConstellationChan;

use script::dom::bindings::codegen::RegisterBindings;

use net::image_cache_task::{ImageCacheTaskFactory, LoadPlaceholder};
use net::storage_task::StorageTaskFactory;
use net::resource_task::new_resource_task;
use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::StorageTask;

use gfx::font_cache_task::FontCacheTask;
use profile::mem;
use profile::time;
use util::opts;
use util::taskpool::TaskPool;

use std::rc::Rc;
use std::sync::mpsc::Sender;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
impl Browser  {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
    where Window: WindowMethods + 'static {
        ::util::opts::set_experimental_enabled(opts::get().enable_experimental);

        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        // Create the global vtables used by the (generated) DOM
        // bindings to implement JS proxies.
        RegisterBindings::RegisterProxyHandlers();

        // Use this thread pool to load-balance simple tasks, such as
        // image decoding.
        let shared_task_pool = TaskPool::new(8);

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let time_profiler_chan = time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        if let Some(port) = opts.webdriver_port {
            webdriver_server::start_server(port);
        }

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      devtools_chan,
                                                      mem_profiler_chan.clone(),
                                                      shared_task_pool);

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan.clone(),
                                                time_profiler_chan,
                                                mem_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_event(&mut self, event: WindowEvent) -> bool {
        self.compositor.handle_event(event)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}
fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy+Send>,
                        time_profiler_chan: time::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        mem_profiler_chan: mem::ProfilerChan,
                        shared_task_pool: TaskPool) -> ConstellationChan {
    use std::env;

    // Create a Servo instance.
    let resource_task = new_resource_task(opts.user_agent.clone());

    // If we are emitting an output file, then we need to block on
    // image load or we risk emitting an output file missing the
    // image.
    let image_cache_task: ImageCacheTask = if opts.output_file.is_some() {
        ImageCacheTaskFactory::new_sync(resource_task.clone(), shared_task_pool,
                                        time_profiler_chan.clone(), LoadPlaceholder::Preload)
    } else {
        ImageCacheTaskFactory::new(resource_task.clone(), shared_task_pool,
                                   time_profiler_chan.clone(), LoadPlaceholder::Preload)
    };

    let font_cache_task = FontCacheTask::new(resource_task.clone());
    let storage_task: StorageTask = StorageTaskFactory::new();

    let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
    script::script_task::ScriptTask>::start(
        compositor_proxy.clone_compositor_proxy(),
        resource_task,
        image_cache_task,
        font_cache_task,
        time_profiler_chan.clone(),
        mem_profiler_chan.clone(),
        devtools_chan,
        storage_task);

    // Send the URL command to the constellation.
    let cwd = env::current_dir().unwrap();
    let url = match url::Url::parse(&opts.url) {
        Ok(url) => url,
        Err(url::ParseError::RelativeUrlWithoutBase)
        => url::Url::from_file_path(&*cwd.join(&opts.url)).unwrap(),
        Err(_) => panic!("URL parsing failed"),
    };

    {
        let ConstellationChan(ref chan) = constellation_chan;
        chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
    }

    constellation_chan
}
<|endoftext|>


<commit_before>use std::{path::PathBuf, str::FromStr};

use structopt::{clap::ArgGroup, StructOpt};

use crate::commands::Command;

#[derive(StructOpt, Clone, PartialEq, Debug)]
pub struct Options {
    #[structopt(hidden = true, possible_value("modules"))]
    pub dummy: Option<String>,

    #[structopt(subcommand)]
    pub command: Command,
}

pub mod graph {
    use super::*;

    #[derive(StructOpt, Clone, PartialEq, Debug)]
    pub struct Options {
        /// Focus the graph on a particular path's environment.
        #[structopt(long = "focus-on")]
        pub focus_on: Option<String>,

        /// The maximum depth of the generated graph
        /// relative to the node selected by '--focus-on'.
        #[structopt(long = "max-depth")]
        pub max_depth: Option<usize>,

        /// Include types (e.g. structs, enums).
        #[structopt(long = "with-types")]
        pub with_types: bool,

        /// Include tests (e.g. `#[cfg(test)] mod tests { … }`).
        #[structopt(long = "with-tests")]
        pub with_tests: bool,

        /// Include orphaned modules (i.e. unused files in /src).
        #[structopt(long = "with-orphans")]
        pub with_orphans: bool,
    }
}

pub mod generate {
    use super::*;

    pub mod graph {
        use super::*;

        #[derive(Clone, PartialEq, Debug)]
        pub enum LayoutAlgorithm {
            Dot,
            Neato,
            Twopi,
            Circo,
            Fdp,
            Sfdp,
        }

        impl FromStr for LayoutAlgorithm {
            type Err = &'static str;

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                match s {
                    "dot" => Ok(Self::Dot),
                    "neato" => Ok(Self::Neato),
                    "twopi" => Ok(Self::Twopi),
                    "circo" => Ok(Self::Circo),
                    "fdp" => Ok(Self::Fdp),
                    "sfdp" => Ok(Self::Sfdp),
                    _ => Err("Unrecognized layout"),
                }
            }
        }

        impl ToString for LayoutAlgorithm {
            fn to_string(&self) -> String {
                match self {
                    Self::Dot => "dot".to_owned(),
                    Self::Neato => "neato".to_owned(),
                    Self::Twopi => "twopi".to_owned(),
                    Self::Circo => "circo".to_owned(),
                    Self::Fdp => "fdp".to_owned(),
                    Self::Sfdp => "sfdp".to_owned(),
                }
            }
        }

        #[derive(StructOpt, Clone, PartialEq, Debug)]
        pub struct Options {
            #[structopt(flatten)]
            pub general: crate::options::general::Options,

            #[structopt(flatten)]
            pub project: crate::options::project::Options,

            #[structopt(flatten)]
            pub graph: crate::options::graph::Options,

            /// The graph layout algorithm to use
            /// (e.g. dot, neato, twopi, circo, fdp, sfdp).
            #[structopt(long = "layout", default_value = "neato")]
            pub layout: crate::options::generate::graph::LayoutAlgorithm,

            /// Include used modules and types
            #[structopt(long = "with-uses", required_if("with-externs", "true"))]
            pub with_uses: bool,

            /// Include used modules and types from extern crates
            #[structopt(long = "with-externs")]
            pub with_externs: bool,
        }
    }

    pub mod tree {
        use super::*;

        #[derive(StructOpt, Clone, PartialEq, Debug)]
        pub struct Options {
            #[structopt(flatten)]
            pub general: crate::options::general::Options,

            #[structopt(flatten)]
            pub project: crate::options::project::Options,

            #[structopt(flatten)]
            pub graph: crate::options::graph::Options,
        }
    }
}

pub mod project {
    use super::*;

    #[derive(StructOpt, Clone, PartialEq, Debug)]
    #[structopt(group = ArgGroup::with_name("target-group"))]
    pub struct Options {
        /// Process only this package's library.
        #[structopt(long = "lib", group = "target-group")]
        pub lib: bool,

        /// Process only the specified binary.
        #[structopt(long = "bin", group = "target-group")]
        pub bin: Option<String>,

        /// Package to process (see `cargo help pkgid`).
        #[structopt(short = "p", long = "package")]
        pub package: Option<String>,

        /// Do not activate the `default` feature.
        #[structopt(long = "no-default-features")]
        pub no_default_features: bool,

        /// Activate all available features
        #[structopt(long = "all-features")]
        pub all_features: bool,

        /// List of features to activate.
        /// This will be ignored if `--cargo-all-features` is provided.
        #[structopt(long = "features")]
        pub features: Vec<String>,

        /// rustc target
        #[structopt(long = "target")]
        pub target: Option<String>,

        #[structopt(
            long = "manifest-path",
            parse(from_os_str),
            default_value = "./Cargo.toml"
        )]
        pub manifest_path: PathBuf,
    }
}

pub mod general {
    use super::*;

    #[derive(StructOpt, Clone, PartialEq, Debug)]
    #[structopt(group = ArgGroup::with_name("target-group"))]
    pub struct Options {
        /// Enable verbose messages during command execution.
        #[structopt(long = "verbose")]
        pub verbose: bool,
    }
}
<commit_msg>Improved CLI help comments<commit_after>use std::{path::PathBuf, str::FromStr};

use structopt::{clap::ArgGroup, StructOpt};

use crate::commands::Command;

#[derive(StructOpt, Clone, PartialEq, Debug)]
pub struct Options {
    #[structopt(hidden = true, possible_value("modules"))]
    pub dummy: Option<String>,

    #[structopt(subcommand)]
    pub command: Command,
}

pub mod graph {
    use super::*;

    #[derive(StructOpt, Clone, PartialEq, Debug)]
    pub struct Options {
        /// Focus the graph on a particular path's environment.
        #[structopt(long = "focus-on")]
        pub focus_on: Option<String>,

        /// The maximum depth of the generated graph
        /// relative to the node selected by '--focus-on'.
        #[structopt(long = "max-depth")]
        pub max_depth: Option<usize>,

        /// Include types (e.g. structs, enums).
        #[structopt(long = "with-types")]
        pub with_types: bool,

        /// Include tests (e.g. `#[cfg(test)] mod tests { … }`).
        #[structopt(long = "with-tests")]
        pub with_tests: bool,

        /// Include orphaned modules (i.e. unused files in /src).
        #[structopt(long = "with-orphans")]
        pub with_orphans: bool,
    }
}

pub mod generate {
    use super::*;

    pub mod graph {
        use super::*;

        #[derive(Clone, PartialEq, Debug)]
        pub enum LayoutAlgorithm {
            Dot,
            Neato,
            Twopi,
            Circo,
            Fdp,
            Sfdp,
        }

        impl FromStr for LayoutAlgorithm {
            type Err = &'static str;

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                match s {
                    "dot" => Ok(Self::Dot),
                    "neato" => Ok(Self::Neato),
                    "twopi" => Ok(Self::Twopi),
                    "circo" => Ok(Self::Circo),
                    "fdp" => Ok(Self::Fdp),
                    "sfdp" => Ok(Self::Sfdp),
                    _ => Err("Unrecognized layout"),
                }
            }
        }

        impl ToString for LayoutAlgorithm {
            fn to_string(&self) -> String {
                match self {
                    Self::Dot => "dot".to_owned(),
                    Self::Neato => "neato".to_owned(),
                    Self::Twopi => "twopi".to_owned(),
                    Self::Circo => "circo".to_owned(),
                    Self::Fdp => "fdp".to_owned(),
                    Self::Sfdp => "sfdp".to_owned(),
                }
            }
        }

        #[derive(StructOpt, Clone, PartialEq, Debug)]
        pub struct Options {
            #[structopt(flatten)]
            pub general: crate::options::general::Options,

            #[structopt(flatten)]
            pub project: crate::options::project::Options,

            #[structopt(flatten)]
            pub graph: crate::options::graph::Options,

            /// The graph layout algorithm to use
            /// (e.g. dot, neato, twopi, circo, fdp, sfdp).
            #[structopt(long = "layout", default_value = "neato")]
            pub layout: crate::options::generate::graph::LayoutAlgorithm,

            /// Include used modules and types
            #[structopt(long = "with-uses", required_if("with-externs", "true"))]
            pub with_uses: bool,

            /// Include used modules and types from extern crates
            #[structopt(long = "with-externs")]
            pub with_externs: bool,
        }
    }

    pub mod tree {
        use super::*;

        #[derive(StructOpt, Clone, PartialEq, Debug)]
        pub struct Options {
            #[structopt(flatten)]
            pub general: crate::options::general::Options,

            #[structopt(flatten)]
            pub project: crate::options::project::Options,

            #[structopt(flatten)]
            pub graph: crate::options::graph::Options,
        }
    }
}

pub mod project {
    use super::*;

    #[derive(StructOpt, Clone, PartialEq, Debug)]
    #[structopt(group = ArgGroup::with_name("target-group"))]
    pub struct Options {
        /// Process only this package's library.
        #[structopt(long = "lib", group = "target-group")]
        pub lib: bool,

        /// Process only the specified binary.
        #[structopt(long = "bin", group = "target-group")]
        pub bin: Option<String>,

        /// Package to process (see `cargo help pkgid`).
        #[structopt(short = "p", long = "package")]
        pub package: Option<String>,

        /// Do not activate the `default` feature.
        #[structopt(long = "no-default-features")]
        pub no_default_features: bool,

        /// Activate all available features.
        #[structopt(long = "all-features")]
        pub all_features: bool,

        /// List of features to activate.
        /// This will be ignored if `--cargo-all-features` is provided.
        #[structopt(long = "features")]
        pub features: Vec<String>,

        /// Analyze for target triple.
        #[structopt(long = "target")]
        pub target: Option<String>,

        /// Path to Cargo.toml.
        #[structopt(long = "manifest-path", parse(from_os_str), default_value = ".")]
        pub manifest_path: PathBuf,
    }
}

pub mod general {
    use super::*;

    #[derive(StructOpt, Clone, PartialEq, Debug)]
    #[structopt(group = ArgGroup::with_name("target-group"))]
    pub struct Options {
        /// Use verbose output.
        #[structopt(long = "verbose")]
        pub verbose: bool,
    }
}
<|endoftext|>