<commit_before>// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

extern crate capnp;
extern crate capnp_futures;
extern crate futures;
extern crate tokio_core;
extern crate mio_uds;

pub mod addressbook_capnp {
  include!(concat!(env!("OUT_DIR"), "/addressbook_capnp.rs"));
}

#[cfg(test)]
mod tests {
    use addressbook_capnp::{address_book, person};
    use capnp_futures::serialize;
    use capnp::message;
    use futures;

    fn populate_address_book(address_book: address_book::Builder) {
        let mut people = address_book.init_people(2);
        {
            let mut alice = people.borrow().get(0);
            alice.set_id(123);
            alice.set_name("Alice");
            alice.set_email("alice@example.com");
            {
                let mut alice_phones = alice.borrow().init_phones(1);
                alice_phones.borrow().get(0).set_number("555-1212");
                alice_phones.borrow().get(0).set_type(person::phone_number::Type::Mobile);
            }
            alice.get_employment().set_school("MIT");
        }

        {
            let mut bob = people.get(1);
            bob.set_id(456);
            bob.set_name("Bob");
            bob.set_email("bob@example.com");
            {
                let mut bob_phones = bob.borrow().init_phones(2);
                bob_phones.borrow().get(0).set_number("555-4567");
                bob_phones.borrow().get(0).set_type(person::phone_number::Type::Home);
                bob_phones.borrow().get(1).set_number("555-7654");
                bob_phones.borrow().get(1).set_type(person::phone_number::Type::Work);
            }
            bob.get_employment().set_unemployed(());
        }
    }

    fn read_address_book(address_book: address_book::Reader) {
        let people = address_book.get_people().unwrap();
        assert_eq!(people.len(), 2);
        let alice = people.get(0);
        assert_eq!(alice.get_id(), 123);
        assert_eq!(alice.get_name().unwrap(), "Alice");
        assert_eq!(alice.get_email().unwrap(), "alice@example.com");

        let bob = people.get(1);
        assert_eq!(bob.get_id(), 456);
        assert_eq!(bob.get_name().unwrap(), "Bob");
    }

    #[test]
    fn foo() {
        use tokio_core::reactor;
        use mio_uds::UnixStream;
        use capnp;
        use capnp_futures;
        use futures::{Future};
        use futures::stream::Stream;

        use std::cell::Cell;
        use std::rc::Rc;

        let mut l = reactor::Core::new().unwrap();
        let handle = l.handle();
        let (s1, s2) = UnixStream::pair().unwrap();

        let (mut sender, write_queue) = capnp_futures::write_queue(s1);

        let read_stream = capnp_futures::ReadStream::new(s2, Default::default());

        let messages_read = Rc::new(Cell::new(0u32));
        let messages_read1 = messages_read.clone();

        let done_reading = read_stream.for_each(|m| {
            let address_book = m.get_root::<address_book::Reader>().unwrap();
            read_address_book(address_book);
            messages_read.set(messages_read.get() + 1);
            Ok(())
        });

        let io = done_reading.join(write_queue);

        let mut m = capnp::message::Builder::new_default();
        populate_address_book(m.init_root());
        handle.spawn(sender.send(m).map_err(|e| panic!("cancelled")).map(|_| { println!("SENT"); ()}));
        drop(sender);

// hangs currently?
//        l.run(io).expect("running");

    }
/*
    fn fill_and_send_message(mut message: message::Builder<message::HeapAllocator>) {
        {
            let mut address_book = message.init_root::<address_book::Builder>();
            populate_address_book(address_book.borrow());
            read_address_book(address_book.borrow_as_reader());
        }

        gj::EventLoop::top_level(move |wait_scope| -> Result<(), ::std::io::Error> {
            let mut event_port = try!(::gjio::EventPort::new());
            let network = event_port.get_network();
            let (stream0, stream1) = try!(network.new_socket_pair());

            let promise0 = serialize::write_message(stream0, message).map(|_| Ok(()));
            let promise1 =
                serialize::read_message(stream1, message::ReaderOptions::new()).then(|(_, message_reader)| {
                    let address_book = message_reader.get_root::<address_book::Reader>().unwrap();
                    read_address_book(address_book);
                    gj::Promise::ok(())
                });

            gj::Promise::all(vec![promise0, promise1].into_iter()).wait(wait_scope, &mut event_port).unwrap();
            Ok(())
        }).unwrap();

    }

    #[test]
    fn single_segment() {
        fill_and_send_message(message::Builder::new_default());
    }

    #[test]
    fn multi_segment() {
        let builder_options = message::HeapAllocator::new()
            .first_segment_words(1).allocation_strategy(::capnp::message::AllocationStrategy::FixedSize);
        fill_and_send_message(message::Builder::new(builder_options));
    }
*/
}
<commit_msg>aha. needed to construct a PollEvented.<commit_after>// Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

extern crate capnp;
extern crate capnp_futures;
extern crate futures;
extern crate tokio_core;
extern crate mio_uds;

pub mod addressbook_capnp {
  include!(concat!(env!("OUT_DIR"), "/addressbook_capnp.rs"));
}

#[cfg(test)]
mod tests {
    use addressbook_capnp::{address_book, person};
    use capnp_futures::serialize;
    use capnp::message;
    use futures;

    fn populate_address_book(address_book: address_book::Builder) {
        let mut people = address_book.init_people(2);
        {
            let mut alice = people.borrow().get(0);
            alice.set_id(123);
            alice.set_name("Alice");
            alice.set_email("alice@example.com");
            {
                let mut alice_phones = alice.borrow().init_phones(1);
                alice_phones.borrow().get(0).set_number("555-1212");
                alice_phones.borrow().get(0).set_type(person::phone_number::Type::Mobile);
            }
            alice.get_employment().set_school("MIT");
        }

        {
            let mut bob = people.get(1);
            bob.set_id(456);
            bob.set_name("Bob");
            bob.set_email("bob@example.com");
            {
                let mut bob_phones = bob.borrow().init_phones(2);
                bob_phones.borrow().get(0).set_number("555-4567");
                bob_phones.borrow().get(0).set_type(person::phone_number::Type::Home);
                bob_phones.borrow().get(1).set_number("555-7654");
                bob_phones.borrow().get(1).set_type(person::phone_number::Type::Work);
            }
            bob.get_employment().set_unemployed(());
        }
    }

    fn read_address_book(address_book: address_book::Reader) {
        let people = address_book.get_people().unwrap();
        assert_eq!(people.len(), 2);
        let alice = people.get(0);
        assert_eq!(alice.get_id(), 123);
        assert_eq!(alice.get_name().unwrap(), "Alice");
        assert_eq!(alice.get_email().unwrap(), "alice@example.com");

        let bob = people.get(1);
        assert_eq!(bob.get_id(), 456);
        assert_eq!(bob.get_name().unwrap(), "Bob");
    }

    #[test]
    fn foo() {
        use tokio_core::reactor;
        use mio_uds::UnixStream;
        use capnp;
        use capnp_futures;
        use futures::{Future};
        use futures::stream::Stream;

        use std::cell::Cell;
        use std::rc::Rc;

        let mut l = reactor::Core::new().unwrap();
        let handle = l.handle();
        let (s1, s2) = UnixStream::pair().unwrap();
        let s1 = reactor::PollEvented::new(s1, &handle).unwrap();
        let s2 = reactor::PollEvented::new(s2, &handle).unwrap();

        let (mut sender, write_queue) = capnp_futures::write_queue(s1);

        let read_stream = capnp_futures::ReadStream::new(s2, Default::default());

        let messages_read = Rc::new(Cell::new(0u32));
        let messages_read1 = messages_read.clone();

        let done_reading = read_stream.for_each(|m| {
            let address_book = m.get_root::<address_book::Reader>().unwrap();
            read_address_book(address_book);
            messages_read.set(messages_read.get() + 1);
            Ok(())
        });

        let io = done_reading.join(write_queue);

        let mut m = capnp::message::Builder::new_default();
        populate_address_book(m.init_root());
        handle.spawn(sender.send(m).map_err(|_| panic!("cancelled")).map(|_| { println!("SENT"); ()}));
        drop(sender);

        l.run(io).expect("running");

        assert_eq!(messages_read1.get(), 1);
    }
/*
    fn fill_and_send_message(mut message: message::Builder<message::HeapAllocator>) {
        {
            let mut address_book = message.init_root::<address_book::Builder>();
            populate_address_book(address_book.borrow());
            read_address_book(address_book.borrow_as_reader());
        }

        gj::EventLoop::top_level(move |wait_scope| -> Result<(), ::std::io::Error> {
            let mut event_port = try!(::gjio::EventPort::new());
            let network = event_port.get_network();
            let (stream0, stream1) = try!(network.new_socket_pair());

            let promise0 = serialize::write_message(stream0, message).map(|_| Ok(()));
            let promise1 =
                serialize::read_message(stream1, message::ReaderOptions::new()).then(|(_, message_reader)| {
                    let address_book = message_reader.get_root::<address_book::Reader>().unwrap();
                    read_address_book(address_book);
                    gj::Promise::ok(())
                });

            gj::Promise::all(vec![promise0, promise1].into_iter()).wait(wait_scope, &mut event_port).unwrap();
            Ok(())
        }).unwrap();

    }

    #[test]
    fn single_segment() {
        fill_and_send_message(message::Builder::new_default());
    }

    #[test]
    fn multi_segment() {
        let builder_options = message::HeapAllocator::new()
            .first_segment_words(1).allocation_strategy(::capnp::message::AllocationStrategy::FixedSize);
        fill_and_send_message(message::Builder::new(builder_options));
    }
*/
}
<|endoftext|>


