<commit_before>use consts::*;
use proto::*;

use std::io::{IoResult, MemReader, MemWriter, TcpStream};
use std::io::net::ip::SocketAddr;
use std::io::timer::Timer;
use std::num::FromPrimitive;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicInt, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender, sync_channel};
use std::time::Duration;
use std::thread::Thread;

macro_rules! fetch_result(
    ($res:ident, $enu:ident::$hack:ident($item:ident)) => (
        match $res {
            $enu::$hack(response) => Ok(response.$item),
            Response::Error(e) => Err(e),
            _ => Err(ZkError::SystemError)
        }
    )
);

macro_rules! fetch_empty_result(
    ($res:ident, $enu:ident::$hack:ident) => (
        match $res {
            $enu::$hack => Ok(()),
            Response::Error(e) => Err(e),
            _ => Err(ZkError::SystemError)
        }
    )
);

#[derive(Show)]
enum OpCode {
    Auth = 100,
    Create = 1,
    Delete = 2,
    Exists = 3,
    GetAcl = 6,
    SetAcl = 7,
    GetChildren = 8,
    GetData = 4,
    SetData = 5,
    Ping = 11,
    CloseSession = -11
}

impl Copy for OpCode {}

pub trait Watcher: Send {
    fn handle(&self, &WatchedEvent);
}

pub type ZkResult<T> = Result<T, ZkError>;

struct Packet {
    opcode: OpCode,
    data: Vec<u8>,
    resp_tx: Sender<Response>
}

#[derive(Clone)]
pub struct ZooKeeper {
    xid: Arc<AtomicInt>,
    running: Arc<AtomicBool>,
    packet_tx: Sender<Packet> // sending Packets from methods to writer task
}

impl ZooKeeper {

    pub fn connect<'a, W: Watcher>(connect_string: &'a str, timeout: Duration, watcher: W) -> ZkResult<ZooKeeper> {

        // communicating reader socket from writer to reader task
        let (reader_sock_tx, reader_sock_rx) = sync_channel(0);
        // comminucating requests (as Packets) from instance methods to writer task
        let (packet_tx, packet_rx): (Sender<Packet>, Receiver<Packet>) = channel();
        // communicating sent Packets from writer task to the reader task
        let (written_tx, written_rx) = channel();
        // event channel for passing WatchedEvents to watcher on a seperate task
        let (event_tx, event_rx) = channel();

        let running = Arc::new(AtomicBool::new(true));
        let running1 = running.clone();

        let hosts = connect_string.split(',').map(|host| host.parse::<SocketAddr>().unwrap()).collect();

        Thread::spawn(move || {
            println!("event thread started");

            loop {
                match event_rx.recv() {
                    Ok(event) => watcher.handle(&event),
                    Err(_) => return
                }
            }
        });

        Thread::spawn(move || {
            println!("writer thread started");

            let mut timer = Timer::new().unwrap();
            let ping_timeout = timer.periodic(timeout);
            let mut writer_sock;
            let mut conn_resp = ConnectResponse::initial(timeout);

            loop {
                println!("connecting: trying to get new writer_sock");
                let (new_writer_sock, new_conn_resp) = match running.load(Ordering::SeqCst) {
                    true => ZooKeeper::reconnect(&hosts, conn_resp),
                    false => return
                };
                writer_sock = new_writer_sock;
                conn_resp = new_conn_resp;

                // pass a clone of the writer socket to the reader thread, will be used for reading
                reader_sock_tx.send(writer_sock.clone());

                loop {
                    // do we have something to send or do we need to ping?
                    select! {
                        res = packet_rx.recv() => {
                            let packet = match res {
                                Ok(packet) => packet,
                                Err(_) => return
                            };
                            let res = writer_sock.write_buffer(&packet.data);
                            if res.is_err() {
                                break;
                            }
                            written_tx.send(packet);
                        },
                        _ = ping_timeout.recv() => {
                            println!("Pinging {}", writer_sock.peer_name().unwrap());
                            let ping = RequestHeader{xid: -2, opcode: OpCode::Ping as i32}.to_byte_vec();
                            let res = writer_sock.write_buffer(&ping);
                            if res.is_err() {
                                println!("Failed to ping server");
                                break;
                            }
                        }
                    };
                }
            }
        });

        Thread::spawn(move || {
            println!("reader thread started");

            loop {
                println!("connecting: trying to get new reader_sock");
                let mut reader_sock = match reader_sock_rx.recv() {
                    Ok(sock) => sock,
                    Err(_) => return
                };

                loop {
                    let reply = ZooKeeper::read_reply(&mut reader_sock);
                    if reply.is_err() {
                        println!("ZooKeeper::read_reply {:?}", reply.err());
                        break;
                    }
                    let (reply_header, mut buf) = reply.unwrap();
                    match reply_header.xid {
                        -1 => event_tx.send(WatchedEvent::read_from(&mut buf)).unwrap(),
                        -2 => println!("Got ping event"),
                        _xid => {
                            let packet = written_rx.recv().unwrap();
                            let result = ZooKeeper::parse_reply(reply_header.err, &packet, &mut buf);
                            packet.resp_tx.send(result);
                         }
                    }
                }
            }
        });

        Ok(ZooKeeper{xid: Arc::new(AtomicInt::new(1)), running: running1, packet_tx: packet_tx})
    }

    fn read_reply<R: Reader>(sock: &mut R) -> IoResult<(ReplyHeader, MemReader)> {
        let buf = try!(sock.read_buffer());
        let mut reader = MemReader::new(buf);
        Ok((ReplyHeader::read_from(&mut reader), reader))
    }

    fn parse_reply<R: Reader>(err: i32, packet: &Packet, buf: &mut R) -> Response {
        match err {
            0 => match packet.opcode {
                OpCode::Auth => Response::Auth,
                OpCode::CloseSession => Response::Close,
                OpCode::Create => Response::Create(CreateResponse::read_from(buf)),
                OpCode::Delete => Response::Delete,
                OpCode::Exists => Response::Exists(StatResponse::read_from(buf)),
                OpCode::GetAcl => Response::GetAcl(GetAclResponse::read_from(buf)),
                OpCode::SetAcl => Response::SetAcl(StatResponse::read_from(buf)),
                OpCode::GetChildren => Response::GetChildren(GetChildrenResponse::read_from(buf)),
                OpCode::GetData => Response::GetData(GetDataResponse::read_from(buf)),
                OpCode::SetData => Response::SetData(StatResponse::read_from(buf)),
                ref opcode => panic!("{:?}Response not implemented yet", opcode)
            },
            e => {
                Response::Error(FromPrimitive::from_i32(e).unwrap())
            }
        }
    }

    fn reconnect(hosts: &Vec<SocketAddr>, conn_resp: ConnectResponse) -> (TcpStream, ConnectResponse) {
        let conn_req = ConnectRequest::from(conn_resp, 0).to_byte_vec();

        loop {
            for host in hosts.iter() {
                println!("Connecting to {}...", host);
                let mut sock = TcpStream::connect_timeout(*host, Duration::seconds(1));
                if sock.is_err() {
                    println!("Failed to connect to {}", host);
                    continue;
                }

                let write = sock.write_buffer(&conn_req);
                if write.is_err() {
                    continue;
                }

                let read = sock.read_buffer();
                if read.is_err() {
                    continue;
                }

                let mut buf = MemReader::new(read.unwrap());
                let conn_resp = ConnectResponse::read_from(&mut buf);

                println!("{:?}", conn_resp);

                return (sock.unwrap(), conn_resp)
            }
        }
    }

    fn xid(&self) -> i32 {
        self.xid.fetch_add(1, Ordering::SeqCst) as i32
    }

    #[allow(unused_must_use)]
    fn request<T: Archive>(&self, opcode: OpCode, xid: i32, req: T) -> Response {
        let rh = RequestHeader{xid: xid, opcode: opcode as i32};

        let mut buf = MemWriter::new();
        rh.write_to(&mut buf);
        req.write_to(&mut buf);

        let (resp_tx, resp_rx) = channel();
        let packet = Packet{opcode: opcode, data: buf.into_inner(), resp_tx: resp_tx};

        self.packet_tx.send(packet);

        resp_rx.recv().unwrap()
    }

    pub fn add_auth(&self, scheme: &str, auth: Vec<u8>) -> ZkResult<()> {
        let req = AuthRequest{typ: 0, scheme: scheme.to_string(), auth: auth};

        let result = self.request(OpCode::Auth, -4, req);

        fetch_empty_result!(result, Response::Auth)
    }

    pub fn create(&self, path: &str, data: Vec<u8>, acl: Vec<Acl>, mode: CreateMode) -> ZkResult<String> {
        let req = CreateRequest{path: path.to_string(), data: data, acl: acl, flags: mode as i32};

        let result = self.request(OpCode::Create, self.xid(), req);

        fetch_result!(result, Response::Create(path))
    }

    pub fn delete(&self, path: &str, version: i32) -> ZkResult<()> {
        let req = DeleteRequest{path: path.to_string(), version: version};

        let result = self.request(OpCode::Delete, self.xid(), req);

        fetch_empty_result!(result, Response::Delete)
    }

    pub fn exists(&self, path: &str, watch: bool) -> ZkResult<Stat> {
        let req = ExistsRequest{path: path.to_string(), watch: watch};

        let result = self.request(OpCode::Exists, self.xid(), req);

        fetch_result!(result, Response::Exists(stat))
    }

    pub fn get_acl(&self, path: &str) -> ZkResult<(Vec<Acl>, Stat)> {
        let req = GetAclRequest{path: path.to_string()};

        let result = self.request(OpCode::GetAcl, self.xid(), req);

        fetch_result!(result, Response::GetAcl(acl_stat))
    }

    pub fn get_children(&self, path: &str, watch: bool) -> ZkResult<Vec<String>> {
        let req = GetChildrenRequest{path: path.to_string(), watch: watch};

        let result = self.request(OpCode::GetChildren, self.xid(), req);

        fetch_result!(result, Response::GetChildren(children))
    }

    pub fn get_data(&self, path: &str, watch: bool) -> ZkResult<(Vec<u8>, Stat)> {
        let req = GetDataRequest{path: path.to_string(), watch: watch};

        let result = self.request(OpCode::GetData, self.xid(), req);

        fetch_result!(result, Response::GetData(data_stat))
    }

    pub fn set_acl(&self, path: &str, acl: Vec<Acl>, version: i32) -> ZkResult<Stat> {
        let req = SetAclRequest{path: path.to_string(), acl: acl, version: version};

        let result = self.request(OpCode::SetAcl, self.xid(), req);

        fetch_result!(result, Response::SetAcl(stat))
    }

    pub fn set_data(&self, path: &str, data: Vec<u8>, version: i32) -> ZkResult<Stat> {
        let req = SetDataRequest{path: path.to_string(), data: data, version: version};

        let result = self.request(OpCode::SetData, self.xid(), req);

        fetch_result!(result, Response::SetData(stat))
    }

    #[allow(unused_must_use)]
    pub fn close(&self) {
        self.request(OpCode::CloseSession, 0, EmptyRequest);

        self.running.store(false, Ordering::SeqCst);
    }
}
<commit_msg>better error messages around result handling, closing client properly<commit_after>use consts::*;
use proto::*;