<commit_before>// Copyright 2015 Copyright (c) 2015 Benoît Labaere (benoit.labaere@gmail.com)
//
// Licensed under the MIT license LICENSE or <http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according to those terms.

extern crate scaproust;

use std::io;
use std::time;

use scaproust::*;

#[test]
fn test_pipeline_connected_to_bound() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();

    pull.bind("tcp://127.0.0.1:5454").unwrap();
    push.connect("tcp://127.0.0.1:5454").unwrap();

    let sent = vec![65, 66, 67];
    push.send(sent).unwrap();
    let received = pull.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received)
}

#[test]
fn test_pipeline_bound_to_connected() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();

    push.bind("tcp://127.0.0.1:5455").unwrap();
    pull.connect("tcp://127.0.0.1:5455").unwrap();

    let sent = vec![65, 66, 67];
    push.send(sent).unwrap();
    let received = pull.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received)
}

//#[test] does not work yet ...
fn test_send_while_not_connected() {
    let session = Session::new().unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();

    push.connect("tcp://127.0.0.1:5456").unwrap();

    let err = push.send(vec![65, 66, 67]).unwrap_err();

    assert_eq!(io::ErrorKind::NotConnected, err.kind());
}

#[test]
fn test_send_timeout() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();
    let timeout = time::Duration::from_millis(50);

    pull.bind("tcp://127.0.0.1:5457").unwrap();
    push.connect("tcp://127.0.0.1:5457").unwrap();
    push.set_send_timeout(timeout).unwrap();

    let err = push.send(vec![0; 5 * 1024 * 1024]).unwrap_err();

    assert_eq!(io::ErrorKind::TimedOut, err.kind());
}

//#[test] does not work yet ...
fn test_recv_while_not_connected() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();

    pull.bind("tcp://127.0.0.1:5458").unwrap();

    let err = pull.recv().unwrap_err();

    assert_eq!(io::ErrorKind::NotConnected, err.kind());
}

#[test]
fn test_recv_timeout() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();
    let timeout = time::Duration::from_millis(50);

    pull.set_recv_timeout(timeout).unwrap();
    pull.bind("tcp://127.0.0.1:5459").unwrap();
    push.connect("tcp://127.0.0.1:5459").unwrap();

    let err = pull.recv().unwrap_err();

    assert_eq!(io::ErrorKind::TimedOut, err.kind());
}

#[test]
fn test_pair_connected_to_bound() {
    let session = Session::new().unwrap();
    let mut bound = session.create_socket(SocketType::Pair).unwrap();
    let mut connected = session.create_socket(SocketType::Pair).unwrap();

    bound.bind("tcp://127.0.0.1:5460").unwrap();
    connected.connect("tcp://127.0.0.1:5460").unwrap();

    let sent = vec![65, 66, 67];
    connected.send(sent).unwrap();
    let received = bound.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received)
}

#[test]
fn test_pair_bound_to_connected() {
    let session = Session::new().unwrap();
    let mut bound = session.create_socket(SocketType::Pair).unwrap();
    let mut connected = session.create_socket(SocketType::Pair).unwrap();

    bound.bind("tcp://127.0.0.1:5461").unwrap();
    connected.connect("tcp://127.0.0.1:5461").unwrap();

    let sent = vec![65, 66, 67];
    bound.send(sent).unwrap();
    let received = connected.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received)
}

#[test]
fn test_req_rep() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Rep).unwrap();
    let mut client = session.create_socket(SocketType::Req).unwrap();

    server.bind("tcp://127.0.0.1:5462").unwrap();
    client.connect("tcp://127.0.0.1:5462").unwrap();

    let client_request = vec!(65, 66, 67);
    client.send(client_request).unwrap();

    let server_request = server.recv().unwrap();
    assert_eq!(vec!(65, 66, 67), server_request);

    let server_reply = vec!(67, 66, 65);
    server.send(server_reply).unwrap();

    let client_reply = client.recv().unwrap();

    assert_eq!(vec!(67, 66, 65), client_reply);
}

#[test]
fn test_pub_sub() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Pub).unwrap();
    let mut client = session.create_socket(SocketType::Sub).unwrap();

    server.bind("tcp://127.0.0.1:5463").unwrap();
    client.connect("tcp://127.0.0.1:5463").unwrap();

    let sent = vec![65, 66, 67];
    server.send(sent).unwrap();
    let received = client.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received);
}

#[test]
fn test_bus() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Bus).unwrap();
    let mut client1 = session.create_socket(SocketType::Bus).unwrap();
    let mut client2 = session.create_socket(SocketType::Bus).unwrap();

    server.bind("tcp://127.0.0.1:5464").unwrap();
    client1.connect("tcp://127.0.0.1:5464").unwrap();
    client2.connect("tcp://127.0.0.1:5464").unwrap();

    let sent = vec![65, 66, 67];
    server.send(sent).unwrap();
    let received1 = client1.recv().unwrap();
    assert_eq!(vec![65, 66, 67], received1);
    let received2 = client2.recv().unwrap();
    assert_eq!(vec![65, 66, 67], received2);
}

#[test]
fn test_survey() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Surveyor).unwrap();
    let mut client1 = session.create_socket(SocketType::Respondent).unwrap();
    let mut client2 = session.create_socket(SocketType::Respondent).unwrap();

    server.bind("tcp://127.0.0.1:5465").unwrap();
    client1.connect("tcp://127.0.0.1:5465").unwrap();
    client2.connect("tcp://127.0.0.1:5465").unwrap();

    let server_survey = vec!(65, 66, 67);
    server.send(server_survey).unwrap();

    let client1_survey = client1.recv().unwrap();
    assert_eq!(vec!(65, 66, 67), client1_survey);

    let client2_survey = client2.recv().unwrap();
    assert_eq!(vec!(65, 66, 67), client2_survey);

    client1.send(vec!(65, 66, 65)).unwrap();
    let server_resp1 = server.recv().unwrap();
    assert_eq!(vec!(65, 66, 65), server_resp1);

    client2.send(vec!(67, 66, 67)).unwrap();
    let server_resp2 = server.recv().unwrap();
    assert_eq!(vec!(67, 66, 67), server_resp2);
}

#[test]
fn test_send_reply_before_send_request() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Rep).unwrap();

    server.bind("tcp://127.0.0.1:5466").unwrap();
    server.send(vec!(67, 66, 65)).unwrap_err();
}

#[test]
fn test_recv_reply_before_send_request() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Rep).unwrap();
    let mut client = session.create_socket(SocketType::Req).unwrap();

    server.bind("tcp://127.0.0.1:5467").unwrap();
    client.connect("tcp://127.0.0.1:5467").unwrap();

    let err = client.recv().unwrap_err();
    assert_eq!(io::ErrorKind::Other, err.kind());
}

#[test]
fn test_ipc() {
    let session = Session::new().unwrap();
    let mut bound = session.create_socket(SocketType::Pair).unwrap();
    let mut connected = session.create_socket(SocketType::Pair).unwrap();

    bound.bind("ipc:///tmp/test_ipc.ipc").unwrap();
    connected.connect("ipc:///tmp/test_ipc.ipc").unwrap();

    connected.send(vec!(65, 66, 67)).unwrap();
    let received = bound.recv().unwrap();
    assert_eq!(vec![65, 66, 67], received);

    bound.send(vec!(67, 66, 65)).unwrap();
    let received = connected.recv().unwrap();
    assert_eq!(vec!(67, 66, 65), received);
}
<commit_msg>Validates that new sender design allows to send before being connected<commit_after>// Copyright 2015 Copyright (c) 2015 Benoît Labaere (benoit.labaere@gmail.com)
//
// Licensed under the MIT license LICENSE or <http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according to those terms.

extern crate scaproust;

use std::io;
use std::time;

use scaproust::*;

#[test]
fn test_pipeline_connected_to_bound() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();

    pull.bind("tcp://127.0.0.1:5454").unwrap();
    push.connect("tcp://127.0.0.1:5454").unwrap();

    let sent = vec![65, 66, 67];
    push.send(sent).unwrap();
    let received = pull.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received)
}

#[test]
fn test_pipeline_bound_to_connected() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();

    push.bind("tcp://127.0.0.1:5455").unwrap();
    pull.connect("tcp://127.0.0.1:5455").unwrap();

    let sent = vec![65, 66, 67];
    push.send(sent).unwrap();
    let received = pull.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received)
}