use std::io::{IoResult, MemReader, MemWriter, TcpStream};
use std::io::net::ip::SocketAddr;
use std::io::timer::Timer;
use std::num::FromPrimitive;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicInt, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender, sync_channel};
use std::time::Duration;
use std::thread::Thread;

macro_rules! fetch_result(
    ($res:ident, $enu:ident::$hack:ident($item:ident)) => (
        match $res {
            $enu::$hack(response) => Ok(response.$item),
            Response::Error(e) => Err(e),
            _ => Err(ZkError::SystemError)
        }
    )
);

macro_rules! fetch_empty_result(
    ($res:ident, $enu:ident::$hack:ident) => (
        match $res {
            $enu::$hack => Ok(()),
            Response::Error(e) => Err(e),
            _ => Err(ZkError::SystemError)
        }
    )
);

#[derive(Show)]
enum OpCode {
    Auth = 100,
    Create = 1,
    Delete = 2,
    Exists = 3,
    GetAcl = 6,
    SetAcl = 7,
    GetChildren = 8,
    GetData = 4,
    SetData = 5,
    Ping = 11,
    CloseSession = -11
}

impl Copy for OpCode {}

pub trait Watcher: Send {
    fn handle(&self, &WatchedEvent);
}

pub type ZkResult<T> = Result<T, ZkError>;

struct Packet {
    opcode: OpCode,
    data: Vec<u8>,
    resp_tx: Sender<Response>
}

#[derive(Clone)]
pub struct ZooKeeper {
    xid: Arc<AtomicInt>,
    running: Arc<AtomicBool>,
    packet_tx: Sender<Packet> // sending Packets from methods to writer task
}

impl ZooKeeper {