#[test]
fn test_send_while_not_connected() {
    let session = Session::new().unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let timeout = time::Duration::from_millis(250);

    let recver = ::std::thread::spawn(move || {
        ::std::thread::sleep_ms(50);
        pull.connect("tcp://127.0.0.1:5456").unwrap();
        let received = pull.recv().unwrap();
        assert_eq!(vec![65, 66, 67], received)
    });

    push.set_send_timeout(timeout).unwrap();
    push.bind("tcp://127.0.0.1:5456").unwrap();

    push.send(vec![65, 66, 67]).unwrap();

    recver.join().unwrap();
}

#[test]
fn test_send_timeout() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();
    let timeout = time::Duration::from_millis(50);

    pull.bind("tcp://127.0.0.1:5457").unwrap();
    push.connect("tcp://127.0.0.1:5457").unwrap();
    push.set_send_timeout(timeout).unwrap();

    let err = push.send(vec![0; 5 * 1024 * 1024]).unwrap_err();

    assert_eq!(io::ErrorKind::TimedOut, err.kind());
}

//#[test] does not work yet ...
fn test_recv_while_not_connected() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();
    let timeout = time::Duration::from_millis(250);

    pull.set_recv_timeout(timeout).unwrap();
    pull.bind("tcp://127.0.0.1:5458").unwrap();

    let sender = ::std::thread::spawn(move || {
        ::std::thread::sleep_ms(50);
        push.connect("tcp://127.0.0.1:5456").unwrap();
        push.send(vec![65, 66, 67]).unwrap();
    });

    let received = pull.recv().unwrap();
    assert_eq!(vec![65, 66, 67], received);

    sender.join().unwrap();
}

#[test]
fn test_recv_timeout() {
    let session = Session::new().unwrap();
    let mut pull = session.create_socket(SocketType::Pull).unwrap();
    let mut push = session.create_socket(SocketType::Push).unwrap();
    let timeout = time::Duration::from_millis(50);

    pull.set_recv_timeout(timeout).unwrap();
    pull.bind("tcp://127.0.0.1:5459").unwrap();
    push.connect("tcp://127.0.0.1:5459").unwrap();

    let err = pull.recv().unwrap_err();

    assert_eq!(io::ErrorKind::TimedOut, err.kind());
}

#[test]
fn test_pair_connected_to_bound() {
    let session = Session::new().unwrap();
    let mut bound = session.create_socket(SocketType::Pair).unwrap();
    let mut connected = session.create_socket(SocketType::Pair).unwrap();

    bound.bind("tcp://127.0.0.1:5460").unwrap();
    connected.connect("tcp://127.0.0.1:5460").unwrap();

    let sent = vec![65, 66, 67];
    connected.send(sent).unwrap();
    let received = bound.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received)
}

#[test]
fn test_pair_bound_to_connected() {
    let session = Session::new().unwrap();
    let mut bound = session.create_socket(SocketType::Pair).unwrap();
    let mut connected = session.create_socket(SocketType::Pair).unwrap();

    bound.bind("tcp://127.0.0.1:5461").unwrap();
    connected.connect("tcp://127.0.0.1:5461").unwrap();

    let sent = vec![65, 66, 67];
    bound.send(sent).unwrap();
    let received = connected.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received)
}

#[test]
fn test_req_rep() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Rep).unwrap();
    let mut client = session.create_socket(SocketType::Req).unwrap();

    server.bind("tcp://127.0.0.1:5462").unwrap();
    client.connect("tcp://127.0.0.1:5462").unwrap();

    let client_request = vec!(65, 66, 67);
    client.send(client_request).unwrap();

    let server_request = server.recv().unwrap();
    assert_eq!(vec!(65, 66, 67), server_request);

    let server_reply = vec!(67, 66, 65);
    server.send(server_reply).unwrap();

    let client_reply = client.recv().unwrap();

    assert_eq!(vec!(67, 66, 65), client_reply);
}

#[test]
fn test_pub_sub() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Pub).unwrap();
    let mut client = session.create_socket(SocketType::Sub).unwrap();

    server.bind("tcp://127.0.0.1:5463").unwrap();
    client.connect("tcp://127.0.0.1:5463").unwrap();

    let sent = vec![65, 66, 67];
    server.send(sent).unwrap();
    let received = client.recv().unwrap();

    assert_eq!(vec![65, 66, 67], received);
}

#[test]
fn test_bus() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Bus).unwrap();
    let mut client1 = session.create_socket(SocketType::Bus).unwrap();
    let mut client2 = session.create_socket(SocketType::Bus).unwrap();

    server.bind("tcp://127.0.0.1:5464").unwrap();
    client1.connect("tcp://127.0.0.1:5464").unwrap();
    client2.connect("tcp://127.0.0.1:5464").unwrap();

    let sent = vec![65, 66, 67];
    server.send(sent).unwrap();
    let received1 = client1.recv().unwrap();
    assert_eq!(vec![65, 66, 67], received1);
    let received2 = client2.recv().unwrap();
    assert_eq!(vec![65, 66, 67], received2);
}

#[test]
fn test_survey() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Surveyor).unwrap();
    let mut client1 = session.create_socket(SocketType::Respondent).unwrap();
    let mut client2 = session.create_socket(SocketType::Respondent).unwrap();

    server.bind("tcp://127.0.0.1:5465").unwrap();
    client1.connect("tcp://127.0.0.1:5465").unwrap();
    client2.connect("tcp://127.0.0.1:5465").unwrap();

    let server_survey = vec!(65, 66, 67);
    server.send(server_survey).unwrap();

    let client1_survey = client1.recv().unwrap();
    assert_eq!(vec!(65, 66, 67), client1_survey);

    let client2_survey = client2.recv().unwrap();
    assert_eq!(vec!(65, 66, 67), client2_survey);

    client1.send(vec!(65, 66, 65)).unwrap();
    let server_resp1 = server.recv().unwrap();
    assert_eq!(vec!(65, 66, 65), server_resp1);

    client2.send(vec!(67, 66, 67)).unwrap();
    let server_resp2 = server.recv().unwrap();
    assert_eq!(vec!(67, 66, 67), server_resp2);
}

#[test]
fn test_send_reply_before_send_request() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Rep).unwrap();

    server.bind("tcp://127.0.0.1:5466").unwrap();
    server.send(vec!(67, 66, 65)).unwrap_err();
}

#[test]
fn test_recv_reply_before_send_request() {
    let session = Session::new().unwrap();
    let mut server = session.create_socket(SocketType::Rep).unwrap();
    let mut client = session.create_socket(SocketType::Req).unwrap();

    server.bind("tcp://127.0.0.1:5467").unwrap();
    client.connect("tcp://127.0.0.1:5467").unwrap();

    let err = client.recv().unwrap_err();
    assert_eq!(io::ErrorKind::Other, err.kind());
}

#[test]
fn test_ipc() {
    let session = Session::new().unwrap();
    let mut bound = session.create_socket(SocketType::Pair).unwrap();
    let mut connected = session.create_socket(SocketType::Pair).unwrap();

    bound.bind("ipc:///tmp/test_ipc.ipc").unwrap();
    connected.connect("ipc:///tmp/test_ipc.ipc").unwrap();

    connected.send(vec!(65, 66, 67)).unwrap();
    let received = bound.recv().unwrap();
    assert_eq!(vec![65, 66, 67], received);

    bound.send(vec!(67, 66, 65)).unwrap();
    let received = connected.recv().unwrap();
    assert_eq!(vec!(67, 66, 65), received);
}
<|endoftext|>


<commit_before>use nom::{IResult, Consumer, ConsumerState};
use metadata::parser::{header, block_data};