    pub fn connect<'a, W: Watcher>(connect_string: &'a str, timeout: Duration, watcher: W) -> ZkResult<ZooKeeper> {

        // communicating reader socket from writer to reader task
        let (reader_sock_tx, reader_sock_rx) = sync_channel(0);
        // comminucating requests (as Packets) from instance methods to writer task
        let (packet_tx, packet_rx): (Sender<Packet>, Receiver<Packet>) = channel();
        // communicating sent Packets from writer task to the reader task
        let (written_tx, written_rx) = channel();
        // event channel for passing WatchedEvents to watcher on a seperate task
        let (event_tx, event_rx) = channel();

        let running = Arc::new(AtomicBool::new(true));
        let running1 = running.clone();

        let hosts = connect_string.split(',').map(|host| host.parse::<SocketAddr>().unwrap()).collect();

        Thread::spawn(move || {
            println!("Event: thread started");

            loop {
                match event_rx.recv() {
                    Ok(event) => watcher.handle(&event),
                    Err(_) => return
                }
            }
        });

        Thread::spawn(move || {
            println!("Writer: thread started");

            let mut timer = Timer::new().unwrap();
            let ping_timeout = timer.periodic(timeout);
            let mut writer_sock;
            let mut conn_resp = ConnectResponse::initial(timeout);

            loop {
                println!("Writer: connecting, trying to get new writer_sock");
                let (new_writer_sock, new_conn_resp) = match running.load(Ordering::SeqCst) {
                    true => ZooKeeper::reconnect(&hosts, conn_resp),
                    false => {
                        println!("Writer: exiting");
                        return
                    }
                };
                writer_sock = new_writer_sock;
                conn_resp = new_conn_resp;

                // pass a clone of the writer socket to the reader thread, will be used for reading
                match reader_sock_tx.send(writer_sock.clone()) {
                    Err(_) => panic!("Writer: failed to pass new socket to reader thread"),
                    _ => ()
                }

                loop {
                    // do we have something to send or do we need to ping?
                    select! {
                        res = packet_rx.recv() => {
                            let packet = match res {
                                Ok(packet) => packet,
                                Err(_) => return
                            };
                            let res = writer_sock.write_buffer(&packet.data);
                            if res.is_err() {
                                println!("Writer: failed to send to server, trying to reconnect");
                                break;
                            }
                            let opcode = packet.opcode;
                            match written_tx.send(packet) {
                                Err(_) => panic!("Writer: failed to communicate with reader thread"),
                                _ => ()
                            }
                            match opcode {
                                OpCode::CloseSession => {
                                    println!("Writer: exiting");
                                    return
                                },
                                _ => ()
                            }
                        },
                        _ = ping_timeout.recv() => {
                            println!("Writer: Pinging {}", writer_sock.peer_name().unwrap());
                            let ping = RequestHeader{xid: -2, opcode: OpCode::Ping as i32}.to_byte_vec();
                            let res = writer_sock.write_buffer(&ping);
                            if res.is_err() {
                                println!("Writer: failed to ping server, trying to reconnect");
                                break;
                            }
                        }
                    };
                }
            }
        });

        Thread::spawn(move || {
            println!("Reader thread started");

            loop {
                println!("Reader: connecting, trying to get new reader_sock");
                let mut reader_sock = match reader_sock_rx.recv() {
                    Ok(sock) => sock,
                    Err(_) => {
                        println!("Reader: writer thread died, exiting");
                        return
                    }
                };

                loop {
                    let reply = ZooKeeper::read_reply(&mut reader_sock);
                    if reply.is_err() {
                        println!("Reader: read_reply {:?}", reply.err());
                        break;
                    }
                    let (reply_header, mut buf) = reply.unwrap();
                    match reply_header.xid {
                        -1 => event_tx.send(WatchedEvent::read_from(&mut buf)).unwrap(),
                        -2 => println!("Reader: got ping event"),
                        _xid => {
                            let packet = written_rx.recv().unwrap();
                            let result = ZooKeeper::parse_reply(reply_header.err, &packet, &mut buf);

                            match packet.resp_tx.send(result) {
                                Err(_) => println!("Reader: failed to pass back result to client thread"),
                                _ => ()
                            }
                         }
                    }
                }
            }
        });

        Ok(ZooKeeper{xid: Arc::new(AtomicInt::new(1)), running: running1, packet_tx: packet_tx})
    }

    fn read_reply<R: Reader>(sock: &mut R) -> IoResult<(ReplyHeader, MemReader)> {
        let buf = try!(sock.read_buffer());
        let mut reader = MemReader::new(buf);
        Ok((ReplyHeader::read_from(&mut reader), reader))
    }

    fn parse_reply<R: Reader>(err: i32, packet: &Packet, buf: &mut R) -> Response {
        match err {
            0 => match packet.opcode {
                OpCode::Auth => Response::Auth,
                OpCode::CloseSession => Response::Close,
                OpCode::Create => Response::Create(CreateResponse::read_from(buf)),
                OpCode::Delete => Response::Delete,
                OpCode::Exists => Response::Exists(StatResponse::read_from(buf)),
                OpCode::GetAcl => Response::GetAcl(GetAclResponse::read_from(buf)),
                OpCode::SetAcl => Response::SetAcl(StatResponse::read_from(buf)),
                OpCode::GetChildren => Response::GetChildren(GetChildrenResponse::read_from(buf)),
                OpCode::GetData => Response::GetData(GetDataResponse::read_from(buf)),
                OpCode::SetData => Response::SetData(StatResponse::read_from(buf)),
                ref opcode => panic!("{:?}Response not implemented yet", opcode)
            },
            e => {
                Response::Error(FromPrimitive::from_i32(e).unwrap())
            }
        }
    }

    fn reconnect(hosts: &Vec<SocketAddr>, conn_resp: ConnectResponse) -> (TcpStream, ConnectResponse) {
        let conn_req = ConnectRequest::from(conn_resp, 0).to_byte_vec();

        loop {
            for host in hosts.iter() {
                println!("Writer: Connecting to {}...", host);
                let mut sock = TcpStream::connect_timeout(*host, Duration::seconds(1));
                if sock.is_err() {
                    println!("Writer: Failed to connect to {}", host);
                    continue;
                }

                let write = sock.write_buffer(&conn_req);
                if write.is_err() {
                    continue;
                }

                let read = sock.read_buffer();
                if read.is_err() {
                    continue;
                }

                let mut buf = MemReader::new(read.unwrap());
                let conn_resp = ConnectResponse::read_from(&mut buf);

                println!("Writer: Connection: {:?}", conn_resp);

                return (sock.unwrap(), conn_resp)
            }
        }
    }

    fn xid(&self) -> i32 {
        self.xid.fetch_add(1, Ordering::SeqCst) as i32
    }

    #[allow(unused_must_use)]
    fn request<T: Archive>(&self, opcode: OpCode, xid: i32, req: T) -> Response {
        let rh = RequestHeader{xid: xid, opcode: opcode as i32};

        let mut buf = MemWriter::new();
        rh.write_to(&mut buf);
        req.write_to(&mut buf);

        let (resp_tx, resp_rx) = channel();
        let packet = Packet{opcode: opcode, data: buf.into_inner(), resp_tx: resp_tx};

        self.packet_tx.send(packet); // TODO check if this fails

        resp_rx.recv().unwrap() // TODO check if this fails
    }

    pub fn add_auth(&self, scheme: &str, auth: Vec<u8>) -> ZkResult<()> {
        let req = AuthRequest{typ: 0, scheme: scheme.to_string(), auth: auth};

        let result = self.request(OpCode::Auth, -4, req);

        fetch_empty_result!(result, Response::Auth)
    }

    pub fn create(&self, path: &str, data: Vec<u8>, acl: Vec<Acl>, mode: CreateMode) -> ZkResult<String> {
        let req = CreateRequest{path: path.to_string(), data: data, acl: acl, flags: mode as i32};

        let result = self.request(OpCode::Create, self.xid(), req);

        fetch_result!(result, Response::Create(path))
    }

    pub fn delete(&self, path: &str, version: i32) -> ZkResult<()> {
        let req = DeleteRequest{path: path.to_string(), version: version};

        let result = self.request(OpCode::Delete, self.xid(), req);

        fetch_empty_result!(result, Response::Delete)
    }

    pub fn exists(&self, path: &str, watch: bool) -> ZkResult<Stat> {
        let req = ExistsRequest{path: path.to_string(), watch: watch};

        let result = self.request(OpCode::Exists, self.xid(), req);

        fetch_result!(result, Response::Exists(stat))
    }

    pub fn get_acl(&self, path: &str) -> ZkResult<(Vec<Acl>, Stat)> {
        let req = GetAclRequest{path: path.to_string()};

        let result = self.request(OpCode::GetAcl, self.xid(), req);

        fetch_result!(result, Response::GetAcl(acl_stat))
    }

    pub fn get_children(&self, path: &str, watch: bool) -> ZkResult<Vec<String>> {
        let req = GetChildrenRequest{path: path.to_string(), watch: watch};

        let result = self.request(OpCode::GetChildren, self.xid(), req);

        fetch_result!(result, Response::GetChildren(children))
    }

    pub fn get_data(&self, path: &str, watch: bool) -> ZkResult<(Vec<u8>, Stat)> {
        let req = GetDataRequest{path: path.to_string(), watch: watch};

        let result = self.request(OpCode::GetData, self.xid(), req);

        fetch_result!(result, Response::GetData(data_stat))
    }

    pub fn set_acl(&self, path: &str, acl: Vec<Acl>, version: i32) -> ZkResult<Stat> {
        let req = SetAclRequest{path: path.to_string(), acl: acl, version: version};

        let result = self.request(OpCode::SetAcl, self.xid(), req);

        fetch_result!(result, Response::SetAcl(stat))
    }

    pub fn set_data(&self, path: &str, data: Vec<u8>, version: i32) -> ZkResult<Stat> {
        let req = SetDataRequest{path: path.to_string(), data: data, version: version};

        let result = self.request(OpCode::SetData, self.xid(), req);

        fetch_result!(result, Response::SetData(stat))
    }

    pub fn close(&self) {
        self.request(OpCode::CloseSession, 0, EmptyRequest);

        self.running.store(false, Ordering::SeqCst);
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::{env, fs};

fn main() {
    if let Some(git_sha) = read_git_sha() {
        println!("cargo:rustc-env={}={}", "BUILD_SHA", git_sha);
    }

    println!(
        "cargo:rustc-env=BUILD_TARGET={}",
        std::env::var("TARGET").unwrap()
    );
}

fn read_git_sha() -> Option<String> {
    let mut repo_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());

    let mut git_path;
    loop {
        git_path = repo_path.join(".git");
        if git_path.exists() {
            break;
        } else if !repo_path.pop() {
            return None;
        }
    }

    let git_head_path = git_path.join("HEAD");
    if let Some(path) = git_head_path.to_str() {
        println!("cargo:rerun-if-changed={}", path);
    }
    if let Ok(mut head_content) = fs::read_to_string(&git_head_path) {
        if head_content.ends_with("\n") {
            head_content.pop();
        }

        // If we're on a branch, read the SHA from the ref file.
        if head_content.starts_with("ref: ") {
            head_content.replace_range(0.."ref: ".len(), "");
            let ref_filename = git_path.join(&head_content);
            if let Some(path) = ref_filename.to_str() {
                println!("cargo:rerun-if-changed={}", path);
            }
            return fs::read_to_string(&ref_filename).ok();
        }

        // If we're on a detached commit, then the `HEAD` file itself contains the sha.
        else if head_content.len() == 40 {
            return Some(head_content);
        }
    }

    None
}
<commit_msg>tree-sitter-cli: build: add support for git submodules (#422)<commit_after>use std::path::PathBuf;
use std::{env, fs};

fn main() {
    if let Some(git_sha) = read_git_sha() {
        println!("cargo:rustc-env={}={}", "BUILD_SHA", git_sha);
    }

    println!(
        "cargo:rustc-env=BUILD_TARGET={}",
        std::env::var("TARGET").unwrap()
    );
}

fn read_git_sha() -> Option<String> {
    let mut repo_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());

    let mut git_path;
    loop {
        git_path = repo_path.join(".git");
        if git_path.exists() {
            break;
        } else if !repo_path.pop() {
            return None;
        }
    }

    let git_dir_path;
    if git_path.is_dir() {
        git_dir_path = git_path;
    } else if let Ok(git_path_content) = fs::read_to_string(&git_path) {
        git_dir_path = repo_path.join(git_path_content.get("gitdir: ".len()..).unwrap().trim_end());
    } else {
        return None;
    }
    let git_head_path = git_dir_path.join("HEAD");
    if let Some(path) = git_head_path.to_str() {
        println!("cargo:rerun-if-changed={}", path);
    }
    if let Ok(mut head_content) = fs::read_to_string(&git_head_path) {
        if head_content.ends_with("\n") {
            head_content.pop();
        }

        // If we're on a branch, read the SHA from the ref file.
        if head_content.starts_with("ref: ") {
            head_content.replace_range(0.."ref: ".len(), "");
            let ref_filename = git_dir_path.join(&head_content);
            if let Some(path) = ref_filename.to_str() {
                println!("cargo:rerun-if-changed={}", path);
            }
            return fs::read_to_string(&ref_filename).ok();
        }

        // If we're on a detached commit, then the `HEAD` file itself contains the sha.
        else if head_content.len() == 40 {
            return Some(head_content);
        }
    }

    None
}
<|endoftext|>


<commit_before>use {Matrix2d, Field, Value, Borrowed};
use vecmath::{multiply, translate, rotate_radians, scale, shear, identity};
use {Transform2d};
use {PolygonColorContext};
use {AddColor, View};

/// A polygon context.
pub struct PolygonContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current polygon.
    pub polygon: Field<'a, &'a [f64]>
}

impl<'a> Transform2d<'a> for PolygonContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn trans_local(&'a self, x: f64, y: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(self.transform.get(), &trans))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn rot_rad_local(&'a self, angle: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(self.transform.get(), &rot))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn scale_local(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(self.transform.get(), &scale))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn shear_local(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(self.transform.get(), &shear))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

impl<'a> AddColor<'a, PolygonColorContext<'a>> for PolygonContext<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> PolygonColorContext<'a> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value([r, g, b, a]),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

impl<'a> View<'a> for PolygonContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

<commit_msg>Sorted use alphabetically<commit_after>use {
    AddColor,
    Borrowed,
    Field,
    Matrix2d,
    PolygonColorContext,
    Transform2d,
    Value,
    View
};
use vecmath::{
    identity,
    multiply,
    rotate_radians,
    scale,
    shear,
    translate,
};

/// A polygon context.
pub struct PolygonContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current polygon.
    pub polygon: Field<'a, &'a [f64]>
}

impl<'a> Transform2d<'a> for PolygonContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn trans_local(&'a self, x: f64, y: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(self.transform.get(), &trans))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn rot_rad_local(&'a self, angle: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(self.transform.get(), &rot))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn scale_local(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(self.transform.get(), &scale))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn shear_local(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(self.transform.get(), &shear))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

impl<'a> AddColor<'a, PolygonColorContext<'a>> for PolygonContext<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> PolygonColorContext<'a> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value([r, g, b, a]),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

impl<'a> View<'a> for PolygonContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

<|endoftext|>


<commit_before>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use Result;

use client::Api;
use firmware::installation_set;
use states::{
    Idle, Install, ProgressReporter, State, StateChangeImpl, StateMachine, TransitionCallback,
};
use std::fs;
use update_package::{ObjectStatus, UpdatePackage};
use walkdir::WalkDir;

#[derive(Debug, PartialEq)]
pub(super) struct Download {
    pub(super) update_package: UpdatePackage,
}

create_state_step!(Download => Idle);
create_state_step!(Download => Install(update_package));

impl TransitionCallback for State<Download> {
    fn callback_state_name(&self) -> &'static str {
        "download"
    }
}

impl ProgressReporter for State<Download> {
    fn package_uid(&self) -> String {
        self.state.update_package.package_uid()
    }

    fn report_enter_state_name(&self) -> &'static str {
        "downloading"
    }

    fn report_leave_state_name(&self) -> &'static str {
        "downloaded"
    }
}

impl StateChangeImpl for State<Download> {
    fn handle(self) -> Result<StateMachine> {
        let installation_set = installation_set::inactive()?;

        // Prune left over from previous installations
        for entry in WalkDir::new(&self.settings.update.download_dir)
            .follow_links(true)
            .min_depth(1)
            .into_iter()
            .filter_entry(|e| e.file_type().is_file())
            .filter_map(|e| e.ok())
            .filter(|e| {
                !self
                    .state
                    .update_package
                    .objects(installation_set)
                    .iter()
                    .map(|o| o.sha256sum())
                    .any(|x| x == e.file_name())
            }) {
            fs::remove_file(entry.path())?;
        }

        // Prune corrupted files
        for object in self.state.update_package.filter_objects(
            &self.settings,
            installation_set,
            &ObjectStatus::Corrupted,
        ) {
            fs::remove_file(&self.settings.update.download_dir.join(object.sha256sum()))?;
        }

        // Download the missing or incomplete objects
        for object in self
            .state
            .update_package
            .filter_objects(&self.settings, installation_set, &ObjectStatus::Missing)
            .into_iter()
            .chain(self.state.update_package.filter_objects(
                &self.settings,
                installation_set,
                &ObjectStatus::Incomplete,
            )) {
            Api::new(&self.settings.network.server_address).download_object(
                &self.firmware.product_uid,
                &self.state.update_package.package_uid(),
                &self.settings.update.download_dir,
                object.sha256sum(),
            )?;
        }

        if self
            .state
            .update_package
            .objects(installation_set)
            .iter()
            .all(|o| o.status(&self.settings.update.download_dir).ok() == Some(ObjectStatus::Ready))
        {
            Ok(StateMachine::Install(self.into()))
        } else {
            bail!("Not all objects are ready for use")
        }
    }
}

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

    fn fake_download_state() -> State<Download> {
        use firmware::{
            tests::{create_fake_installation_set, create_fake_metadata, FakeDevice},
            Metadata,
        };
        use runtime_settings::RuntimeSettings;
        use std::{env, fs::create_dir_all};
        use update_package::tests::{create_fake_settings, get_update_package};

        let settings = create_fake_settings();
        let tmpdir = settings.update.download_dir.clone();
        let _ = create_dir_all(&tmpdir);
        create_fake_installation_set(&tmpdir, 0);
        env::set_var("PATH", format!("{}", &tmpdir.to_string_lossy()));

        State {
            settings,
            runtime_settings: RuntimeSettings::default(),
            firmware: Metadata::new(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap(),
            state: Download {
                update_package: get_update_package(),
            },
        }
    }

    #[test]
    fn skip_download_if_ready() {
        use update_package::tests::create_fake_object;

        let download_state = fake_download_state();
        let tmpdir = download_state.settings.update.download_dir.clone();

        create_fake_object(&download_state.settings);

        let machine = StateMachine::Download(download_state).move_to_next_state();
        assert_state!(machine, Install);

        assert_eq!(
            WalkDir::new(&tmpdir)
                .follow_links(true)
                .min_depth(1)
                .into_iter()
                .filter_entry(|e| e.file_type().is_file())
                .count(),
            1,
            "Number of objects is wrong"
        );
    }

    #[test]
    fn download_objects() {
        use crypto_hash::{hex_digest, Algorithm};
        use mockito::mock;
        use std::{fs::File, io::Read};

        let sha256sum = "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646";
        let download_state = fake_download_state();
        let tmpdir = download_state.settings.update.download_dir.clone();

        // leftover file to ensure it is removed
        let _ = File::create(&tmpdir.join("leftover-file"));

        let mock = mock(
            "GET",
            format!(
                "/products/{}/packages/{}/objects/{}",
                "229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
                &download_state.state.update_package.package_uid(),
                &sha256sum
            )
            .as_str(),
        )
        .match_header("Content-Type", "application/json")
        .match_header("Api-Content-Type", "application/vnd.updatehub-v1+json")
        .with_status(200)
        .with_body("1234567890")
        .create();

        let machine = StateMachine::Download(download_state).move_to_next_state();
        assert_state!(machine, Install);

        mock.assert();

        assert_eq!(
            WalkDir::new(&tmpdir)
                .follow_links(true)
                .min_depth(1)
                .into_iter()
                .filter_entry(|e| e.file_type().is_file())
                .count(),
            1,
            "Failed to remove the corrupted object"
        );

        let mut object_content = String::new();
        let _ = File::open(&tmpdir.join(&sha256sum))
            .expect("Fail to open the temporary directory.")
            .read_to_string(&mut object_content);

        assert_eq!(
            &hex_digest(Algorithm::SHA256, object_content.as_bytes()),
            &sha256sum,
            "Checksum mismatch"
        );
    }

    #[test]
    fn download_has_transition_callback_trait() {
        let download_state = fake_download_state();
        assert_eq!(download_state.callback_state_name(), "download");
    }
}
<commit_msg>rustfmt: Apply format changes<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use Result;

use client::Api;
use firmware::installation_set;
use states::{
    Idle, Install, ProgressReporter, State, StateChangeImpl, StateMachine, TransitionCallback,
};
use std::fs;
use update_package::{ObjectStatus, UpdatePackage};
use walkdir::WalkDir;