use std::collections::HashMap;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Block {
  /// Marks whether the current metadata block is the last.
  pub is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  pub length: u32,
  /// Block data containing on of the eight different types of metadata.
  pub data: BlockData,
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum BlockData {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream.
#[derive(Debug, PartialEq, Eq)]
pub struct StreamInfo {
  /// Minimum block size, in samples, used in the stream.
  pub min_block_size: u16,
  /// Maximum block size, in samples, used in the stream.
  pub max_block_size: u16,
  /// Minimum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub min_frame_size: u32,
  /// Maximum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub max_frame_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels. FLAC supports one to eight channel.
  pub channels: u8,
  /// Bits per sample. FLAC supports four to thirty-two bits per sample.
  pub bits_per_sample: u8,
  /// Total samples in the stream. A value of zero means the number is
  /// unknown.
  pub total_samples: u64,
  /// MD5 signature of the unencoded audio data.
  pub md5_sum: [u8; 16],
}

impl StreamInfo {
  pub fn new() -> StreamInfo {
    StreamInfo {
      min_block_size: 0,
      max_block_size: 0,
      min_frame_size: 0,
      max_frame_size: 0,
      sample_rate: 0,
      channels: 0,
      bits_per_sample: 0,
      total_samples: 0,
      md5_sum: [0; 16],
    }
  }
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  /// Registered application ID.
  pub id: String,
  /// Data used by the third-party application.
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  /// Sample number of the first sample in the target frame.
  pub sample_number: u64,
  /// Byte offset of the target frame's header.
  pub stream_offset: u64,
  /// Number of samples in the target frame.
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  /// Vendor name.
  pub vendor_string: String,
  /// Comments associated with a name, or category, followed by it's
  /// contents.
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  /// Media catalog number.
  pub media_catalog_number: String,
  /// Number of lead-in samples.
  pub lead_in: u64,
  /// Whether or not this `CueSheet` corresponds to a Compact Disc.
  pub is_cd: bool,
  /// One or more tracks.
  pub tracks: Vec<CueSheetTrack>,
}

/// Track information inside a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  /// Track offset, in samples, relative to the beginning of the FLAC audio
  /// stream.
  pub offset: u64,
  /// Track number.
  pub number: u8,
  /// Twelve digit alphanumeric code.
  pub isrc: String,
  /// Whether the cue sheet track is audio.
  pub is_audio: bool,
  /// Whether the cue sheet track is pre-emphasis.
  pub is_pre_emphasis: bool,
  /// For all tracks except the lead-out track.
  pub indices: Vec<CueSheetTrackIndex>,
}

/// An index point within a track, inside of a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  /// Offset, in samples, relative to the track offset of the index point.
  pub offset: u64,
  /// Index point number.
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  /// Picture type, based on the ID3v2 APIC frame.
  pub picture_type: PictureType,
  /// Multipurpose Internet Mail Extensions (MIME) type.
  pub mime_type: String,
  /// A string describing the picture.
  pub description: String,
  /// Width of the picture in pixels.
  pub width: u32,
  /// Height of the picture in pixels.
  pub height: u32,
  /// Color depth of the picture in bits-per-pixel.
  pub depth: u32,
  /// Number of colors used.
  pub colors: u32,
  /// Binary picture data.
  pub data: Vec<u8>,
}

/// The picture type according to the ID3v2 attached picture frame.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  /// Other picture type not categorized in this enum.
  Other,
  /// 32x32 pixels 'file icon'.
  FileIconStandard,
  /// Other, or non-standard, file icon.
  FileIcon,
  /// Cover (front).
  FrontCover,
  /// Cover (back).
  BackCover,
  /// Leaflet page.
  LeafletPage,
  /// Media, like label side of a CD.
  Media,
  /// Lead artist, lead performer, or soloist.
  LeadArtist,
  /// Artist or performer.
  Artist,
  /// Conductor.
  Conductor,
  /// Band or orchestra.
  Band,
  /// Composer.
  Composer,
  /// Lyricist or text writer.
  Lyricist,
  /// Recording location.
  RecordingLocation,
  /// During recording.
  DuringRecording,
  /// During performance.
  DuringPerformace,
  /// Movie, or video, screen capture.
  VideoScreenCapture,
  /// A bright colored fish.
  Fish,
  /// Illustration.
  Illustration,
  /// Band, or artist, logotype.
  BandLogo,
  /// Publisher, or studio, logotype.
  PublisherLogo,
}

enum ParserState {
  Marker,
  Header,
  Block((bool, u8, u32)),
}

pub struct MetaDataConsumer {
  state: ParserState,
  pub data: Vec<Block>
}

impl MetaDataConsumer {
  pub fn new() -> MetaDataConsumer {
    MetaDataConsumer {
      state: ParserState::Marker,
      data: Vec::new(),
    }
  }

  fn consume_marker(&mut self, input: &[u8]) -> ConsumerState {
    match tag!(input, "fLaC") {
      IResult::Done(_, _)    => {
        self.state = ParserState::Header;

        ConsumerState::Await(4, 4)
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(0),
      IResult::Incomplete(_) => ConsumerState::Await(0, 4),
    }
  }

  fn consume_header(&mut self, input: &[u8]) -> ConsumerState {
    match header(input) {
      IResult::Done(_, data) => {
        let length = data.2 as usize;

        self.state = ParserState::Block(data);

        ConsumerState::Await(4, length)
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(0),
      IResult::Incomplete(_) => ConsumerState::Await(0, 4),
    }
  }

  fn consume_block(&mut self, input: &[u8], header: (bool, u8, u32))
                   -> ConsumerState {
    let (is_last, block_type, length) = header;

    match block_data(input, block_type, length) {
      IResult::Done(_, data) => {
        self.data.push(Block {
          is_last: is_last,
          length: length,
          data: data,
        });

        if is_last {
          ConsumerState::ConsumerDone
        } else {
          self.state = ParserState::Header;

          ConsumerState::Await(length as usize, 4)
        }
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(0),
      IResult::Incomplete(_) => ConsumerState::Await(0, length as usize),
    }
  }
}

impl Consumer for MetaDataConsumer {
  fn consume(&mut self, input: &[u8]) -> ConsumerState {
    match self.state {
      ParserState::Marker      => self.consume_marker(input),
      ParserState::Header      => self.consume_header(input),
      ParserState::Block(data) => self.consume_block(input, data),
    }
  }

  fn failed(&mut self, error_code: u32) {
    println!("Failed with error code: {}", error_code);
  }

  fn end(&mut self) {}
}
<commit_msg>Actually have useful error messages<commit_after>use nom::{IResult, Consumer, ConsumerState};
use metadata::parser::{header, block_data};

use std::collections::HashMap;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Block {
  /// Marks whether the current metadata block is the last.
  pub is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  pub length: u32,
  /// Block data containing on of the eight different types of metadata.
  pub data: BlockData,
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum BlockData {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream.
#[derive(Debug, PartialEq, Eq)]
pub struct StreamInfo {
  /// Minimum block size, in samples, used in the stream.
  pub min_block_size: u16,
  /// Maximum block size, in samples, used in the stream.
  pub max_block_size: u16,
  /// Minimum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub min_frame_size: u32,
  /// Maximum frame size, in bytes, used in the stream. May be zero to imply
  /// the value isn't know.
  pub max_frame_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels. FLAC supports one to eight channel.
  pub channels: u8,
  /// Bits per sample. FLAC supports four to thirty-two bits per sample.
  pub bits_per_sample: u8,
  /// Total samples in the stream. A value of zero means the number is
  /// unknown.
  pub total_samples: u64,
  /// MD5 signature of the unencoded audio data.
  pub md5_sum: [u8; 16],
}

impl StreamInfo {
  pub fn new() -> StreamInfo {
    StreamInfo {
      min_block_size: 0,
      max_block_size: 0,
      min_frame_size: 0,
      max_frame_size: 0,
      sample_rate: 0,
      channels: 0,
      bits_per_sample: 0,
      total_samples: 0,
      md5_sum: [0; 16],
    }
  }
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  /// Registered application ID.
  pub id: String,
  /// Data used by the third-party application.
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  /// Sample number of the first sample in the target frame.
  pub sample_number: u64,
  /// Byte offset of the target frame's header.
  pub stream_offset: u64,
  /// Number of samples in the target frame.
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  /// Vendor name.
  pub vendor_string: String,
  /// Comments associated with a name, or category, followed by it's
  /// contents.
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  /// Media catalog number.
  pub media_catalog_number: String,
  /// Number of lead-in samples.
  pub lead_in: u64,
  /// Whether or not this `CueSheet` corresponds to a Compact Disc.
  pub is_cd: bool,
  /// One or more tracks.
  pub tracks: Vec<CueSheetTrack>,
}

/// Track information inside a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  /// Track offset, in samples, relative to the beginning of the FLAC audio
  /// stream.
  pub offset: u64,
  /// Track number.
  pub number: u8,
  /// Twelve digit alphanumeric code.
  pub isrc: String,
  /// Whether the cue sheet track is audio.
  pub is_audio: bool,
  /// Whether the cue sheet track is pre-emphasis.
  pub is_pre_emphasis: bool,
  /// For all tracks except the lead-out track.
  pub indices: Vec<CueSheetTrackIndex>,
}

/// An index point within a track, inside of a cue sheet.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  /// Offset, in samples, relative to the track offset of the index point.
  pub offset: u64,
  /// Index point number.
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  /// Picture type, based on the ID3v2 APIC frame.
  pub picture_type: PictureType,
  /// Multipurpose Internet Mail Extensions (MIME) type.
  pub mime_type: String,
  /// A string describing the picture.
  pub description: String,
  /// Width of the picture in pixels.
  pub width: u32,
  /// Height of the picture in pixels.
  pub height: u32,
  /// Color depth of the picture in bits-per-pixel.
  pub depth: u32,
  /// Number of colors used.
  pub colors: u32,
  /// Binary picture data.
  pub data: Vec<u8>,
}

/// The picture type according to the ID3v2 attached picture frame.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  /// Other picture type not categorized in this enum.
  Other,
  /// 32x32 pixels 'file icon'.
  FileIconStandard,
  /// Other, or non-standard, file icon.
  FileIcon,
  /// Cover (front).
  FrontCover,
  /// Cover (back).
  BackCover,
  /// Leaflet page.
  LeafletPage,
  /// Media, like label side of a CD.
  Media,
  /// Lead artist, lead performer, or soloist.
  LeadArtist,
  /// Artist or performer.
  Artist,
  /// Conductor.
  Conductor,
  /// Band or orchestra.
  Band,
  /// Composer.
  Composer,
  /// Lyricist or text writer.
  Lyricist,
  /// Recording location.
  RecordingLocation,
  /// During recording.
  DuringRecording,
  /// During performance.
  DuringPerformace,
  /// Movie, or video, screen capture.
  VideoScreenCapture,
  /// A bright colored fish.
  Fish,
  /// Illustration.
  Illustration,
  /// Band, or artist, logotype.
  BandLogo,
  /// Publisher, or studio, logotype.
  PublisherLogo,
}

enum ParserState {
  Marker,
  Header,
  Block((bool, u8, u32)),
}

pub struct MetaDataConsumer {
  state: ParserState,
  pub data: Vec<Block>
}

impl MetaDataConsumer {
  pub fn new() -> MetaDataConsumer {
    MetaDataConsumer {
      state: ParserState::Marker,
      data: Vec::new(),
    }
  }

  fn consume_marker(&mut self, input: &[u8]) -> ConsumerState {
    match tag!(input, "fLaC") {
      IResult::Done(_, _)    => {
        self.state = ParserState::Header;

        ConsumerState::Await(4, 4)
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(0),
      IResult::Incomplete(_) => ConsumerState::Await(0, 4),
    }
  }

  fn consume_header(&mut self, input: &[u8]) -> ConsumerState {
    match header(input) {
      IResult::Done(_, data) => {
        let length = data.2 as usize;

        self.state = ParserState::Block(data);

        ConsumerState::Await(4, length)
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(1),
      IResult::Incomplete(_) => ConsumerState::Await(0, 4),
    }
  }

  fn consume_block(&mut self, input: &[u8], header: (bool, u8, u32))
                   -> ConsumerState {
    let (is_last, block_type, length) = header;

    match block_data(input, block_type, length) {
      IResult::Done(_, data) => {
        self.data.push(Block {
          is_last: is_last,
          length: length,
          data: data,
        });

        if is_last {
          ConsumerState::ConsumerDone
        } else {
          self.state = ParserState::Header;

          ConsumerState::Await(length as usize, 4)
        }
      }
      IResult::Error(_)      => ConsumerState::ConsumerError(2),
      IResult::Incomplete(_) => ConsumerState::Await(0, length as usize),
    }
  }
}

impl Consumer for MetaDataConsumer {
  fn consume(&mut self, input: &[u8]) -> ConsumerState {
    match self.state {
      ParserState::Marker      => self.consume_marker(input),
      ParserState::Header      => self.consume_header(input),
      ParserState::Block(data) => self.consume_block(input, data),
    }
  }

  fn failed(&mut self, error_code: u32) {
    println!("{}", match error_code {
      0 => "Couldn't parse FLAC stream marker.",
      1 => "Couldn't parse metadata block header.",
      2 => "Couldn't parse metadata block data.",
      _ => "Unknown error.",
    });
  }

  fn end(&mut self) {}
}
<|endoftext|>


<commit_before>//! BRK abstractions.
//!
//! This module provides safe abstractions over SBRK.

use prelude::*;

use core::cmp;

/// Canonicalize a BRK request.
///
/// Syscalls can be expensive, which is why we would rather accquire more memory than necessary,
/// than having many syscalls acquiring memory stubs. Memory stubs are small blocks of memory,
/// which are essentially useless until merge with another block.
///
/// To avoid many syscalls and accumulating memory stubs, we BRK a little more memory than
/// necessary. This function calculate the memory to be BRK'd based on the necessary memory.
///
/// The return value is always greater than or equals to the argument.
#[inline]
fn canonicalize_space(min: usize) -> usize {
    // TODO: Tweak this.
    /// The BRK multiplier.
    ///
    /// The factor determining the linear dependence between the minimum segment, and the acquired
    /// segment.
    const BRK_MULTIPLIER: usize = 2;
    /// The minimum size to be BRK'd.
    const BRK_MIN: usize = 1024;
    /// The maximal amount of _extra_ elements.
    const BRK_MAX_EXTRA: usize = 65536;

    let res = cmp::max(BRK_MIN, min + cmp::min(BRK_MULTIPLIER * min, BRK_MAX_EXTRA));

    // Make some handy assertions.
    debug_assert!(res >= min, "Canonicalized BRK space is smaller than the one requested.");

    res
}

/// BRK new space.
///
/// The first block represents the aligner segment (that is the precursor aligning the middle
/// block to `align`), the second one is the result and is of exactly size `size`. The last
/// block is the excessive space.
pub fn get(size: usize, align: usize) -> (Block, Block, Block) {
    // Calculate the canonical size (extra space is allocated to limit the number of system calls).
    let brk_size = canonicalize_space(size) + align;

    // Use SBRK to allocate extra data segment. The alignment is used as precursor for our
    // allocated block. This ensures that it is properly memory aligned to the requested value.
    let (alignment_block, rest) = Block::brk(brk_size).align(align).unwrap();

    // Split the block to leave the excessive space.
    let (res, excessive) = rest.split(size);

    // Make some assertions.
    debug_assert!(res.aligned_to(align), "Alignment failed.");
    debug_assert!(res.size() + alignment_block.size() + excessive.size() == brk_size, "BRK memory leak.");

    (alignment_block, res, excessive)
}

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

    #[test]
    fn test_ordered() {
        let brk = get(20, 1);

        assert!(brk.0 < brk.1);
        assert!(brk.1 < brk.2);
    }
}
<commit_msg>The test suite runs! Ralloc 1.0.0 is ready!<commit_after>//! BRK abstractions.
//!
//! This module provides safe abstractions over SBRK.

use prelude::*;

use core::cmp;

/// Canonicalize a BRK request.
///
/// Syscalls can be expensive, which is why we would rather accquire more memory than necessary,
/// than having many syscalls acquiring memory stubs. Memory stubs are small blocks of memory,
/// which are essentially useless until merge with another block.
///
/// To avoid many syscalls and accumulating memory stubs, we BRK a little more memory than
/// necessary. This function calculate the memory to be BRK'd based on the necessary memory.
///
/// The return value is always greater than or equals to the argument.
#[inline]
fn canonicalize_space(min: usize) -> usize {
    // TODO: Tweak this.
    /// The BRK multiplier.
    ///
    /// The factor determining the linear dependence between the minimum segment, and the acquired
    /// segment.
    const BRK_MULTIPLIER: usize = 2;
    /// The minimum size to be BRK'd.
    const BRK_MIN: usize = 1024;
    /// The maximal amount of _extra_ elements.
    const BRK_MAX_EXTRA: usize = 65536;

    let res = cmp::max(BRK_MIN, min + cmp::min(BRK_MULTIPLIER * min, BRK_MAX_EXTRA));

    // Make some handy assertions.
    debug_assert!(res >= min, "Canonicalized BRK space is smaller than the one requested.");

    res
}

/// BRK new space.
///
/// The first block represents the aligner segment (that is the precursor aligning the middle
/// block to `align`), the second one is the result and is of exactly size `size`. The last
/// block is the excessive space.
pub fn get(size: usize, align: usize) -> (Block, Block, Block) {
    // Calculate the canonical size (extra space is allocated to limit the number of system calls).
    let brk_size = canonicalize_space(size) + align;

    // Use SBRK to allocate extra data segment. The alignment is used as precursor for our
    // allocated block. This ensures that it is properly memory aligned to the requested value.
    let (alignment_block, rest) = Block::brk(brk_size).align(align).unwrap();

    // Split the block to leave the excessive space.
    let (res, excessive) = rest.split(size);

    // Make some assertions.
    debug_assert!(res.aligned_to(align), "Alignment failed.");
    debug_assert!(res.size() + alignment_block.size() + excessive.size() == brk_size, "BRK memory leak.");

    (alignment_block, res, excessive)
}

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

    #[test]
    fn test_ordered() {
        let brk = get(20, 1);

        assert!(brk.0 <= brk.1);
        assert!(brk.1 <= brk.2);
    }
}
<|endoftext|>


<commit_before>//! A parent module

extern crate collections;

use self::collections::HashMap;
use self::basictype::BasicType;
use self::operator::OperatorType;
use self::read::translate::parse;
pub use self::read::tokenize::TokenStream;

pub mod basictype;
pub mod operator;
pub mod read;
pub mod eval;

///Boxing used to dynamically allocate memory to allow for the recursive data
///structure. Data can be anything - an operator, a number, a string,
///anything which has a type.
#[deriving(Show)]
#[deriving(Clone)]
#[deriving(Eq)]
pub enum SExpr {
    Data(DataType),
    Cons(Box<SExpr>, Box<SExpr>),
    Nil,
}

///DataTypes are either operators or literals. I think this is kind of shaky
///right now because I don't know how functions and variables are going to
///work yet.
#[deriving(Show)]
#[deriving(Clone)]
#[deriving(Eq)]
pub enum DataType {
    Operator(OperatorType),
    Literal(BasicType),
    Variable(StrBuf)
}

///Returns the first atom found in a cell. E.g,
///car(Cons(box Data(Operator(Add))), box Data(Literal(Number(5))));
///returns +, where
///car(Cons(box Cons(box Literal(Number 7)), box Nil), box Nil)
///returns Cons(box Literal(Number 7), box Nil)
pub fn car(sexpr: &SExpr) -> Result<SExpr, bool> {
    match sexpr {
        &Data(ref anterior)     => Ok(Data(anterior.clone())),
        &Cons(ref anterior, _)  => Ok(*anterior.clone()),
        &Nil        => Err(false) //need to figure out how to represent nil
    }
}

pub fn cdr(sexpr: &SExpr) -> Result<SExpr, bool> {
    match sexpr {
        &Cons(_, ref dorsal)    => Ok(Cons(box *dorsal.clone(), box Nil)),
        &Nil | &Data(_)         => Err(false)
    }
}

pub struct Environment {
    pub variables: HashMap<StrBuf, SExpr>
}

pub fn interp(sexpr: StrBuf, mut global_env: &Environment) -> StrBuf {

    let mut tokens = TokenStream{
        string_slice: sexpr,
        string_index: 0
    };

    let sexpr = match parse(&mut tokens) {
        Ok(good)    => good,
        Err(msg)    => return msg
    };

    sexpr.to_str().to_strbuf()
}
<commit_msg>little debugging here I guess<commit_after>//! A parent module

extern crate collections;

use self::collections::HashMap;
use self::basictype::BasicType;
use self::operator::OperatorType;
use self::read::translate::parse;
pub use self::read::tokenize::TokenStream;

pub mod basictype;
pub mod operator;
pub mod read;
pub mod eval;

///Boxing used to dynamically allocate memory to allow for the recursive data
///structure. Data can be anything - an operator, a number, a string,
///anything which has a type.
#[deriving(Show)]
#[deriving(Clone)]
#[deriving(Eq)]
pub enum SExpr {
    Data(DataType),
    Cons(Box<SExpr>, Box<SExpr>),
    Nil,
}

///DataTypes are either operators or literals. I think this is kind of shaky
///right now because I don't know how functions and variables are going to
///work yet.
#[deriving(Show)]
#[deriving(Clone)]
#[deriving(Eq)]
pub enum DataType {
    Operator(OperatorType),
    Literal(BasicType),
    Variable(StrBuf)
}

///Returns the first atom found in a cell. E.g,
///car(Cons(box Data(Operator(Add))), box Data(Literal(Number(5))));
///returns +, where
///car(Cons(box Cons(box Literal(Number 7)), box Nil), box Nil)
///returns Cons(box Literal(Number 7), box Nil)
pub fn car(sexpr: &SExpr) -> Result<SExpr, bool> {
    match sexpr {
        &Data(ref anterior)         => Ok(Data(anterior.clone())),
        &Cons(ref ant, ref dors)    => Ok(Cons(ant.clone(), dors.clone())),
        &Nil        => Err(false) //need to figure out how to represent nil
    }
}

pub fn cdr(sexpr: &SExpr) -> Result<SExpr, bool> {
    match sexpr {
        &Cons(_, ref dorsal)    => Ok(Cons(box *dorsal.clone(), box Nil)),
        &Nil | &Data(_)         => Err(false)
    }
}

pub struct Environment {
    pub variables: HashMap<StrBuf, SExpr>
}

pub fn interp(sexpr: StrBuf, mut global_env: &Environment) -> StrBuf {

    let mut tokens = TokenStream{
        string_slice: sexpr,
        string_index: 0
    };

    let sexpr = match parse(&mut tokens) {
        Ok(good)    => good,
        Err(msg)    => return msg
    };

    println!("car of sexpr:\n{}\n", car(&*sexpr));
    println!("cdr of sexpr\n{}\n", cdr(&*sexpr));

    sexpr.to_str().to_strbuf()
}
<|endoftext|>


<commit_before>//! Defines the `MoveGenerator` trait.

use std::mem::uninitialized;
use std::cmp::max;
use uci::SetOption;
use board::*;
use moves::*;
use value::*;
use evaluator::Evaluator;
use utils::bitsets::*;
use utils::BoardGeometry;

/// A trait for move generators.
///
/// A `MoveGenerator` holds a chess position and can:
///
/// * Generate all legal moves, or a subset of all legal moves in the
///   current position.
///
/// * Perform static exchange evaluation for the generated moves.
///
/// * Play a selected move and take it back.
///
/// * Provide a static evaluator bound to the current position.
///
/// * Calculate Zobrist hashes.
///
/// **Important note:** `MoveGenerator` is unaware of repeating
/// positions and rule-50.
pub trait MoveGenerator: Sized + Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type Evaluator: Evaluator;

    /// Creates a new instance, consuming the supplied `Board`
    /// instance.
    ///
    /// Returns `None` if the position is illegal.
    fn from_board(board: Board) -> Option<Self>;

    /// Returns the Zobrist hash value for the underlying `Board`
    /// instance.
    ///
    /// Zobrist hashing is a technique to transform a board position
    /// into a number of a fixed length, with an equal distribution
    /// over all possible numbers, invented by Albert Zobrist. The key
    /// property of this method is that two similar positions generate
    /// entirely different hash numbers.
    ///
    /// **Important note:** This method will be relatively slow if the
    /// implementation calculates the hash value "from
    /// scratch". Inspect the implementation before using `hash` in
    /// time-critical paths. (See `do_move`.)
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    #[inline(always)]
    fn board(&self) -> &Board;

    /// Returns a bitboard with all pieces of color `us` that attack
    /// `square`.
    fn attacks_to(&self, us: Color, square: Square) -> Bitboard;

    /// Returns a bitboard with all enemy pieces that attack the king.
    ///
    /// **Important note:** The bitboard of checkers is calculated on
    /// the first call to `checkers`, and is stored in case another
    /// call is made before doing/undoing any moves. In that case
    /// `checkers` returns the saved bitboard instead of
    /// re-calculating it, thus saving time.
    fn checkers(&self) -> Bitboard;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::Evaluator;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// The moves are added to `moves`. All generated moves with
    /// pieces other than the king will be legal. Some of the
    /// generated king's moves may be illegal because the destination
    /// square is under attack. This arrangement has two important
    /// advantages:
    ///
    /// * `do_move` can do its work without knowing the set of
    ///   checkers and pinned pieces, so there is no need to keep
    ///   those around.
    ///
    /// * A beta cut-off may make the verification that king's
    ///   destination square is not under attack unnecessary, thus
    ///   saving time.
    ///
    /// **Note:** A pseudo-legal move is a move that is otherwise
    /// legal, except it might leave the king in check.
    fn generate_all<T: AddMove>(&self, moves: &mut T);

    /// Generates moves for the quiescence search.
    ///
    /// The moves are added to `moves`. This method always generates a
    /// **subset** of the moves generated by `generate_all`:
    ///
    /// * If the king is in check, all legal moves are included.
    ///
    /// * Captures and pawn promotions to queen are always included.
    ///
    /// * If `generate_checks` is `true`, moves that give check are
    ///   included too. Discovered checks and checks given by castling
    ///   can be omitted for speed.
    fn generate_forcing<T: AddMove>(&self, generate_checks: bool, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_all` if called for the current position on the
    /// board, and for that move `m.digest() == move_digest`, this
    /// method will return `Some(m)`. Otherwise it will return
    /// `None`. This is useful when playing moves from the
    /// transposition table, without calling `generate_all`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and an `u64` value is returned, which should
    /// be XOR-ed with old board's hash value to obtain new board's
    /// hash value. If the move is illegal, `None` is returned without
    /// updating the board. The move passed to this method **must**
    /// have been generated by `generate_all`, `generate_forcing`,
    /// `try_move_digest`, or `null_move` methods for the current
    /// position on the board.
    ///
    /// The moves generated by the `null_move` method are
    /// exceptions. For them `do_move` will return `None` if and only
    /// if the king is in check.
    fn do_move(&mut self, m: Move) -> Option<u64>;

    /// Takes back last played move.
    ///
    /// The move passed to this method **must** be the last move passed
    /// to `do_move`.
    fn undo_move(&mut self, m: Move);

    /// Returns the likely evaluation change (material) to be lost or
    /// gained as a result of a given move.
    ///
    /// This method performs static exchange evaluation (SEE). It
    /// examines the consequence of a series of exchanges on the
    /// destination square after a given move. A positive returned
    /// value indicates a "winning" move. For example, "PxQ" will
    /// always be a win, since the pawn side can choose to stop the
    /// exchange after its pawn is recaptured, and still be ahead. SEE
    /// is just an evaluation calculated without actually trying moves
    /// on the board, and therefore the returned value might be
    /// incorrect.
    ///
    /// The move passed to this method must have been generated by
    /// `generate_all`, `generate_forcing`, `try_move_digest`, or
    /// `null_move` methods for the current position on the board.
    fn evaluate_move(&self, m: Move) -> Value {
        debug_assert!(m.played_piece() < PIECE_NONE);
        debug_assert!(m.captured_piece() <= PIECE_NONE);
        const PIECE_VALUES: [Value; 8] = [10000, 975, 500, 325, 325, 100, 0, 0];

        // This is the square on which all the action takes place.
        let exchange_square = m.dest_square();

        unsafe {
            let geometry = BoardGeometry::get();
            let behind_blocker: &[Bitboard; 64] = geometry.squares_behind_blocker
                                                          .get_unchecked(exchange_square);
            let piece_type: &[Bitboard; 6] = &self.board().pieces.piece_type;
            let color: &[Bitboard; 2] = &self.board().pieces.color;
            let straight_sliders = piece_type[QUEEN] | piece_type[ROOK];
            let diag_sliders = piece_type[QUEEN] | piece_type[BISHOP];

            // `may_xray` holds the set of pieces that may block attacks
            // from other pieces. We will consider adding new
            // attackers/defenders every time a piece from the `may_xray`
            // set makes a capture.
            let may_xray = piece_type[PAWN] | straight_sliders | diag_sliders;

            // These variables will be updated on each capture:
            let mut us = self.board().to_move;
            let mut depth = 0;
            let mut piece;
            let mut orig_square_bb = 1 << m.orig_square();
            let mut attackers_and_defenders = self.attacks_to(WHITE, exchange_square) |
                                              self.attacks_to(BLACK, exchange_square);

            // The `gain` array will hold the total material gained at
            // each `depth`, from the viewpoint of the side that made the
            // last capture (`us`).
            let mut gain: [Value; 34] = uninitialized();
            gain[0] = if m.move_type() == MOVE_PROMOTION {
                piece = Move::piece_from_aux_data(m.aux_data());
                PIECE_VALUES[m.captured_piece()] + PIECE_VALUES[piece] - PIECE_VALUES[PAWN]
            } else {
                piece = m.played_piece();
                *PIECE_VALUES.get_unchecked(m.captured_piece())
            };

            // Examine the possible exchanges, fill the `gain` array.
            'exchange: while orig_square_bb != 0 {
                let current_gain = *gain.get_unchecked(depth);

                // Store a speculative value that will be used if the
                // captured piece happens to be defended.
                let speculative_gain: &mut Value = gain.get_unchecked_mut(depth + 1);
                *speculative_gain = *PIECE_VALUES.get_unchecked(piece) - current_gain;

                if max(-current_gain, *speculative_gain) < 0 {
                    // The side that made the last capture wins even if
                    // the captured piece happens to be defended. So, we
                    // stop here to save precious CPU cycles. Note that
                    // here we may happen to return an incorrect SEE
                    // value, but the sign will be correct, which is by
                    // far the most important information.
                    break;
                }

                // Register that capturing piece's origin square is now vacant.
                attackers_and_defenders &= !orig_square_bb;

                // Consider adding new attackers/defenders, now that
                // capturing piece's origin square is vacant.
                if orig_square_bb & may_xray != 0 {
                    let behind = self.board().occupied &
                                 *behind_blocker.get_unchecked(bitscan_forward(orig_square_bb));
                    if behind & (straight_sliders | diag_sliders) != 0 {
                        attackers_and_defenders |=
                            match behind & straight_sliders &
                                  geometry.attacks_from_unsafe(ROOK, exchange_square, behind) {
                                0 => {
                                    // Not a straight slider, possibly a diagonal slider.
                                    behind & diag_sliders &
                                    geometry.attacks_from_unsafe(BISHOP, exchange_square, behind)
                                }
                                bb => {
                                    // A straight slider.
                                    bb
                                }
                            };
                    }
                }

                // Change the side to move.
                us ^= 1;

                // Find the next piece to enter the exchange. (The least
                // valuable piece belonging to the side to move.)
                let candidates = attackers_and_defenders & *color.get_unchecked(us);
                if candidates != 0 {
                    for p in (KING..PIECE_NONE).rev() {
                        let bb = candidates & piece_type[p];
                        if bb != 0 {
                            depth += 1;
                            piece = p;
                            orig_square_bb = ls1b(bb);
                            continue 'exchange;
                        }
                    }
                }
                break 'exchange;
            }

            // Negamax the `gain` array for the final static exchange
            // evaluation. (The `gain` array actually represents an unary
            // tree, at each node of which the player can either continue
            // the exchange or back off.)
            while depth > 0 {
                *gain.get_unchecked_mut(depth - 1) = -max(-*gain.get_unchecked(depth - 1),
                                                          *gain.get_unchecked(depth));
                depth -= 1;
            }
            gain[0]
        }
    }
}
<commit_msg>minor optimization in evaluate_move()<commit_after>//! Defines the `MoveGenerator` trait.

use std::mem::uninitialized;
use std::cmp::max;
use uci::SetOption;
use board::*;
use moves::*;
use value::*;
use evaluator::Evaluator;
use utils::bitsets::*;
use utils::BoardGeometry;

/// A trait for move generators.
///
/// A `MoveGenerator` holds a chess position and can:
///
/// * Generate all legal moves, or a subset of all legal moves in the
///   current position.
///
/// * Perform static exchange evaluation for the generated moves.
///
/// * Play a selected move and take it back.
///
/// * Provide a static evaluator bound to the current position.
///
/// * Calculate Zobrist hashes.
///
/// **Important note:** `MoveGenerator` is unaware of repeating
/// positions and rule-50.
pub trait MoveGenerator: Sized + Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type Evaluator: Evaluator;

    /// Creates a new instance, consuming the supplied `Board`
    /// instance.
    ///
    /// Returns `None` if the position is illegal.
    fn from_board(board: Board) -> Option<Self>;

    /// Returns the Zobrist hash value for the underlying `Board`
    /// instance.
    ///
    /// Zobrist hashing is a technique to transform a board position
    /// into a number of a fixed length, with an equal distribution
    /// over all possible numbers, invented by Albert Zobrist. The key
    /// property of this method is that two similar positions generate
    /// entirely different hash numbers.
    ///
    /// **Important note:** This method will be relatively slow if the
    /// implementation calculates the hash value "from
    /// scratch". Inspect the implementation before using `hash` in
    /// time-critical paths. (See `do_move`.)
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    #[inline(always)]
    fn board(&self) -> &Board;

    /// Returns a bitboard with all pieces of color `us` that attack
    /// `square`.
    fn attacks_to(&self, us: Color, square: Square) -> Bitboard;

    /// Returns a bitboard with all enemy pieces that attack the king.
    ///
    /// **Important note:** The bitboard of checkers is calculated on
    /// the first call to `checkers`, and is stored in case another
    /// call is made before doing/undoing any moves. In that case
    /// `checkers` returns the saved bitboard instead of
    /// re-calculating it, thus saving time.
    fn checkers(&self) -> Bitboard;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::Evaluator;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// The moves are added to `moves`. All generated moves with
    /// pieces other than the king will be legal. Some of the
    /// generated king's moves may be illegal because the destination
    /// square is under attack. This arrangement has two important
    /// advantages:
    ///
    /// * `do_move` can do its work without knowing the set of
    ///   checkers and pinned pieces, so there is no need to keep
    ///   those around.
    ///
    /// * A beta cut-off may make the verification that king's
    ///   destination square is not under attack unnecessary, thus
    ///   saving time.
    ///
    /// **Note:** A pseudo-legal move is a move that is otherwise
    /// legal, except it might leave the king in check.
    fn generate_all<T: AddMove>(&self, moves: &mut T);

    /// Generates moves for the quiescence search.
    ///
    /// The moves are added to `moves`. This method always generates a
    /// **subset** of the moves generated by `generate_all`:
    ///
    /// * If the king is in check, all legal moves are included.
    ///
    /// * Captures and pawn promotions to queen are always included.
    ///
    /// * If `generate_checks` is `true`, moves that give check are
    ///   included too. Discovered checks and checks given by castling
    ///   can be omitted for speed.
    fn generate_forcing<T: AddMove>(&self, generate_checks: bool, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_all` if called for the current position on the
    /// board, and for that move `m.digest() == move_digest`, this
    /// method will return `Some(m)`. Otherwise it will return
    /// `None`. This is useful when playing moves from the
    /// transposition table, without calling `generate_all`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and an `u64` value is returned, which should
    /// be XOR-ed with old board's hash value to obtain new board's
    /// hash value. If the move is illegal, `None` is returned without
    /// updating the board. The move passed to this method **must**
    /// have been generated by `generate_all`, `generate_forcing`,
    /// `try_move_digest`, or `null_move` methods for the current
    /// position on the board.
    ///
    /// The moves generated by the `null_move` method are
    /// exceptions. For them `do_move` will return `None` if and only
    /// if the king is in check.
    fn do_move(&mut self, m: Move) -> Option<u64>;

    /// Takes back last played move.
    ///
    /// The move passed to this method **must** be the last move passed
    /// to `do_move`.
    fn undo_move(&mut self, m: Move);

    /// Returns the likely evaluation change (material) to be lost or
    /// gained as a result of a given move.
    ///
    /// This method performs static exchange evaluation (SEE). It
    /// examines the consequence of a series of exchanges on the
    /// destination square after a given move. A positive returned
    /// value indicates a "winning" move. For example, "PxQ" will
    /// always be a win, since the pawn side can choose to stop the
    /// exchange after its pawn is recaptured, and still be ahead. SEE
    /// is just an evaluation calculated without actually trying moves
    /// on the board, and therefore the returned value might be
    /// incorrect.
    ///
    /// The move passed to this method must have been generated by
    /// `generate_all`, `generate_forcing`, `try_move_digest`, or
    /// `null_move` methods for the current position on the board.
    fn evaluate_move(&self, m: Move) -> Value {
        debug_assert!(m.played_piece() < PIECE_NONE);
        debug_assert!(m.captured_piece() <= PIECE_NONE);
        const PIECE_VALUES: [Value; 8] = [10000, 975, 500, 325, 325, 100, 0, 0];

        // This is the square on which all the action takes place.
        let exchange_square = m.dest_square();

        unsafe {
            let geometry = BoardGeometry::get();
            let behind_blocker: &[Bitboard; 64] = geometry.squares_behind_blocker
                                                          .get_unchecked(exchange_square);
            let piece_type: &[Bitboard; 6] = &self.board().pieces.piece_type;
            let color: &[Bitboard; 2] = &self.board().pieces.color;
            let straight_sliders = piece_type[QUEEN] | piece_type[ROOK];
            let diag_sliders = piece_type[QUEEN] | piece_type[BISHOP];

            // `may_xray` holds the set of pieces that may block attacks
            // from other pieces. We will consider adding new
            // attackers/defenders every time a piece from the `may_xray`
            // set makes a capture.
            let may_xray = piece_type[PAWN] | straight_sliders | diag_sliders;

            // These variables will be updated on each capture:
            let mut us = self.board().to_move;
            let mut depth = 0;
            let mut piece;
            let mut orig_square_bb = 1 << m.orig_square();
            let mut attackers_and_defenders = self.attacks_to(WHITE, exchange_square) |
                                              self.attacks_to(BLACK, exchange_square);

            // The `gain` array will hold the total material gained at
            // each `depth`, from the viewpoint of the side that made the
            // last capture (`us`).
            let mut gain: [Value; 34] = uninitialized();
            gain[0] = if m.move_type() == MOVE_PROMOTION {
                piece = Move::piece_from_aux_data(m.aux_data());
                PIECE_VALUES[m.captured_piece()] + PIECE_VALUES[piece] - PIECE_VALUES[PAWN]
            } else {
                piece = m.played_piece();
                *PIECE_VALUES.get_unchecked(m.captured_piece())
            };

            // Examine the possible exchanges, fill the `gain` array.
            'exchange: while orig_square_bb != 0 {
                let current_gain = *gain.get_unchecked(depth);

                // Store a speculative value that will be used if the
                // captured piece happens to be defended.
                let speculative_gain: &mut Value = gain.get_unchecked_mut(depth + 1);
                *speculative_gain = *PIECE_VALUES.get_unchecked(piece) - current_gain;

                if max(-current_gain, *speculative_gain) < 0 {
                    // The side that made the last capture wins even if
                    // the captured piece happens to be defended. So, we
                    // stop here to save precious CPU cycles. Note that
                    // here we may happen to return an incorrect SEE
                    // value, but the sign will be correct, which is by
                    // far the most important information.
                    break;
                }

                // Register that capturing piece's origin square is now vacant.
                attackers_and_defenders &= !orig_square_bb;

                // Consider adding new attackers/defenders, now that
                // capturing piece's origin square is vacant.
                if orig_square_bb & may_xray != 0 {
                    let behind = self.board().occupied &
                                 *behind_blocker.get_unchecked(bitscan_1bit(orig_square_bb));
                    if behind & (straight_sliders | diag_sliders) != 0 {
                        attackers_and_defenders |=
                            match behind & straight_sliders &
                                  geometry.attacks_from_unsafe(ROOK, exchange_square, behind) {
                                0 => {
                                    // Not a straight slider, possibly a diagonal slider.
                                    behind & diag_sliders &
                                    geometry.attacks_from_unsafe(BISHOP, exchange_square, behind)
                                }
                                bb => {
                                    // A straight slider.
                                    bb
                                }
                            };
                    }
                }

                // Change the side to move.
                us ^= 1;

                // Find the next piece to enter the exchange. (The least
                // valuable piece belonging to the side to move.)
                let candidates = attackers_and_defenders & *color.get_unchecked(us);
                if candidates != 0 {
                    for p in (KING..PIECE_NONE).rev() {
                        let bb = candidates & piece_type[p];
                        if bb != 0 {
                            depth += 1;
                            piece = p;
                            orig_square_bb = ls1b(bb);
                            continue 'exchange;
                        }
                    }
                }
                break 'exchange;
            }

            // Negamax the `gain` array for the final static exchange
            // evaluation. (The `gain` array actually represents an unary
            // tree, at each node of which the player can either continue
            // the exchange or back off.)
            while depth > 0 {
                *gain.get_unchecked_mut(depth - 1) = -max(-*gain.get_unchecked(depth - 1),
                                                          *gain.get_unchecked(depth));
                depth -= 1;
            }
            gain[0]
        }
    }
}
<|endoftext|>


<commit_before>use typedef::*;

/// Stops the program and shuts down the vm
pub const HALT: Byte = 0x01;

/// Adds the two top most values and pushes the result back to the stack. This also removes the
/// processed values from the stack.
pub const ADD: Byte = 0x02;

/// Subtracts the first value on the stack from the second and pushes the result back to the stack.
/// This also removes the processed values from the stack.
pub const SUB: Byte = 0x03;

/// Adds the two top most values and pushes the result back to the stack. This also removes the
/// processed values from the stack.
pub const MUL: Byte = 0x04;

/// Divides the second value on the stack throuh the first one and pushes the result back to the
/// top of the stack. This also removes the processed values from the stack.
pub const DIV: Byte = 0x05;

/// Prints out the top most value on the stack
#[deprecated(since="0.1.0")]
pub const PRINT: Byte = 0x06;

/// Pushes a value (Word) to the stack
pub const PUSH: Byte = 0x07;

/// An unconditional jump to the specified address
pub const JMP: Byte = 0x08;

/// Jumps to the specified address if the top most value on the stack equals 0
pub const JZ: Byte = 0x09;

/// Jumps to the specified address if the top most value on the stack is not equal to 0
pub const JNZ: Byte = 0x0A;

/// Moves the specified value (Word) to the specified register (Address)
pub const MOVW: Byte = 0x0B;

/// Moves the specified value (SmallWord) to the specified register (Address)
pub const MOVS: Byte = 0x0C;

/// Moves the specified value (TinyWord) to the specified register (Address)
pub const MOVT: Byte = 0x0D;

/// Moves the specified value (Byte) to the specified register (Address)
pub const MOVB: Byte = 0x0E;

/// Moves the value in the specified buffer register (Address) to the otherwise specified buffer
/// register (Address)
pub const MOV: Byte = 0x0F;
<commit_msg>Added deprication notice<commit_after>use typedef::*;

/// Stops the program and shuts down the vm
pub const HALT: Byte = 0x01;

/// Adds the two top most values and pushes the result back to the stack. This also removes the
/// processed values from the stack.
pub const ADD: Byte = 0x02;

/// Subtracts the first value on the stack from the second and pushes the result back to the stack.
/// This also removes the processed values from the stack.
pub const SUB: Byte = 0x03;

/// Adds the two top most values and pushes the result back to the stack. This also removes the
/// processed values from the stack.
pub const MUL: Byte = 0x04;

/// Divides the second value on the stack throuh the first one and pushes the result back to the
/// top of the stack. This also removes the processed values from the stack.
pub const DIV: Byte = 0x05;

/// Prints out the top most value on the stack
#[deprecated(since="0.1.0", note="will be replaced soon")]
pub const PRINT: Byte = 0x06;

/// Pushes a value (Word) to the stack
pub const PUSH: Byte = 0x07;

/// An unconditional jump to the specified address
pub const JMP: Byte = 0x08;

/// Jumps to the specified address if the top most value on the stack equals 0
pub const JZ: Byte = 0x09;

/// Jumps to the specified address if the top most value on the stack is not equal to 0
pub const JNZ: Byte = 0x0A;

/// Moves the specified value (Word) to the specified register (Address)
pub const MOVW: Byte = 0x0B;

/// Moves the specified value (SmallWord) to the specified register (Address)
pub const MOVS: Byte = 0x0C;

/// Moves the specified value (TinyWord) to the specified register (Address)
pub const MOVT: Byte = 0x0D;

/// Moves the specified value (Byte) to the specified register (Address)
pub const MOVB: Byte = 0x0E;

/// Moves the value in the specified buffer register (Address) to the otherwise specified buffer
/// register (Address)
pub const MOV: Byte = 0x0F;
<|endoftext|>