#[derive(Debug, PartialEq)]
pub(super) struct Download {
    pub(super) update_package: UpdatePackage,
}

create_state_step!(Download => Idle);
create_state_step!(Download => Install(update_package));

impl TransitionCallback for State<Download> {
    fn callback_state_name(&self) -> &'static str {
        "download"
    }
}

impl ProgressReporter for State<Download> {
    fn package_uid(&self) -> String {
        self.state.update_package.package_uid()
    }

    fn report_enter_state_name(&self) -> &'static str {
        "downloading"
    }

    fn report_leave_state_name(&self) -> &'static str {
        "downloaded"
    }
}

impl StateChangeImpl for State<Download> {
    fn handle(self) -> Result<StateMachine> {
        let installation_set = installation_set::inactive()?;

        // Prune left over from previous installations
        for entry in WalkDir::new(&self.settings.update.download_dir)
            .follow_links(true)
            .min_depth(1)
            .into_iter()
            .filter_entry(|e| e.file_type().is_file())
            .filter_map(|e| e.ok())
            .filter(|e| {
                !self
                    .state
                    .update_package
                    .objects(installation_set)
                    .iter()
                    .map(|o| o.sha256sum())
                    .any(|x| x == e.file_name())
            })
        {
            fs::remove_file(entry.path())?;
        }

        // Prune corrupted files
        for object in self.state.update_package.filter_objects(
            &self.settings,
            installation_set,
            &ObjectStatus::Corrupted,
        ) {
            fs::remove_file(&self.settings.update.download_dir.join(object.sha256sum()))?;
        }

        // Download the missing or incomplete objects
        for object in self
            .state
            .update_package
            .filter_objects(&self.settings, installation_set, &ObjectStatus::Missing)
            .into_iter()
            .chain(self.state.update_package.filter_objects(
                &self.settings,
                installation_set,
                &ObjectStatus::Incomplete,
            ))
        {
            Api::new(&self.settings.network.server_address).download_object(
                &self.firmware.product_uid,
                &self.state.update_package.package_uid(),
                &self.settings.update.download_dir,
                object.sha256sum(),
            )?;
        }

        if self
            .state
            .update_package
            .objects(installation_set)
            .iter()
            .all(|o| o.status(&self.settings.update.download_dir).ok() == Some(ObjectStatus::Ready))
        {
            Ok(StateMachine::Install(self.into()))
        } else {
            bail!("Not all objects are ready for use")
        }
    }
}

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

    fn fake_download_state() -> State<Download> {
        use firmware::{
            tests::{create_fake_installation_set, create_fake_metadata, FakeDevice},
            Metadata,
        };
        use runtime_settings::RuntimeSettings;
        use std::{env, fs::create_dir_all};
        use update_package::tests::{create_fake_settings, get_update_package};

        let settings = create_fake_settings();
        let tmpdir = settings.update.download_dir.clone();
        let _ = create_dir_all(&tmpdir);
        create_fake_installation_set(&tmpdir, 0);
        env::set_var("PATH", format!("{}", &tmpdir.to_string_lossy()));

        State {
            settings,
            runtime_settings: RuntimeSettings::default(),
            firmware: Metadata::new(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap(),
            state: Download {
                update_package: get_update_package(),
            },
        }
    }

    #[test]
    fn skip_download_if_ready() {
        use update_package::tests::create_fake_object;

        let download_state = fake_download_state();
        let tmpdir = download_state.settings.update.download_dir.clone();

        create_fake_object(&download_state.settings);

        let machine = StateMachine::Download(download_state).move_to_next_state();
        assert_state!(machine, Install);

        assert_eq!(
            WalkDir::new(&tmpdir)
                .follow_links(true)
                .min_depth(1)
                .into_iter()
                .filter_entry(|e| e.file_type().is_file())
                .count(),
            1,
            "Number of objects is wrong"
        );
    }

    #[test]
    fn download_objects() {
        use crypto_hash::{hex_digest, Algorithm};
        use mockito::mock;
        use std::{fs::File, io::Read};

        let sha256sum = "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646";
        let download_state = fake_download_state();
        let tmpdir = download_state.settings.update.download_dir.clone();

        // leftover file to ensure it is removed
        let _ = File::create(&tmpdir.join("leftover-file"));

        let mock = mock(
            "GET",
            format!(
                "/products/{}/packages/{}/objects/{}",
                "229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
                &download_state.state.update_package.package_uid(),
                &sha256sum
            )
            .as_str(),
        )
        .match_header("Content-Type", "application/json")
        .match_header("Api-Content-Type", "application/vnd.updatehub-v1+json")
        .with_status(200)
        .with_body("1234567890")
        .create();

        let machine = StateMachine::Download(download_state).move_to_next_state();
        assert_state!(machine, Install);

        mock.assert();

        assert_eq!(
            WalkDir::new(&tmpdir)
                .follow_links(true)
                .min_depth(1)
                .into_iter()
                .filter_entry(|e| e.file_type().is_file())
                .count(),
            1,
            "Failed to remove the corrupted object"
        );

        let mut object_content = String::new();
        let _ = File::open(&tmpdir.join(&sha256sum))
            .expect("Fail to open the temporary directory.")
            .read_to_string(&mut object_content);

        assert_eq!(
            &hex_digest(Algorithm::SHA256, object_content.as_bytes()),
            &sha256sum,
            "Checksum mismatch"
        );
    }

    #[test]
    fn download_has_transition_callback_trait() {
        let download_state = fake_download_state();
        assert_eq!(download_state.callback_state_name(), "download");
    }
}
<|endoftext|>


<commit_before>///! Defines the `Nameable` trait, for objects with names.
use super::Symbol;
use std::fmt;

/// Trait for use with objects named by symbols
pub trait Nameable {
    fn name(&self) -> Symbol;
}

impl<'t> fmt::Display for Nameable + 't {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name())
    }
}

#[macro_export]
macro_rules! default_nameable_impl {
    ($target:ty) => (
        impl symbol::Nameable for $target {
            fn name(&self) -> Symbol {
                self.name
            }
        });

    ($target:ty, $($mbr:ident).+) => (
        impl symbol::Nameable for $target {
            fn name(&self) -> Symbol {
                self.$($mbr).+
            }
        });
}

<commit_msg>nameable: fix module-level doc-comment<commit_after>//! Defines the `Nameable` trait, for objects with names.
use super::Symbol;
use std::fmt;

/// Trait for use with objects named by symbols
pub trait Nameable {
    fn name(&self) -> Symbol;
}

impl<'t> fmt::Display for Nameable + 't {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.name())
    }
}

#[macro_export]
macro_rules! default_nameable_impl {
    ($target:ty) => (
        impl symbol::Nameable for $target {
            fn name(&self) -> Symbol {
                self.name
            }
        });

    ($target:ty, $($mbr:ident).+) => (
        impl symbol::Nameable for $target {
            fn name(&self) -> Symbol {
                self.$($mbr).+
            }
        });
}

<|endoftext|>


<commit_before>use terrain::gfx_macros::TileMapData;
use data::{load_map_file, get_map_tile};
use game::constants::{MAP_FILE_PATH, TILEMAP_BUF_LENGTH, TILES_PCS_W, TILES_PCS_H};

#[derive(Debug)]
pub struct Terrain {
  pub tiles: Vec<TileMapData>
}

fn calc_index(xpos: usize, ypos: usize) -> usize {
  (ypos * TILES_PCS_W) + xpos
}

fn populate_tilemap(mut tiles: Vec<TileMapData>) -> Vec<TileMapData> {
  let map = load_map_file(MAP_FILE_PATH);
  for ypos in 0..TILES_PCS_H {
    for xpos in 0..TILES_PCS_W {
      let map_val = get_map_tile(&map, 0, xpos as usize, ypos as usize);
      let tex_x = map_val % 32;
      let y = (map_val - tex_x) / 32;
      let idx = calc_index(xpos, ypos);
      let x = if tex_x < 1 { 1 } else { tex_x - 1 };
      tiles[idx] = TileMapData::new([x as f32, y as f32, 0.0, 0.0]);
    }
  }
  tiles
}

pub fn generate() -> Terrain {
  let mut charmap_data = Vec::with_capacity(TILEMAP_BUF_LENGTH);

  for _ in 0..TILEMAP_BUF_LENGTH {
    charmap_data.push(TileMapData::new_empty());
  }

  Terrain {
    tiles: populate_tilemap(charmap_data)
  }
}
<commit_msg>Refactor populate_tilemap function<commit_after>use terrain::gfx_macros::TileMapData;
use data::{load_map_file, get_map_tile};
use game::constants::{MAP_FILE_PATH, TILEMAP_BUF_LENGTH, TILES_PCS_W, TILES_PCS_H};

#[derive(Debug)]
pub struct Terrain {
  pub tiles: Vec<TileMapData>
}

fn calc_index(xpos: usize, ypos: usize) -> usize {
  (ypos * TILES_PCS_W) + xpos
}

fn populate_tilemap(mut tiles: Vec<TileMapData>) -> Vec<TileMapData> {
  let map = load_map_file(MAP_FILE_PATH);
  for ypos in 0..TILES_PCS_H {
    for xpos in 0..TILES_PCS_W {
      let map_val = get_map_tile(&map, 0, xpos, ypos);
      let tex_x = map_val % 32;
      let y = (map_val - tex_x) / 32;
      let x = if tex_x < 1 { 1 } else { tex_x - 1 };
      let idx = calc_index(xpos, ypos);
      tiles[idx] = TileMapData::new([x as f32, y as f32, 0.0, 0.0]);
    }
  }
  tiles
}

pub fn generate() -> Terrain {
  let mut charmap_data = Vec::with_capacity(TILEMAP_BUF_LENGTH);

  for _ in 0..TILEMAP_BUF_LENGTH {
    charmap_data.push(TileMapData::new_empty());
  }

  Terrain {
    tiles: populate_tilemap(charmap_data)
  }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular patterns
//!
//! This provides a data structure, `Pattern<Symbol>` representing a matching pattern in a regular language. This is a
//! more generalised form of a regular expression as it supports symbol types other than simple strings. A pattern using
//! the `char` symbol has identical expressive power to a regular expression.
//!
//! Regular patterns can be created from strings, arrays or vectors using `into_pattern`, and can use any cloneable type
//! to represent a symbol:
//!
//! ```
//! # use ndfa::*;
//! let match_abc = "abc".into_pattern();
//! let match_123 = [1,2,3].into_pattern();
//! ```
//!
//! These patterns are quite boring (they just match exactly the string that's passed in). To create more interesting
//! patterns, there are a series of functions that will create patterns with repetitions or other constructs in them:
//!
//! ```
//! # use ndfa::*;
//! let stuff_or_nonsense = "stuff".or("nonsense");
//! let any_amount_of_stuff = "stuff".repeat_forever(1);
//! let went_to_market = "piggies".repeat(0..5);
//! ```
//!
//! For convenience, these methods will work on any type that can be converted into a pattern. Every regular expression
//! can be converted into a regular pattern, but these patterns are also for symbol types other than characters, and do
//! not require any quoting in order to be used (and are hence much easier to use with dynamic values).
//!
//! ```
//! # use ndfa::*;
//! let some_counting = vec![1, 2, 3].repeat_forever(1);
//! ```
//!

use std::iter::FromIterator;
use std::ops::Range;

use super::state_machine::*;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Pattern<Symbol: Clone> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

impl<Symbol: Clone> Pattern<Symbol> {
    ///
    /// Compiles this pattern onto a state machine, returning the accepting symbol
    ///
    pub fn compile<OutputSymbol>(&self, state_machine: &mut MutableStateMachine<Symbol, OutputSymbol>, start_state: StateId) -> StateId {
        match self {
            &Epsilon => {
                start_state
            },

            &Match(ref symbols) => {
                // Match each symbol in turn
                let mut current_state = start_state;

                for sym in symbols {
                    let next_state = state_machine.count_states();
                    state_machine.add_transition(current_state, sym.clone(), next_state);
                    current_state = next_state;
                }

                current_state
            },

            &RepeatInfinite(ref count, ref pattern) => {
                start_state
            },

            &Repeat(ref range, ref pattern) => {
                start_state
            },

            &MatchAll(ref patterns) => {
                // Match each pattern in turn
                let mut current_state = start_state;

                for pattern in patterns {
                    let next_state = self.compile(state_machine, current_state);
                    current_state = next_state;
                }

                current_state
            },

            &MatchAny(ref patterns) => {
                // Everything is compiled starting at a particular state, and everything ends on a particular state
                let target_state = state_machine.count_states();
                state_machine.create_state(target_state);

                for pattern in patterns {
                    let final_state = self.compile(state_machine, start_state);
                    state_machine.join_states(final_state, target_state);
                }

                target_state
            }
        }
    }
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol: Clone> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol: Clone> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol: Clone> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol: Clone> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol: Clone> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol: Clone, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'Match(x)' and 'Match(y)' should produce 'Match(xy)'
            (Match(first_string), Match(second_string)) => Match(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (MatchAll(first_string), MatchAll(second_string)) => MatchAll(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'y' should produce 'MatchAll(xy)'
            (MatchAll(first_string), second) => {
                let mut result = first_string.clone();
                result.push(second);
                MatchAll(result)
            },

            // Combining 'x' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (first, MatchAll(second_string)) => {
                let mut result: Vec<Pattern<Symbol>> = vec![first];
                for p in second_string {
                    result.push(p.clone());
                }
                MatchAll(result)
            },

            // Everything else is just MatchAll(xy)
            (first, second) => MatchAll(vec![first, second])
        }
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'MatchAny(x)' and 'MatchAny(y)' should produce 'MatchAny(xy)'
            (MatchAny(first_string), MatchAny(second_string)) => MatchAny(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Everything else is just MatchAny(xy)
            (first, second) => MatchAny(vec![first, second])
        }
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern_combine_matches() {
        let pattern = "abc".append("def");

        assert!(pattern == Match(vec!['a', 'b', 'c', 'd', 'e', 'f']));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_left() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_right() {
        let pattern = "abc".append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_both() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_not_matchall_or_match() {
        let pattern: Pattern<char> = MatchAny(vec![Epsilon]).append(MatchAny(vec![Epsilon]));

        assert!(pattern == MatchAll(vec![MatchAny(vec![Epsilon]), MatchAny(vec![Epsilon])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern_combine_matchanys() {
        let pattern = MatchAny(vec!["abc".to_pattern()]).or(MatchAny(vec!["def".to_pattern()]));

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<commit_msg>Implement the inifinite repeat compiler<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular patterns
//!
//! This provides a data structure, `Pattern<Symbol>` representing a matching pattern in a regular language. This is a
//! more generalised form of a regular expression as it supports symbol types other than simple strings. A pattern using
//! the `char` symbol has identical expressive power to a regular expression.
//!
//! Regular patterns can be created from strings, arrays or vectors using `into_pattern`, and can use any cloneable type
//! to represent a symbol:
//!
//! ```
//! # use ndfa::*;
//! let match_abc = "abc".into_pattern();
//! let match_123 = [1,2,3].into_pattern();
//! ```
//!
//! These patterns are quite boring (they just match exactly the string that's passed in). To create more interesting
//! patterns, there are a series of functions that will create patterns with repetitions or other constructs in them:
//!
//! ```
//! # use ndfa::*;
//! let stuff_or_nonsense = "stuff".or("nonsense");
//! let any_amount_of_stuff = "stuff".repeat_forever(1);
//! let went_to_market = "piggies".repeat(0..5);
//! ```
//!
//! For convenience, these methods will work on any type that can be converted into a pattern. Every regular expression
//! can be converted into a regular pattern, but these patterns are also for symbol types other than characters, and do
//! not require any quoting in order to be used (and are hence much easier to use with dynamic values).
//!
//! ```
//! # use ndfa::*;
//! let some_counting = vec![1, 2, 3].repeat_forever(1);
//! ```
//!

use std::iter::FromIterator;
use std::ops::Range;

use super::state_machine::*;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Pattern<Symbol: Clone> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

impl<Symbol: Clone> Pattern<Symbol> {
    ///
    /// Compiles this pattern onto a state machine, returning the accepting symbol
    ///
    pub fn compile<OutputSymbol>(&self, state_machine: &mut MutableStateMachine<Symbol, OutputSymbol>, start_state: StateId) -> StateId {
        match self {
            &Epsilon => {
                start_state
            },

            &Match(ref symbols) => {
                // Match each symbol in turn
                let mut current_state = start_state;

                for sym in symbols {
                    let next_state = state_machine.count_states();
                    state_machine.add_transition(current_state, sym.clone(), next_state);
                    current_state = next_state;
                }

                current_state
            },

            &RepeatInfinite(ref count, ref pattern) => {
                // Create a target state
                let target_state = state_machine.count_states();
                state_machine.create_state(target_state);

                let mut repeat_state = start_state;

                for repeat in 0..(count+2) {
                    // The last state can also be the target state
                    if repeat == count+1 {
                        state_machine.join_states(repeat_state, target_state)
                    }

                    // Compile this iteration through the repetition
                    let initial_state = repeat_state;
                    repeat_state = pattern.compile(state_machine, repeat_state);

                    // The last state needs to repeat, so turn it into a loop
                    if repeat == count + 1 {
                        state_machine.join_states(repeat_state, initial_state);
                    }
                }

                target_state
            },

            &Repeat(ref range, ref pattern) => {
                start_state
            },

            &MatchAll(ref patterns) => {
                // Match each pattern in turn
                let mut current_state = start_state;

                for pattern in patterns {
                    let next_state = pattern.compile(state_machine, current_state);
                    current_state = next_state;
                }

                current_state
            },

            &MatchAny(ref patterns) => {
                // Everything is compiled starting at a particular state, and everything ends on a particular state
                let target_state = state_machine.count_states();
                state_machine.create_state(target_state);

                for pattern in patterns {
                    let final_state = pattern.compile(state_machine, start_state);
                    state_machine.join_states(final_state, target_state);
                }

                target_state
            }
        }
    }
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol: Clone> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol: Clone> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol: Clone> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol: Clone> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol: Clone> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol: Clone, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'Match(x)' and 'Match(y)' should produce 'Match(xy)'
            (Match(first_string), Match(second_string)) => Match(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (MatchAll(first_string), MatchAll(second_string)) => MatchAll(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'y' should produce 'MatchAll(xy)'
            (MatchAll(first_string), second) => {
                let mut result = first_string.clone();
                result.push(second);
                MatchAll(result)
            },

            // Combining 'x' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (first, MatchAll(second_string)) => {
                let mut result: Vec<Pattern<Symbol>> = vec![first];
                for p in second_string {
                    result.push(p.clone());
                }
                MatchAll(result)
            },

            // Everything else is just MatchAll(xy)
            (first, second) => MatchAll(vec![first, second])
        }
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'MatchAny(x)' and 'MatchAny(y)' should produce 'MatchAny(xy)'
            (MatchAny(first_string), MatchAny(second_string)) => MatchAny(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Everything else is just MatchAny(xy)
            (first, second) => MatchAny(vec![first, second])
        }
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern_combine_matches() {
        let pattern = "abc".append("def");

        assert!(pattern == Match(vec!['a', 'b', 'c', 'd', 'e', 'f']));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_left() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_right() {
        let pattern = "abc".append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_both() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_not_matchall_or_match() {
        let pattern: Pattern<char> = MatchAny(vec![Epsilon]).append(MatchAny(vec![Epsilon]));

        assert!(pattern == MatchAll(vec![MatchAny(vec![Epsilon]), MatchAny(vec![Epsilon])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern_combine_matchanys() {
        let pattern = MatchAny(vec!["abc".to_pattern()]).or(MatchAny(vec!["def".to_pattern()]));

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<|endoftext|>


<commit_before>use euclid::{Point2D, Rect, Size2D};
use internal_types::{CompiledNode, DrawListId, DrawListItemIndex};
use resource_list::ResourceList;
use util;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct NodeIndex(pub u32);

pub struct DrawListIndexBuffer {
    pub draw_list_id: DrawListId,
    pub indices: Vec<DrawListItemIndex>,
}

pub struct AABBTreeNode {
    pub split_rect: Rect<f32>,
    pub actual_rect: Rect<f32>,
    pub node_index: NodeIndex,

    // TODO: Use Option + NonZero here
    pub children: Option<NodeIndex>,

    pub is_visible: bool,

    pub draw_lists: Vec<DrawListIndexBuffer>,

    pub resource_list: Option<ResourceList>,
    pub compiled_node: Option<CompiledNode>,
}

impl AABBTreeNode {
    fn new(split_rect: &Rect<f32>, node_index: NodeIndex) -> AABBTreeNode {
        AABBTreeNode {
            split_rect: split_rect.clone(),
            actual_rect: Rect::zero(),
            node_index: node_index,
            children: None,
            is_visible: false,
            resource_list: None,
            draw_lists: Vec::new(),
            compiled_node: None,
        }
    }

    #[inline]
    fn append_item(&mut self,
                   draw_list_id: DrawListId,
                   item_index: DrawListItemIndex,
                   rect: &Rect<f32>) {
        self.actual_rect = self.actual_rect.union(rect);

        let need_new_list = match self.draw_lists.last_mut() {
            Some(draw_list) => {
                draw_list.draw_list_id != draw_list_id
            }
            None => {
                true
            }
        };

        if need_new_list {
            self.draw_lists.push(DrawListIndexBuffer {
                draw_list_id: draw_list_id,
                indices: Vec::new(),
            });
        }

        self.draw_lists.last_mut().unwrap().indices.push(item_index);
    }

    fn item_count(&self) -> usize {
        let mut count = 0;
        for list in &self.draw_lists {
            count += list.indices.len();
        }
        count
    }
}

pub struct AABBTree {
    pub nodes: Vec<AABBTreeNode>,
    pub split_size: f32,

    work_node_indices: Vec<NodeIndex>,
}

impl AABBTree {
    pub fn new(split_size: f32, scene_rect: &Rect<f32>) -> AABBTree {
        let mut tree = AABBTree {
            nodes: Vec::new(),
            split_size: split_size,

            work_node_indices: Vec::new(),
        };

        let root_node = AABBTreeNode::new(scene_rect, NodeIndex(0));
        tree.nodes.push(root_node);

        tree
    }

    #[allow(dead_code)]
    pub fn print(&self, node_index: NodeIndex, level: u32) {
        let mut indent = String::new();
        for _ in 0..level {
            indent.push_str("  ");
        }

        let node = self.node(node_index);
        println!("{}n={:?} sr={:?} ar={:?} c={:?} lists={} items={}",
                 indent,
                 node_index,
                 node.split_rect,
                 node.actual_rect,
                 node.children,
                 node.draw_lists.len(),
                 node.item_count());

        if let Some(child_index) = node.children {
            let NodeIndex(child_index) = child_index;
            self.print(NodeIndex(child_index+0), level+1);
            self.print(NodeIndex(child_index+1), level+1);
        }
    }

    #[inline(always)]
    pub fn node(&self, index: NodeIndex) -> &AABBTreeNode {
        let NodeIndex(index) = index;
        &self.nodes[index as usize]
    }

    #[inline(always)]
    pub fn node_mut(&mut self, index: NodeIndex) -> &mut AABBTreeNode {
        let NodeIndex(index) = index;
        &mut self.nodes[index as usize]
    }

    #[inline]
    fn find_best_nodes(&mut self,
                       node_index: NodeIndex,
                       rect: &Rect<f32>) {
        self.split_if_needed(node_index);

        if let Some(child_node_index) = self.node(node_index).children {
            let NodeIndex(child_node_index) = child_node_index;
            let left_node_index = NodeIndex(child_node_index + 0);
            let right_node_index = NodeIndex(child_node_index + 1);

            let left_intersect = self.node(left_node_index).split_rect.intersects(rect);
            if left_intersect {
                self.find_best_nodes(left_node_index, rect);
            }

            let right_intersect = self.node(right_node_index).split_rect.intersects(rect);
            if right_intersect {
                self.find_best_nodes(right_node_index, rect);
            }
        } else {
            self.work_node_indices.push(node_index);
        }
    }

    #[inline]
    pub fn insert(&mut self,
                  rect: &Rect<f32>,
                  draw_list_id: DrawListId,
                  item_index: DrawListItemIndex) {
        debug_assert!(self.work_node_indices.len() == 0);
        self.find_best_nodes(NodeIndex(0), rect);
        for node_index in self.work_node_indices.drain(..) {
            let NodeIndex(node_index) = node_index;
            let node = &mut self.nodes[node_index as usize];
            node.append_item(draw_list_id, item_index, rect);
        }
    }

    fn split_if_needed(&mut self, node_index: NodeIndex) {
        if self.node(node_index).children.is_none() {
            let rect = self.node(node_index).split_rect.clone();

            let child_rects = if rect.size.width > self.split_size &&
                                 rect.size.width > rect.size.height {
                let new_width = rect.size.width * 0.5;

                let left = Rect::new(rect.origin, Size2D::new(new_width, rect.size.height));
                let right = Rect::new(rect.origin + Point2D::new(new_width, 0.0),
                                      Size2D::new(rect.size.width - new_width, rect.size.height));

                Some((left, right))
            } else if rect.size.height > self.split_size {
                let new_height = rect.size.height * 0.5;

                let left = Rect::new(rect.origin, Size2D::new(rect.size.width, new_height));
                let right = Rect::new(rect.origin + Point2D::new(0.0, new_height),
                                      Size2D::new(rect.size.width, rect.size.height - new_height));

                Some((left, right))
            } else {
                None
            };

            if let Some((left_rect, right_rect)) = child_rects {
                let child_node_index = self.nodes.len() as u32;

                let left_node = AABBTreeNode::new(&left_rect, NodeIndex(child_node_index+0));
                self.nodes.push(left_node);

                let right_node = AABBTreeNode::new(&right_rect, NodeIndex(child_node_index+1));
                self.nodes.push(right_node);

                self.node_mut(node_index).children = Some(NodeIndex(child_node_index));
            }
        }
    }

    fn check_node_visibility(&mut self,
                             node_index: NodeIndex,
                             rect: &Rect<f32>) {
        let children = {
            let node = self.node_mut(node_index);
            if node.split_rect.intersects(rect) {
                if node.draw_lists.len() > 0 &&
                   node.actual_rect.intersects(rect) {
                    debug_assert!(node.children.is_none());
                    node.is_visible = true;
                }
                node.children
            } else {
                return;
            }
        };

        if let Some(child_index) = children {
            let NodeIndex(child_index) = child_index;
            self.check_node_visibility(NodeIndex(child_index+0), rect);
            self.check_node_visibility(NodeIndex(child_index+1), rect);
        }
    }

    pub fn cull(&mut self, rect: &Rect<f32>) {
        let _pf = util::ProfileScope::new("  cull");
        for node in &mut self.nodes {
            node.is_visible = false;
        }
        if self.nodes.len() > 0 {
            self.check_node_visibility(NodeIndex(0), &rect);
        }
    }
}
<commit_msg>Remove unused field<commit_after>use euclid::{Point2D, Rect, Size2D};
use internal_types::{CompiledNode, DrawListId, DrawListItemIndex};
use resource_list::ResourceList;
use util;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct NodeIndex(pub u32);

pub struct DrawListIndexBuffer {
    pub draw_list_id: DrawListId,
    pub indices: Vec<DrawListItemIndex>,
}

pub struct AABBTreeNode {
    pub split_rect: Rect<f32>,
    pub actual_rect: Rect<f32>,

    // TODO: Use Option + NonZero here
    pub children: Option<NodeIndex>,

    pub is_visible: bool,

    pub draw_lists: Vec<DrawListIndexBuffer>,

    pub resource_list: Option<ResourceList>,
    pub compiled_node: Option<CompiledNode>,
}

impl AABBTreeNode {
    fn new(split_rect: &Rect<f32>) -> AABBTreeNode {
        AABBTreeNode {
            split_rect: split_rect.clone(),
            actual_rect: Rect::zero(),
            children: None,
            is_visible: false,
            resource_list: None,
            draw_lists: Vec::new(),
            compiled_node: None,
        }
    }

    #[inline]
    fn append_item(&mut self,
                   draw_list_id: DrawListId,
                   item_index: DrawListItemIndex,
                   rect: &Rect<f32>) {
        self.actual_rect = self.actual_rect.union(rect);

        let need_new_list = match self.draw_lists.last_mut() {
            Some(draw_list) => {
                draw_list.draw_list_id != draw_list_id
            }
            None => {
                true
            }
        };

        if need_new_list {
            self.draw_lists.push(DrawListIndexBuffer {
                draw_list_id: draw_list_id,
                indices: Vec::new(),
            });
        }

        self.draw_lists.last_mut().unwrap().indices.push(item_index);
    }

    fn item_count(&self) -> usize {
        let mut count = 0;
        for list in &self.draw_lists {
            count += list.indices.len();
        }
        count
    }
}

pub struct AABBTree {
    pub nodes: Vec<AABBTreeNode>,
    pub split_size: f32,

    work_node_indices: Vec<NodeIndex>,
}

impl AABBTree {
    pub fn new(split_size: f32, scene_rect: &Rect<f32>) -> AABBTree {
        let mut tree = AABBTree {
            nodes: Vec::new(),
            split_size: split_size,

            work_node_indices: Vec::new(),
        };

        let root_node = AABBTreeNode::new(scene_rect);
        tree.nodes.push(root_node);

        tree
    }

    #[allow(dead_code)]
    pub fn print(&self, node_index: NodeIndex, level: u32) {
        let mut indent = String::new();
        for _ in 0..level {
            indent.push_str("  ");
        }

        let node = self.node(node_index);
        println!("{}n={:?} sr={:?} ar={:?} c={:?} lists={} items={}",
                 indent,
                 node_index,
                 node.split_rect,
                 node.actual_rect,
                 node.children,
                 node.draw_lists.len(),
                 node.item_count());

        if let Some(child_index) = node.children {
            let NodeIndex(child_index) = child_index;
            self.print(NodeIndex(child_index+0), level+1);
            self.print(NodeIndex(child_index+1), level+1);
        }
    }

    #[inline(always)]
    pub fn node(&self, index: NodeIndex) -> &AABBTreeNode {
        let NodeIndex(index) = index;
        &self.nodes[index as usize]
    }

    #[inline(always)]
    pub fn node_mut(&mut self, index: NodeIndex) -> &mut AABBTreeNode {
        let NodeIndex(index) = index;
        &mut self.nodes[index as usize]
    }

    #[inline]
    fn find_best_nodes(&mut self,
                       node_index: NodeIndex,
                       rect: &Rect<f32>) {
        self.split_if_needed(node_index);

        if let Some(child_node_index) = self.node(node_index).children {
            let NodeIndex(child_node_index) = child_node_index;
            let left_node_index = NodeIndex(child_node_index + 0);
            let right_node_index = NodeIndex(child_node_index + 1);

            let left_intersect = self.node(left_node_index).split_rect.intersects(rect);
            if left_intersect {
                self.find_best_nodes(left_node_index, rect);
            }

            let right_intersect = self.node(right_node_index).split_rect.intersects(rect);
            if right_intersect {
                self.find_best_nodes(right_node_index, rect);
            }
        } else {
            self.work_node_indices.push(node_index);
        }
    }

    #[inline]
    pub fn insert(&mut self,
                  rect: &Rect<f32>,
                  draw_list_id: DrawListId,
                  item_index: DrawListItemIndex) {
        debug_assert!(self.work_node_indices.len() == 0);
        self.find_best_nodes(NodeIndex(0), rect);
        for node_index in self.work_node_indices.drain(..) {
            let NodeIndex(node_index) = node_index;
            let node = &mut self.nodes[node_index as usize];
            node.append_item(draw_list_id, item_index, rect);
        }
    }

    fn split_if_needed(&mut self, node_index: NodeIndex) {
        if self.node(node_index).children.is_none() {
            let rect = self.node(node_index).split_rect.clone();

            let child_rects = if rect.size.width > self.split_size &&
                                 rect.size.width > rect.size.height {
                let new_width = rect.size.width * 0.5;

                let left = Rect::new(rect.origin, Size2D::new(new_width, rect.size.height));
                let right = Rect::new(rect.origin + Point2D::new(new_width, 0.0),
                                      Size2D::new(rect.size.width - new_width, rect.size.height));

                Some((left, right))
            } else if rect.size.height > self.split_size {
                let new_height = rect.size.height * 0.5;

                let left = Rect::new(rect.origin, Size2D::new(rect.size.width, new_height));
                let right = Rect::new(rect.origin + Point2D::new(0.0, new_height),
                                      Size2D::new(rect.size.width, rect.size.height - new_height));

                Some((left, right))
            } else {
                None
            };

            if let Some((left_rect, right_rect)) = child_rects {
                let child_node_index = self.nodes.len() as u32;

                let left_node = AABBTreeNode::new(&left_rect);
                self.nodes.push(left_node);

                let right_node = AABBTreeNode::new(&right_rect);
                self.nodes.push(right_node);

                self.node_mut(node_index).children = Some(NodeIndex(child_node_index));
            }
        }
    }

    fn check_node_visibility(&mut self,
                             node_index: NodeIndex,
                             rect: &Rect<f32>) {
        let children = {
            let node = self.node_mut(node_index);
            if node.split_rect.intersects(rect) {
                if node.draw_lists.len() > 0 &&
                   node.actual_rect.intersects(rect) {
                    debug_assert!(node.children.is_none());
                    node.is_visible = true;
                }
                node.children
            } else {
                return;
            }
        };

        if let Some(child_index) = children {
            let NodeIndex(child_index) = child_index;
            self.check_node_visibility(NodeIndex(child_index+0), rect);
            self.check_node_visibility(NodeIndex(child_index+1), rect);
        }
    }

    pub fn cull(&mut self, rect: &Rect<f32>) {
        let _pf = util::ProfileScope::new("  cull");
        for node in &mut self.nodes {
            node.is_visible = false;
        }
        if self.nodes.len() > 0 {
            self.check_node_visibility(NodeIndex(0), &rect);
        }
    }
}
<|endoftext|>