<commit_before>use toml_edit;

#[derive(Debug, Hash, PartialEq, Eq, Clone)]
enum DependencySource {
    Version(String),
    Git(String),
    Path(String),
}

/// A dependency handled by Cargo
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub struct Dependency {
    /// The name of the dependency (as it is set in its `Cargo.toml` and known to crates.io)
    pub name: String,
    optional: bool,
    source: DependencySource,
}

impl Default for Dependency {
    fn default() -> Dependency {
        Dependency {
            name: "".into(),
            optional: false,
            source: DependencySource::Version("0.1.0".into()),
        }
    }
}

impl Dependency {
    /// Create a new dependency with a name
    pub fn new(name: &str) -> Dependency {
        Dependency {
            name: name.into(),
            ..Dependency::default()
        }
    }

    /// Set dependency to a given version
    pub fn set_version(mut self, version: &str) -> Dependency {
        self.source = DependencySource::Version(version.into());
        self
    }

    /// Set dependency to a given repository
    pub fn set_git(mut self, repo: &str) -> Dependency {
        self.source = DependencySource::Git(repo.into());
        self
    }

    /// Set dependency to a given path
    pub fn set_path(mut self, path: &str) -> Dependency {
        self.source = DependencySource::Path(path.into());
        self
    }

    /// Set whether the dependency is optional
    pub fn set_optional(mut self, opt: bool) -> Dependency {
        self.optional = opt;
        self
    }

    /// Get version of dependency
    pub fn version(&self) -> Option<&str> {
        if let DependencySource::Version(ref version) = self.source {
            Some(version)
        } else {
            None
        }
    }

    /// Convert dependency to TOML
    ///
    /// Returns a tuple with the dependency's name and either the version as a `String`
    /// or the path/git repository as an `InlineTable`.
    /// (If the dependency is set as `optional`, an `InlineTable` is returned in any case.)
    pub fn to_toml(&self) -> (String, toml_edit::Item) {
        let data: toml_edit::Item = match (self.optional, self.source.clone()) {
            // Extra short when version flag only
            (false, DependencySource::Version(v)) => toml_edit::value(v),
            // Other cases are represented as an inline tables
            (optional, source) => {
                let mut data = toml_edit::InlineTable::default();

                match source {
                    DependencySource::Version(v) => {
                        data.get_or_insert("version", v);
                    }
                    DependencySource::Git(v) => {
                        data.get_or_insert("git", v);
                    }
                    DependencySource::Path(v) => {
                        data.get_or_insert("path", v);
                    }
                }
                if self.optional {
                    data.get_or_insert("optional", optional);
                }

                data.fmt();
                toml_edit::value(toml_edit::Value::InlineTable(data))
            }
        };

        (self.name.clone(), data)
    }
}
<commit_msg>fix grammar<commit_after>use toml_edit;

#[derive(Debug, Hash, PartialEq, Eq, Clone)]
enum DependencySource {
    Version(String),
    Git(String),
    Path(String),
}

/// A dependency handled by Cargo
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub struct Dependency {
    /// The name of the dependency (as it is set in its `Cargo.toml` and known to crates.io)
    pub name: String,
    optional: bool,
    source: DependencySource,
}

impl Default for Dependency {
    fn default() -> Dependency {
        Dependency {
            name: "".into(),
            optional: false,
            source: DependencySource::Version("0.1.0".into()),
        }
    }
}

impl Dependency {
    /// Create a new dependency with a name
    pub fn new(name: &str) -> Dependency {
        Dependency {
            name: name.into(),
            ..Dependency::default()
        }
    }

    /// Set dependency to a given version
    pub fn set_version(mut self, version: &str) -> Dependency {
        self.source = DependencySource::Version(version.into());
        self
    }

    /// Set dependency to a given repository
    pub fn set_git(mut self, repo: &str) -> Dependency {
        self.source = DependencySource::Git(repo.into());
        self
    }

    /// Set dependency to a given path
    pub fn set_path(mut self, path: &str) -> Dependency {
        self.source = DependencySource::Path(path.into());
        self
    }

    /// Set whether the dependency is optional
    pub fn set_optional(mut self, opt: bool) -> Dependency {
        self.optional = opt;
        self
    }

    /// Get version of dependency
    pub fn version(&self) -> Option<&str> {
        if let DependencySource::Version(ref version) = self.source {
            Some(version)
        } else {
            None
        }
    }

    /// Convert dependency to TOML
    ///
    /// Returns a tuple with the dependency's name and either the version as a `String`
    /// or the path/git repository as an `InlineTable`.
    /// (If the dependency is set as `optional`, an `InlineTable` is returned in any case.)
    pub fn to_toml(&self) -> (String, toml_edit::Item) {
        let data: toml_edit::Item = match (self.optional, self.source.clone()) {
            // Extra short when version flag only
            (false, DependencySource::Version(v)) => toml_edit::value(v),
            // Other cases are represented as an inline table
            (optional, source) => {
                let mut data = toml_edit::InlineTable::default();

                match source {
                    DependencySource::Version(v) => {
                        data.get_or_insert("version", v);
                    }
                    DependencySource::Git(v) => {
                        data.get_or_insert("git", v);
                    }
                    DependencySource::Path(v) => {
                        data.get_or_insert("path", v);
                    }
                }
                if self.optional {
                    data.get_or_insert("optional", optional);
                }

                data.fmt();
                toml_edit::value(toml_edit::Value::InlineTable(data))
            }
        };

        (self.name.clone(), data)
    }
}
<|endoftext|>


<commit_before>extern crate syn;

use std::env;
use std::fs::File;
use std::io::{Write, BufWriter};
use syn::DeriveInput;

pub fn generate_elm(_: &DeriveInput) {
    let mut path = env::current_dir().unwrap();
    path.push("generated/test.txt");

    let file = File::create(path).unwrap();
    let ref mut w = BufWriter::new(file);
    w.write("Hello, World!".as_bytes()).unwrap();
}
<commit_msg>Write a test file with the name of the struct<commit_after>extern crate syn;

use std::env;
use std::fs::File;
use std::io::{Write, BufWriter};
use syn::DeriveInput;

pub fn generate_elm(ast: &DeriveInput) {
    let mut path = env::current_dir().unwrap();
    let name = &ast.ident;
    path.push(format!("generated/{}.elm", name));

    let file = File::create(path).unwrap();
    let ref mut w = BufWriter::new(file);
    w.write("Hello, World!".as_bytes()).unwrap();
}
<|endoftext|>


<commit_before>use futures;
use futures::future::{Future};
use futures::future;
use futures::{Stream, Sink};
use std::cmp;
use std::collections::vec_deque::VecDeque;
use std::default::Default;
use std::net::SocketAddr;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio_core::net::TcpStream;
use tokio_core::reactor;
use tokio_core::reactor::Handle;
use tokio_io::AsyncRead;
use tokio_io::codec::Framed;

use datastore::DataStore;
use errors::*;
use fillable::*;
use manifest::ManifestWithFile;
use metainfo::{MetaInfo, InfoHash};
use peer_protocol::{PeerID, Message, BitTorrentPeerCodec};
use peer_protocol;
use tracker::TrackerClient;
use util::{tcp_connect2, BxFuture, FutureEnhanced, VecDequeStream, mkdirp_for_file};

type PeerFramed = Framed<TcpStream, BitTorrentPeerCodec>;

struct DownloaderState {
    info: MetaInfo,
    datastore: DataStore,
    manifest: ManifestWithFile,
    peer_state: PeerState,
    blah_state: BlahState,
}

type AM<T> = Arc<Mutex<T>>;

pub fn start<P: AsRef<Path>>(info: MetaInfo, peer_id: PeerID, store_path: P, manifest_path: P) -> Result<()> {
    let mut core = reactor::Core::new()?;
    let handle = core.handle();

    mkdirp_for_file(&store_path)?;
    mkdirp_for_file(&manifest_path)?;
    let datastore = DataStore::create_or_open(&info, store_path)?;
    let manifest = ManifestWithFile::load_or_new(info.clone(), manifest_path)?;
    let mut tc = TrackerClient::new(info.clone(), peer_id.clone())?;

    let tracker_res = tc.easy_start()?;
    println!("tracker res: {:#?}", tracker_res);
    if let Some(reason) = tracker_res.failure_reason {
        bail!("tracker failed: {}", reason);
    }

    if tracker_res.peers.is_empty() {
        bail!("tracker returned no peers");
    }

    let num_pieces = info.num_pieces() as u64;
    let info_hash = info.info_hash.clone();

    let n_start_peers = cmp::min(1, tracker_res.peers.len());

    let dstate = DownloaderState {
        info: info,
        datastore: datastore,
        manifest: manifest,
        peer_state: PeerState::new(num_pieces),
        blah_state: BlahState::default(),
    };

    let dstate_c = Arc::new(Mutex::new(dstate));

    let mut top_futures: Vec<BxFuture<(), Error>> = Vec::new();

    for peer in tracker_res.peers[..n_start_peers].iter() {
        let dstate_c = dstate_c.clone();
        let handle = handle.clone();
        let f = connect_peer(peer.address, info_hash.clone(), peer_id.clone(), &handle)
            .and_then(move |(stream, remote_peer_id)| drive_peer(dstate_c, &handle, stream, remote_peer_id))
            .bxed();
        top_futures.push(f);
    }

    let future_root = future::join_all(top_futures);

    core.run(future_root)?;
    Ok(())
}

/// Connect to a remote peer
fn connect_peer(addr: SocketAddr, info_hash: InfoHash, peer_id: PeerID, handle: &reactor::Handle) -> BxFuture<(PeerFramed, PeerID), Error> {
    let info_hash2 = info_hash.clone();

    println!("connecting to {} ...", addr);
    tcp_connect2(&addr, Duration::from_millis(3000), &handle)
        .chain_err(|| "peer connection failed")
        .and_then(move |stream| {
            println!("connected");
            peer_protocol::handshake_send_async(stream, info_hash.clone(), peer_id.clone())
        })
        .and_then(|stream| peer_protocol::handshake_read_1_async(stream))
        .and_then(move |(stream, remote_info_hash)| {
            println!("remote info hash: {:?}", remote_info_hash);
            if remote_info_hash != info_hash2 {
                bail!("peer info hash mismatch peer:{:?} me:{:?}",
                      remote_info_hash,
                      info_hash2);
            }
            Ok(stream)
        })
        .and_then(|stream| peer_protocol::handshake_read_2_async(stream).map(move |(stream, remote_peer_id)| (stream, remote_peer_id)))
        .and_then(|(stream, remote_peer_id)| {
            println!("remote peer id: {:?}", remote_peer_id);

            // let stream: Framed<TcpStream,BitTorrentPeerCodec> = stream.framed(BitTorrentPeerCodec);
            let stream: PeerFramed = stream.framed(BitTorrentPeerCodec);
            Ok((stream, remote_peer_id))
        })
        .bxed()
}

// /// One step of the main loop.
// fn loop_step(lstate: LoopState) -> BxFuture<future::Loop<String, LoopState>, Error> {
//     use futures::future::Loop::{Break, Continue};
//     let (stream, mut dstate) = lstate;
//     // Note: There are many `bxed` calls in here because match arms must return the same type.
//     // And the long long types produced by future chaining are not equivalent.
//     // So the boxing turns them into trait objects implementing the same specified Future.
//     stream.into_future()
//         .map_err(|(err, _stream)| err)
//         .and_then(move |(omsg, stream)| {
//             match omsg {
//                 None => future::ok(Break("event stream ended".to_owned())).bxed(),
//                 Some(msg) => {
//                     match handle_peer_message(msg, &mut dstate) {
//                         Err(err) => future::err(err).bxed(),
//                         Ok(outs) => {
//                             let n_outs = outs.len();
//                             stream.send_all(VecDequeStream::<Message, Error>::new(outs))
//                                 .map(move |(stream, _)| {
//                                     println!("sent {}", n_outs);
//                                     Continue((stream, dstate))
//                                 })
//                                 .bxed()
//                         }
//                     }
//                 }
//             }
//         })
//         .bxed()
// }

enum HandlePeerMessageRes {
    Pass,
    Reply(VecDeque<Message>),
    Close,
}

fn drive_peer(dstate_c: AM<DownloaderState>, handle: &Handle, stream: PeerFramed, remote_peer_id: PeerID) -> BxFuture<(), Error> {
    let (peer_tx, peer_rx) = stream.split();

    // Separate send from receive so that the listener doesn't block all the time
    let (buf_tx, buf_rx) = futures::sync::mpsc::channel::<Message>(5);

    // debugging type assertions
    // let _: &Stream<Item = Message, Error = ()> = &buf_rx;
    // let _: &Sink<SinkItem = Message, SinkError = Error> = &peer_tx;
    // let _: &Stream<Item = Message, Error = Error> = &buf_rx.map_err(|()| "lol".into());
    // let _: &Future<Item = (_, _), Error = Error> = &peer_tx.send_all(buf_rx.map_err(|()| "lol".into()));

    // Process the send channel
    handle.spawn(peer_tx.send_all(buf_rx.map_err(|()| Into::<Error>::into("peer send failed")))
        .map(|(_sink, _stream)| ())
        .map_err(|e| {
            println!("warning: send to peer failed: {}", e);
        }));

    // type PeerStream = Box<Stream<Item = Message, Error = Error>>;
    // type PeerSink = Box<Sink<SinkItem = Message, SinkError = Error>>;
    // type LoopState = (AM<DownloaderState>, PeerStream, PeerSink);

    struct LoopState<S, U>
        where S: Stream<Item = Message, Error = Error>,
              U: Sink<SinkItem = Message, SinkError = Error>
    {
        dstate_c: AM<DownloaderState>,
        peer_rx: S,
        peer_tx: U,
    }

    let init = LoopState {
        dstate_c: dstate_c,
        peer_rx: peer_rx,
        peer_tx: buf_tx.sink_map_err(|send_err| {
            format!("error sending message: {}", send_err).into()
        }),
    };

    use futures::future::Loop;
    future::loop_fn(init,
                    |LoopState { dstate_c, peer_rx, peer_tx }| -> BxFuture<Loop<(), LoopState<_, _>>, Error> {
        peer_rx.into_future()
            .map_err(|(err, _stream)| err)
            .and_then(|(item, peer_rx)| -> BxFuture<Loop<(), LoopState<_, _>>, Error> {
                match item {
                    Some(msg) => {
                        let cmd: Result<HandlePeerMessageRes> = {
                            let mut dstate = dstate_c.lock().unwrap();
                            handle_peer_message(&mut dstate, &msg)
                        };
                        use self::HandlePeerMessageRes::*;
                        match cmd {
                            Ok(Pass) => future::ok(Loop::Continue(LoopState { dstate_c, peer_rx, peer_tx })).bxed(),
                            Ok(Reply(outs)) => {
                                peer_tx.send_all(VecDequeStream::<Message, Error>::new(outs))
                                    .map(move |(peer_tx, _)| Loop::Continue(LoopState { dstate_c, peer_rx, peer_tx }))
                                    .bxed()
                            }
                            Ok(Close) => {
                                // println!("closing peer connection: {:?}", remote_peer_id.clone());
                                println!("closing peer connection");
                                future::ok(Loop::Break(())).bxed()
                            }
                            Err(err) => {
                                println!("closing peer due to error: {:?}", err);
                                future::ok(Loop::Break(())).bxed()
                            }
                        }
                    }
                    None => {
                        println!("peer hung up");
                        future::ok(Loop::Break(())).bxed()
                    }
                }
            }).bxed()
    })
        .bxed()
}

/// One synchronous step.
/// Returns messages to send.
fn handle_peer_message(dstate: &mut DownloaderState, msg: &Message) -> Result<HandlePeerMessageRes> {
    use self::HandlePeerMessageRes::*;

    let mut outs = VecDeque::new();
    println!("recv message {}: {}",
             dstate.blah_state.nreceived,
             msg.summarize());
    dstate.blah_state.nreceived += 1;
    match msg {
        &Message::KeepAlive => {}
        &Message::Choke => dstate.peer_state.peer_choking = true,
        &Message::Unchoke => dstate.peer_state.peer_choking = false,
        &Message::Interested => dstate.peer_state.peer_interested = true,
        &Message::NotInterested => dstate.peer_state.peer_interested = false,
        &Message::Bitfield { ref bits } => {
            if bits.len() < dstate.info.num_pieces() {
                bail!("bitfield has less bits {} than pieces {}",
                      bits.len(),
                      dstate.info.num_pieces());
            }
            let mut i_start = 0;
            let mut in_interval = false;
            for b in 0..dstate.info.num_pieces() {
                if bits[b] && !in_interval {
                    i_start = b;
                    in_interval = true;
                } else if !bits[b] && in_interval {
                    dstate.peer_state.has.add(i_start as u64, b as u64)?;
                    in_interval = false;
                }
            }
            if in_interval {
                dstate.peer_state.has.add(i_start as u64, dstate.info.num_pieces() as u64)?;
            }
        }
        &Message::Have { piece } => {
            dstate.peer_state.has.add(piece as u64, piece as u64 + 1)?;
        }
        &Message::Request { .. } => {
            bail!("not implemented");
        }
        &Message::Piece { piece, offset, ref block } => {
            dstate.datastore.write_block(piece as u64, offset as u64, &block)?;
            let newly_filled = dstate.manifest.manifest.add_block(piece as u64, offset as u64, block.len() as u64)?;
            for p in newly_filled {
                let expected_hash = dstate.info.piece_hashes[p as usize].clone();
                println!("filled piece: {}", p);
                if let Some(verified) = dstate.datastore.verify_piece(p, expected_hash)? {
                    println!("verified piece: {}", verified.piece);
                    dstate.manifest.manifest.mark_verified(verified)?;
                } else {
                    println!("flunked piece: {}", p);
                    dstate.manifest.manifest.remove_piece(p)?;
                }
            }

            dstate.manifest.store()?;
            dstate.blah_state.waiting = false;
        }
        &Message::Cancel { .. } => bail!("not implemented"),
        &Message::Port { .. } => {}
    }
    if dstate.blah_state.nreceived >= 1 && dstate.peer_state.am_choking {
        let out = Message::Unchoke {};
        println!("sending message: {:?}", out);
        dstate.peer_state.am_choking = false;
        outs.push_back(out);
    }
    if dstate.blah_state.nreceived >= 1 && !dstate.peer_state.am_interested {
        let out = Message::Interested {};
        println!("sending message: {:?}", out);
        dstate.peer_state.am_interested = true;
        outs.push_back(out);
    }
    if !dstate.blah_state.waiting && !dstate.peer_state.peer_choking && dstate.peer_state.am_interested {
        match dstate.manifest.manifest.next_desired_block() {
            None => {
                // No more blocks needed! Unless something fails verification.
                for piece in dstate.manifest.manifest.needs_verify() {
                    let expected_hash = dstate.info.piece_hashes[piece as usize].clone();
                    println!("verifying piece: {}", piece);
                    if let Some(verified) = dstate.datastore.verify_piece(piece, expected_hash)? {
                        println!("verified piece: {}", verified.piece);
                        dstate.manifest.manifest.mark_verified(verified)?;
                    } else {
                        println!("flunked piece: {}", piece);
                        dstate.manifest.manifest.remove_piece(piece)?;
                    }
                }
                dstate.manifest.store()?;

                if dstate.manifest.manifest.all_verified() {
                    println!("all pieces verified!");
                    return Ok(Close);
                }
            }
            Some(desire) => {
                let out = Message::Request {
                    piece: desire.piece,
                    offset: desire.offset,
                    length: desire.length,
                };
                println!("sending message: {:?}", out);
                dstate.blah_state.waiting = true;
                outs.push_back(out);
            }
        }
    }

    if outs.len() > 0 {
        Ok(Reply(outs))
    } else {
        Ok(Pass)
    }
}

#[derive(Debug)]
pub struct PeerState {
    /// Peer is interested in this client
    peer_interested: bool,
    /// Peer is choking this client
    peer_choking: bool,

    am_interested: bool,
    am_choking: bool,

    has: Fillable,
}

#[derive(Debug, Default)]
pub struct BlahState {
    nreceived: u64,
    requested: bool,
    waiting: bool,
}

impl PeerState {
    fn new(num_pieces: u64) -> Self {
        PeerState {
            peer_interested: false,
            peer_choking: true,
            am_interested: false,
            am_choking: true,
            has: Fillable::new(num_pieces),
        }
    }
}
<commit_msg>clean<commit_after>use futures;
use futures::future::{Future};
use futures::future;
use futures::{Stream, Sink};
use std::cmp;
use std::collections::vec_deque::VecDeque;
use std::default::Default;
use std::net::SocketAddr;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio_core::net::TcpStream;
use tokio_core::reactor;
use tokio_core::reactor::Handle;
use tokio_io::AsyncRead;
use tokio_io::codec::Framed;

use datastore::DataStore;
use errors::*;
use fillable::*;
use manifest::ManifestWithFile;
use metainfo::{MetaInfo, InfoHash};
use peer_protocol::{PeerID, Message, BitTorrentPeerCodec};
use peer_protocol;
use tracker::TrackerClient;
use util::{tcp_connect2, BxFuture, FutureEnhanced, VecDequeStream, mkdirp_for_file};

type PeerFramed = Framed<TcpStream, BitTorrentPeerCodec>;

struct DownloaderState {
    info: MetaInfo,
    datastore: DataStore,
    manifest: ManifestWithFile,
    peer_state: PeerState,
    blah_state: BlahState,
}

type AM<T> = Arc<Mutex<T>>;

pub fn start<P: AsRef<Path>>(info: MetaInfo, peer_id: PeerID, store_path: P, manifest_path: P) -> Result<()> {
    let mut core = reactor::Core::new()?;
    let handle = core.handle();

    mkdirp_for_file(&store_path)?;
    mkdirp_for_file(&manifest_path)?;
    let datastore = DataStore::create_or_open(&info, store_path)?;
    let manifest = ManifestWithFile::load_or_new(info.clone(), manifest_path)?;
    let mut tc = TrackerClient::new(info.clone(), peer_id.clone())?;

    let tracker_res = tc.easy_start()?;
    println!("tracker res: {:#?}", tracker_res);
    if let Some(reason) = tracker_res.failure_reason {
        bail!("tracker failed: {}", reason);
    }

    if tracker_res.peers.is_empty() {
        bail!("tracker returned no peers");
    }

    let num_pieces = info.num_pieces() as u64;
    let info_hash = info.info_hash.clone();

    let n_start_peers = cmp::min(1, tracker_res.peers.len());

    let dstate = DownloaderState {
        info: info,
        datastore: datastore,
        manifest: manifest,
        peer_state: PeerState::new(num_pieces),
        blah_state: BlahState::default(),
    };

    let dstate_c = Arc::new(Mutex::new(dstate));

    let mut top_futures: Vec<BxFuture<(), Error>> = Vec::new();

    for peer in tracker_res.peers[..n_start_peers].iter() {
        let dstate_c = dstate_c.clone();
        let handle = handle.clone();
        let f = connect_peer(peer.address, info_hash.clone(), peer_id.clone(), &handle)
            .and_then(move |(stream, remote_peer_id)| drive_peer(dstate_c, &handle, stream, remote_peer_id))
            .bxed();
        top_futures.push(f);
    }

    let future_root = future::join_all(top_futures);

    core.run(future_root)?;
    Ok(())
}

/// Connect to a remote peer
fn connect_peer(addr: SocketAddr, info_hash: InfoHash, peer_id: PeerID, handle: &reactor::Handle) -> BxFuture<(PeerFramed, PeerID), Error> {
    let info_hash2 = info_hash.clone();

    println!("connecting to {} ...", addr);
    tcp_connect2(&addr, Duration::from_millis(3000), &handle)
        .chain_err(|| "peer connection failed")
        .and_then(move |stream| {
            println!("connected");
            peer_protocol::handshake_send_async(stream, info_hash.clone(), peer_id.clone())
        })
        .and_then(|stream| peer_protocol::handshake_read_1_async(stream))
        .and_then(move |(stream, remote_info_hash)| {
            println!("remote info hash: {:?}", remote_info_hash);
            if remote_info_hash != info_hash2 {
                bail!("peer info hash mismatch peer:{:?} me:{:?}",
                      remote_info_hash,
                      info_hash2);
            }
            Ok(stream)
        })
        .and_then(|stream| peer_protocol::handshake_read_2_async(stream).map(move |(stream, remote_peer_id)| (stream, remote_peer_id)))
        .and_then(|(stream, remote_peer_id)| {
            println!("remote peer id: {:?}", remote_peer_id);

            // let stream: Framed<TcpStream,BitTorrentPeerCodec> = stream.framed(BitTorrentPeerCodec);
            let stream: PeerFramed = stream.framed(BitTorrentPeerCodec);
            Ok((stream, remote_peer_id))
        })
        .bxed()
}

enum HandlePeerMessageRes {
    Pass,
    Reply(VecDeque<Message>),
    Close,
}

fn drive_peer(dstate_c: AM<DownloaderState>, handle: &Handle, stream: PeerFramed, remote_peer_id: PeerID) -> BxFuture<(), Error> {
    let (peer_tx, peer_rx) = stream.split();

    // Separate send from receive so that the listener doesn't block all the time
    let (buf_tx, buf_rx) = futures::sync::mpsc::channel::<Message>(5);

    // debugging type assertions
    // let _: &Stream<Item = Message, Error = ()> = &buf_rx;
    // let _: &Sink<SinkItem = Message, SinkError = Error> = &peer_tx;
    // let _: &Stream<Item = Message, Error = Error> = &buf_rx.map_err(|()| "lol".into());
    // let _: &Future<Item = (_, _), Error = Error> = &peer_tx.send_all(buf_rx.map_err(|()| "lol".into()));

    // Process the send channel
    handle.spawn(peer_tx.send_all(buf_rx.map_err(|()| Into::<Error>::into("peer send failed")))
        .map(|(_sink, _stream)| ())
        .map_err(|e| {
            println!("warning: send to peer failed: {}", e);
        }));

    // type PeerStream = Box<Stream<Item = Message, Error = Error>>;
    // type PeerSink = Box<Sink<SinkItem = Message, SinkError = Error>>;
    // type LoopState = (AM<DownloaderState>, PeerStream, PeerSink);

    struct LoopState<S, U>
        where S: Stream<Item = Message, Error = Error>,
              U: Sink<SinkItem = Message, SinkError = Error>
    {
        dstate_c: AM<DownloaderState>,
        peer_rx: S,
        peer_tx: U,
    }

    let init = LoopState {
        dstate_c: dstate_c,
        peer_rx: peer_rx,
        peer_tx: buf_tx.sink_map_err(|send_err| {
            format!("error sending message: {}", send_err).into()
        }),
    };

    use futures::future::Loop;
    future::loop_fn(init,
                    |LoopState { dstate_c, peer_rx, peer_tx }| -> BxFuture<Loop<(), LoopState<_, _>>, Error> {
        peer_rx.into_future()
            .map_err(|(err, _stream)| err)
            .and_then(|(item, peer_rx)| -> BxFuture<Loop<(), LoopState<_, _>>, Error> {
                match item {
                    Some(msg) => {
                        let cmd: Result<HandlePeerMessageRes> = {
                            let mut dstate = dstate_c.lock().unwrap();
                            handle_peer_message(&mut dstate, &msg)
                        };
                        use self::HandlePeerMessageRes::*;
                        match cmd {
                            Ok(Pass) => future::ok(Loop::Continue(LoopState { dstate_c, peer_rx, peer_tx })).bxed(),
                            Ok(Reply(outs)) => {
                                peer_tx.send_all(VecDequeStream::<Message, Error>::new(outs))
                                    .map(move |(peer_tx, _)| Loop::Continue(LoopState { dstate_c, peer_rx, peer_tx }))
                                    .bxed()
                            }
                            Ok(Close) => {
                                // println!("closing peer connection: {:?}", remote_peer_id.clone());
                                println!("closing peer connection");
                                future::ok(Loop::Break(())).bxed()
                            }
                            Err(err) => {
                                println!("closing peer due to error: {:?}", err);
                                future::ok(Loop::Break(())).bxed()
                            }
                        }
                    }
                    None => {
                        println!("peer hung up");
                        future::ok(Loop::Break(())).bxed()
                    }
                }
            }).bxed()
    })
        .bxed()
}

/// One synchronous step.
/// Returns messages to send.
fn handle_peer_message(dstate: &mut DownloaderState, msg: &Message) -> Result<HandlePeerMessageRes> {
    use self::HandlePeerMessageRes::*;

    let mut outs = VecDeque::new();
    println!("recv message {}: {}",
             dstate.blah_state.nreceived,
             msg.summarize());
    dstate.blah_state.nreceived += 1;
    match msg {
        &Message::KeepAlive => {}
        &Message::Choke => dstate.peer_state.peer_choking = true,
        &Message::Unchoke => dstate.peer_state.peer_choking = false,
        &Message::Interested => dstate.peer_state.peer_interested = true,
        &Message::NotInterested => dstate.peer_state.peer_interested = false,
        &Message::Bitfield { ref bits } => {
            if bits.len() < dstate.info.num_pieces() {
                bail!("bitfield has less bits {} than pieces {}",
                      bits.len(),
                      dstate.info.num_pieces());
            }
            let mut i_start = 0;
            let mut in_interval = false;
            for b in 0..dstate.info.num_pieces() {
                if bits[b] && !in_interval {
                    i_start = b;
                    in_interval = true;
                } else if !bits[b] && in_interval {
                    dstate.peer_state.has.add(i_start as u64, b as u64)?;
                    in_interval = false;
                }
            }
            if in_interval {
                dstate.peer_state.has.add(i_start as u64, dstate.info.num_pieces() as u64)?;
            }
        }
        &Message::Have { piece } => {
            dstate.peer_state.has.add(piece as u64, piece as u64 + 1)?;
        }
        &Message::Request { .. } => {
            bail!("not implemented");
        }
        &Message::Piece { piece, offset, ref block } => {
            dstate.datastore.write_block(piece as u64, offset as u64, &block)?;
            let newly_filled = dstate.manifest.manifest.add_block(piece as u64, offset as u64, block.len() as u64)?;
            for p in newly_filled {
                let expected_hash = dstate.info.piece_hashes[p as usize].clone();
                println!("filled piece: {}", p);
                if let Some(verified) = dstate.datastore.verify_piece(p, expected_hash)? {
                    println!("verified piece: {}", verified.piece);
                    dstate.manifest.manifest.mark_verified(verified)?;
                } else {
                    println!("flunked piece: {}", p);
                    dstate.manifest.manifest.remove_piece(p)?;
                }
            }

            dstate.manifest.store()?;
            dstate.blah_state.waiting = false;
        }
        &Message::Cancel { .. } => bail!("not implemented"),
        &Message::Port { .. } => {}
    }
    if dstate.blah_state.nreceived >= 1 && dstate.peer_state.am_choking {
        let out = Message::Unchoke {};
        println!("sending message: {:?}", out);
        dstate.peer_state.am_choking = false;
        outs.push_back(out);
    }
    if dstate.blah_state.nreceived >= 1 && !dstate.peer_state.am_interested {
        let out = Message::Interested {};
        println!("sending message: {:?}", out);
        dstate.peer_state.am_interested = true;
        outs.push_back(out);
    }
    if !dstate.blah_state.waiting && !dstate.peer_state.peer_choking && dstate.peer_state.am_interested {
        match dstate.manifest.manifest.next_desired_block() {
            None => {
                // No more blocks needed! Unless something fails verification.
                for piece in dstate.manifest.manifest.needs_verify() {
                    let expected_hash = dstate.info.piece_hashes[piece as usize].clone();
                    println!("verifying piece: {}", piece);
                    if let Some(verified) = dstate.datastore.verify_piece(piece, expected_hash)? {
                        println!("verified piece: {}", verified.piece);
                        dstate.manifest.manifest.mark_verified(verified)?;
                    } else {
                        println!("flunked piece: {}", piece);
                        dstate.manifest.manifest.remove_piece(piece)?;
                    }
                }
                dstate.manifest.store()?;

                if dstate.manifest.manifest.all_verified() {
                    println!("all pieces verified!");
                    return Ok(Close);
                }
            }
            Some(desire) => {
                let out = Message::Request {
                    piece: desire.piece,
                    offset: desire.offset,
                    length: desire.length,
                };
                println!("sending message: {:?}", out);
                dstate.blah_state.waiting = true;
                outs.push_back(out);
            }
        }
    }

    if outs.len() > 0 {
        Ok(Reply(outs))
    } else {
        Ok(Pass)
    }
}

#[derive(Debug)]
pub struct PeerState {
    /// Peer is interested in this client
    peer_interested: bool,
    /// Peer is choking this client
    peer_choking: bool,

    am_interested: bool,
    am_choking: bool,

    has: Fillable,
}

#[derive(Debug, Default)]
pub struct BlahState {
    nreceived: u64,
    requested: bool,
    waiting: bool,
}

impl PeerState {
    fn new(num_pieces: u64) -> Self {
        PeerState {
            peer_interested: false,
            peer_choking: true,
            am_interested: false,
            am_choking: true,
            has: Fillable::new(num_pieces),
        }
    }
}
<|endoftext|>


<commit_before>//! Facilities for implementing chess engines.

pub mod time_manager;

use std::collections::VecDeque;
use std::ops::Deref;
use std::sync::Arc;
use std::time::{SystemTime, Duration};
use std::cmp::min;
use std::io;
use uci::*;
use search::*;
use self::time_manager::*;

const NAME: &'static str = "Alcibiades";
const AUTHOR: &'static str = "Evgeni Pandurski";
const VERSION: &'static str = "0.1";
const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

/// Serves UCI commands until a "quit" command is received.
///
/// The current thread will block until the UCI session is closed.
///
/// Returns `Err` if the handshake was unsuccessful, or if an IO error
/// occurred.
pub fn run_server<S: SearchExecutor<ReportData = Vec<Variation>>>() -> io::Result<()> {
    run_engine::<Engine<S>>()
}

/// Represents a condition for terminating the search.
enum PlayWhen {
    TimeManagement(TimeManager), // Stop when the time manager says.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(u64), // Stop when the given number of nodes has been searched.
    Depth(Depth), // Stop when the given search depth has been completed.
    Never, // An infinite search.
}

/// Implements `UciEngine` trait.
struct Engine<S: SearchExecutor<ReportData = Vec<Variation>>> {
    tt: Arc<S::HashTable>,
    position: S::SearchNode,
    searcher: S,
    queue: VecDeque<EngineReply>,

    // The starting time of the current/last search.
    started_at: SystemTime,

    // The status of the current/last search.
    status: SearchStatus,

    // Helps the engine decide when to send periodic progress reports.
    silent_since: SystemTime,

    // Whether the engine is thinking in pondering mode at the moment.
    is_pondering: bool,

    // Tells the engine when it must stop thinking and play the best move.
    play_when: PlayWhen,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> UciEngine for Engine<S> {
    fn name() -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author() -> String {
        AUTHOR.to_string()
    }

    fn options() -> Vec<(String, OptionDescription)> {
        // Add up all suported options.
        let mut options = vec![
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 64 * 1024, default: 16 }),
            ("Clear Hash".to_string(), OptionDescription::Button),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ];
        options.extend(S::options());

        // Remove duplicated options.
        options.sort_by(|a, b| a.0.cmp(&b.0));
        let mut options_dedup = vec![];
        let mut prev_name = String::from("");
        for o in options.drain(..) {
            if o.0 == prev_name {
                continue;
            }
            prev_name = o.0.clone();
            options_dedup.push(o);
        }
        options_dedup
    }

    fn new(tt_size_mb: Option<usize>) -> Engine<S> {
        let tt = Arc::new(S::HashTable::new(tt_size_mb));
        Engine {
            tt: tt.clone(),
            position: S::SearchNode::from_history(START_FEN, &mut vec![].into_iter()).ok().unwrap(),
            searcher: S::new(tt),
            queue: VecDeque::new(),
            started_at: SystemTime::now(),
            status: SearchStatus {
                done: true,
                depth: 0,
                searched_nodes: 0,
                duration_millis: 0,
                nps: 0,
            },
            silent_since: SystemTime::now(),
            is_pondering: false,
            play_when: PlayWhen::Never,
            pondering_is_allowed: false,
        }
    }

    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                // TODO: Can we remove this?
                self.pondering_is_allowed = value == "true";
            }
            "Hash" => {
                // We do not support re-sizing of the transposition
                // table once the engine has been started.
                return;
            }
            "Clear Hash" => {
                self.tt.clear();
            }
            _ => (),
        }
        S::set_option(name, value);
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if let Ok(p) = S::SearchNode::from_history(fen, moves) {
            self.position = p;
        }
    }

    fn go(&mut self, params: GoParams) {
        self.terminate();

        // TODO: What should we do with "mate"?
        let GoParams { mut searchmoves,
                       ponder,
                       wtime,
                       btime,
                       winc,
                       binc,
                       movestogo,
                       depth,
                       nodes,
                       movetime,
                       infinite,
                       .. } = params;

        // Validate `searchmoves`.
        let searchmoves = {
            let mut moves = vec![];
            let legal_moves = self.position.legal_moves();
            if !searchmoves.is_empty() {
                searchmoves.sort();
                for m in legal_moves.iter() {
                    if searchmoves.binary_search(&m.notation()).is_ok() {
                        moves.push(*m);
                    }
                }
            };
            if moves.is_empty() {
                legal_moves
            } else {
                moves
            }
        };

        // Start a new search.
        self.tt.new_search();
        self.started_at = SystemTime::now();
        self.status = SearchStatus {
            done: false,
            depth: 0,
            searched_nodes: 0,
            duration_millis: 0,
            ..self.status
        };
        self.silent_since = SystemTime::now();
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(min(depth.unwrap(), DEPTH_MAX as u64) as Depth)
        } else {
            PlayWhen::TimeManagement(TimeManager::new(self.position.board().to_move,
                                                      self.pondering_is_allowed,
                                                      wtime,
                                                      btime,
                                                      winc,
                                                      binc,
                                                      movestogo))
        };
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: self.position.clone(),
            depth: DEPTH_MAX,
            lower_bound: VALUE_MIN,
            upper_bound: VALUE_MAX,
            searchmoves: searchmoves,
        });
    }

    fn ponder_hit(&mut self) {
        if self.status.done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.terminate();
        self.queue_best_move();
    }

    fn wait_for_reply(&mut self, duration: Duration) -> Option<EngineReply> {
        if self.queue.is_empty() {
            let done = self.status.done;

            // Wait for `search_thread` to do some work, and hopefully
            // update its status. (We must do this even when the
            // search is done -- in that case the next line will just
            // yield the CPU to another process.)
            self.wait_status_update(duration);

            if !done {
                let &SearchStatus { done, depth, searched_nodes, duration_millis, .. } =
                    &self.status;

                // Check if we must play now.
                if !self.is_pondering &&
                   match self.play_when {
                    PlayWhen::TimeManagement(ref tm) => done || tm.must_play(),
                    PlayWhen::MoveTime(t) => done || duration_millis >= t,
                    PlayWhen::Nodes(n) => done || searched_nodes >= n,
                    PlayWhen::Depth(d) => done || depth >= d,
                    PlayWhen::Never => false,
                } {
                    self.stop();
                }
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.terminate();
    }
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> Engine<S> {
    /// Adds a progress report message to the queue.
    fn queue_progress_report(&mut self) {
        let SearchStatus { ref depth, ref searched_nodes, ref nps, .. } = self.status;
        self.queue.push_back(EngineReply::Info(vec![
            InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
            InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
            InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
        ]));
        self.silent_since = SystemTime::now();
    }

    /// Adds a message containing the current (multi)PV to the queue.
    fn queue_pv(&mut self, variations: &Vec<Variation>) {
        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, ref nps, .. } =
            self.status;
        for (i, &Variation { ref moves, value, bound }) in variations.iter().enumerate() {
            let bound_suffix = match bound {
                BOUND_EXACT => "",
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                _ => panic!("unexpected bound type"),
            };
            let mut moves_string = String::new();
            for m in moves {
                moves_string.push_str(&m.notation());
                moves_string.push(' ');
            }
            self.queue.push_back(EngineReply::Info(vec![
                InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
                InfoItem { info_type: "multipv".to_string(), data: format!("{}", i + 1) },
                InfoItem { info_type: "score".to_string(), data: format!("cp {}{}", value, bound_suffix) },
                InfoItem { info_type: "time".to_string(), data: format!("{}", duration_millis) },
                InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
                InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
                InfoItem { info_type: "pv".to_string(), data: moves_string },
            ]));
        }
        self.silent_since = SystemTime::now();
    }

    /// Adds a message containing the current best move to the queue.
    fn queue_best_move(&mut self) {
        let pv = extract_pv(self.tt.deref(), &self.position, 2);
        let best_move = if let Some(m) = pv.moves.get(0) {
            m.notation()
        } else {
            // If the PV is empty, pick the first legal move.
            self.position.legal_moves().get(0).map_or("0000".to_string(), |m| m.notation())
        };
        self.queue.push_back(EngineReply::BestMove {
            best_move: best_move,
            ponder_move: pv.moves.get(1).map(|m| m.notation()),
        });
        self.silent_since = SystemTime::now();
    }

    fn terminate(&mut self) {
        self.searcher.terminate_search();
        while !self.status.done {
            self.wait_status_update(Duration::from_millis(1000));
        }
    }

    fn wait_status_update(&mut self, duration: Duration) {
        self.searcher.wait_report(duration);
        while let Ok(r) = self.searcher.try_recv_report() {
            self.process_report(r)
        }
    }

    fn process_report(&mut self, report: SearchReport<Vec<Variation>>) {
        // Update the search status.
        let duration = self.started_at.elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        self.status.depth = report.depth;
        self.status.done = report.done;

        // Inform the time manager.
        if let PlayWhen::TimeManagement(ref mut tm) = self.play_when {
            tm.update_status(&report);
        }

        // If available, send the PV.
        if !report.data.is_empty() {
            self.queue_pv(&report.data);
        }

        // If nothing has been sent for a while, send a progress report.
        if self.silent_since.elapsed().unwrap().as_secs() > 10 {
            self.queue_progress_report();
        }
    }
}

/// Contains information about the current progress of a search.
struct SearchStatus {
    pub done: bool,
    pub depth: Depth,
    pub searched_nodes: u64,

    /// The duration of the search in milliseconds.
    pub duration_millis: u64,

    /// Average number of analyzed nodes per second.
    pub nps: u64,
}
<commit_msg>impl Default for SearchStatus<commit_after>//! Facilities for implementing chess engines.

pub mod time_manager;

use std::collections::VecDeque;
use std::ops::Deref;
use std::sync::Arc;
use std::time::{SystemTime, Duration};
use std::cmp::min;
use std::io;
use uci::*;
use search::*;
use self::time_manager::*;

const NAME: &'static str = "Alcibiades";
const AUTHOR: &'static str = "Evgeni Pandurski";
const VERSION: &'static str = "0.1";
const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

/// Serves UCI commands until a "quit" command is received.
///
/// The current thread will block until the UCI session is closed.
///
/// Returns `Err` if the handshake was unsuccessful, or if an IO error
/// occurred.
pub fn run_server<S: SearchExecutor<ReportData = Vec<Variation>>>() -> io::Result<()> {
    run_engine::<Engine<S>>()
}

/// Represents a condition for terminating the search.
enum PlayWhen {
    TimeManagement(TimeManager), // Stop when the time manager says.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(u64), // Stop when the given number of nodes has been searched.
    Depth(Depth), // Stop when the given search depth has been completed.
    Never, // An infinite search.
}

/// Implements `UciEngine` trait.
struct Engine<S: SearchExecutor<ReportData = Vec<Variation>>> {
    tt: Arc<S::HashTable>,
    position: S::SearchNode,
    searcher: S,
    queue: VecDeque<EngineReply>,

    // The starting time of the current/last search.
    started_at: SystemTime,

    // The status of the current/last search.
    status: SearchStatus,

    // Helps the engine decide when to send periodic progress reports.
    silent_since: SystemTime,

    // Whether the engine is thinking in pondering mode at the moment.
    is_pondering: bool,

    // Tells the engine when it must stop thinking and play the best move.
    play_when: PlayWhen,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> UciEngine for Engine<S> {
    fn name() -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author() -> String {
        AUTHOR.to_string()
    }

    fn options() -> Vec<(String, OptionDescription)> {
        // Add up all suported options.
        let mut options = vec![
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 64 * 1024, default: 16 }),
            ("Clear Hash".to_string(), OptionDescription::Button),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ];
        options.extend(S::options());

        // Remove duplicated options.
        options.sort_by(|a, b| a.0.cmp(&b.0));
        let mut options_dedup = vec![];
        let mut prev_name = String::from("");
        for o in options.drain(..) {
            if o.0 == prev_name {
                continue;
            }
            prev_name = o.0.clone();
            options_dedup.push(o);
        }
        options_dedup
    }

    fn new(tt_size_mb: Option<usize>) -> Engine<S> {
        let tt = Arc::new(S::HashTable::new(tt_size_mb));
        Engine {
            tt: tt.clone(),
            position: S::SearchNode::from_history(START_FEN, &mut vec![].into_iter()).ok().unwrap(),
            searcher: S::new(tt),
            queue: VecDeque::new(),
            started_at: SystemTime::now(),
            status: SearchStatus { done: true, ..Default::default() },
            silent_since: SystemTime::now(),
            is_pondering: false,
            play_when: PlayWhen::Never,
            pondering_is_allowed: false,
        }
    }

    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                // TODO: Can we remove this?
                self.pondering_is_allowed = value == "true";
            }
            "Hash" => {
                // We do not support re-sizing of the transposition
                // table once the engine has been started.
                return;
            }
            "Clear Hash" => {
                self.tt.clear();
            }
            _ => (),
        }
        S::set_option(name, value);
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if let Ok(p) = S::SearchNode::from_history(fen, moves) {
            self.position = p;
        }
    }

    fn go(&mut self, params: GoParams) {
        self.terminate();

        // TODO: What should we do with "mate"?
        let GoParams { mut searchmoves,
                       ponder,
                       wtime,
                       btime,
                       winc,
                       binc,
                       movestogo,
                       depth,
                       nodes,
                       movetime,
                       infinite,
                       .. } = params;

        // Validate `searchmoves`.
        let searchmoves = {
            let mut moves = vec![];
            let legal_moves = self.position.legal_moves();
            if !searchmoves.is_empty() {
                searchmoves.sort();
                for m in legal_moves.iter() {
                    if searchmoves.binary_search(&m.notation()).is_ok() {
                        moves.push(*m);
                    }
                }
            };
            if moves.is_empty() {
                legal_moves
            } else {
                moves
            }
        };

        // Start a new search.
        self.tt.new_search();
        self.started_at = SystemTime::now();
        self.status = SearchStatus { nps: self.status.nps, ..Default::default() };
        self.silent_since = SystemTime::now();
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(min(depth.unwrap(), DEPTH_MAX as u64) as Depth)
        } else {
            PlayWhen::TimeManagement(TimeManager::new(self.position.board().to_move,
                                                      self.pondering_is_allowed,
                                                      wtime,
                                                      btime,
                                                      winc,
                                                      binc,
                                                      movestogo))
        };
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: self.position.clone(),
            depth: DEPTH_MAX,
            lower_bound: VALUE_MIN,
            upper_bound: VALUE_MAX,
            searchmoves: searchmoves,
        });
    }

    fn ponder_hit(&mut self) {
        if self.status.done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.terminate();
        self.queue_best_move();
    }

    fn wait_for_reply(&mut self, duration: Duration) -> Option<EngineReply> {
        if self.queue.is_empty() {
            let done = self.status.done;

            // Wait for `search_thread` to do some work, and hopefully
            // update its status. (We must do this even when the
            // search is done -- in that case the next line will just
            // yield the CPU to another process.)
            self.wait_status_update(duration);

            if !done {
                let &SearchStatus { done, depth, searched_nodes, duration_millis, .. } =
                    &self.status;

                // Check if we must play now.
                if !self.is_pondering &&
                   match self.play_when {
                    PlayWhen::TimeManagement(ref tm) => done || tm.must_play(),
                    PlayWhen::MoveTime(t) => done || duration_millis >= t,
                    PlayWhen::Nodes(n) => done || searched_nodes >= n,
                    PlayWhen::Depth(d) => done || depth >= d,
                    PlayWhen::Never => false,
                } {
                    self.stop();
                }
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.terminate();
    }
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> Engine<S> {
    /// Adds a progress report message to the queue.
    fn queue_progress_report(&mut self) {
        let SearchStatus { ref depth, ref searched_nodes, ref nps, .. } = self.status;
        self.queue.push_back(EngineReply::Info(vec![
            InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
            InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
            InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
        ]));
        self.silent_since = SystemTime::now();
    }

    /// Adds a message containing the current (multi)PV to the queue.
    fn queue_pv(&mut self, variations: &Vec<Variation>) {
        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, ref nps, .. } =
            self.status;
        for (i, &Variation { ref moves, value, bound }) in variations.iter().enumerate() {
            let bound_suffix = match bound {
                BOUND_EXACT => "",
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                _ => panic!("unexpected bound type"),
            };
            let mut moves_string = String::new();
            for m in moves {
                moves_string.push_str(&m.notation());
                moves_string.push(' ');
            }
            self.queue.push_back(EngineReply::Info(vec![
                InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
                InfoItem { info_type: "multipv".to_string(), data: format!("{}", i + 1) },
                InfoItem { info_type: "score".to_string(), data: format!("cp {}{}", value, bound_suffix) },
                InfoItem { info_type: "time".to_string(), data: format!("{}", duration_millis) },
                InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
                InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
                InfoItem { info_type: "pv".to_string(), data: moves_string },
            ]));
        }
        self.silent_since = SystemTime::now();
    }

    /// Adds a message containing the current best move to the queue.
    fn queue_best_move(&mut self) {
        let pv = extract_pv(self.tt.deref(), &self.position, 2);
        let best_move = if let Some(m) = pv.moves.get(0) {
            m.notation()
        } else {
            // If the PV is empty, pick the first legal move.
            self.position.legal_moves().get(0).map_or("0000".to_string(), |m| m.notation())
        };
        self.queue.push_back(EngineReply::BestMove {
            best_move: best_move,
            ponder_move: pv.moves.get(1).map(|m| m.notation()),
        });
        self.silent_since = SystemTime::now();
    }

    fn terminate(&mut self) {
        self.searcher.terminate_search();
        while !self.status.done {
            self.wait_status_update(Duration::from_millis(1000));
        }
    }

    fn wait_status_update(&mut self, duration: Duration) {
        self.searcher.wait_report(duration);
        while let Ok(r) = self.searcher.try_recv_report() {
            self.process_report(r)
        }
    }

    fn process_report(&mut self, report: SearchReport<Vec<Variation>>) {
        // Update the search status.
        let duration = self.started_at.elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        self.status.depth = report.depth;
        self.status.done = report.done;

        // Inform the time manager.
        if let PlayWhen::TimeManagement(ref mut tm) = self.play_when {
            tm.update_status(&report);
        }

        // If available, send the PV.
        if !report.data.is_empty() {
            self.queue_pv(&report.data);
        }

        // If nothing has been sent for a while, send a progress report.
        if self.silent_since.elapsed().unwrap().as_secs() > 10 {
            self.queue_progress_report();
        }
    }
}

/// Contains information about the current progress of a search.
struct SearchStatus {
    pub done: bool,
    pub depth: Depth,
    pub searched_nodes: u64,

    /// The duration of the search in milliseconds.
    pub duration_millis: u64,

    /// Average number of analyzed nodes per second.
    pub nps: u64,
}

impl Default for SearchStatus {
    fn default() -> Self {
        SearchStatus {
            done: false,
            depth: 0,
            searched_nodes: 0,
            duration_millis: 0,
            nps: 0,
        }
    }
}
<|endoftext|>


<commit_before>use float::Float;
use int::Int;

macro_rules! fp_overflow {
    (infinity, $fty:ty, $sign: expr) => {
        return {
            <$fty as Float>::from_parts(
                $sign,
                <$fty as Float>::exponent_max() as <$fty as Float>::Int,
                0 as <$fty as Float>::Int)
        }
    }
}

macro_rules! fp_convert {
    ($intrinsic:ident: $ity:ty, $fty:ty) => {

    pub extern "C" fn $intrinsic(i: $ity) -> $fty {
        if i == 0 {
            return 0.0
        }

        let mant_dig = <$fty>::significand_bits() + 1;
        let exponent_bias = <$fty>::exponent_bias();

        let n = <$ity>::bits();
        let (s, a) = i.extract_sign();
        let mut a = a;

        // number of significant digits
        let sd = n - a.leading_zeros();

        // exponent
        let mut e = sd - 1;

        if <$ity>::bits() < mant_dig {
            return <$fty>::from_parts(s,
                (e + exponent_bias) as <$fty as Float>::Int,
                (a as <$fty as Float>::Int) << (mant_dig - e - 1))
        }

        a = if sd > mant_dig {
            /* start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
            *  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
            *                                                12345678901234567890123456
            *  1 = msb 1 bit
            *  P = bit MANT_DIG-1 bits to the right of 1
            *  Q = bit MANT_DIG bits to the right of 1
            *  R = "or" of all bits to the right of Q
            */
            let mant_dig_plus_one = mant_dig + 1;
            let mant_dig_plus_two = mant_dig + 2;
            a = if sd == mant_dig_plus_one {
                a << 1
            } else if sd == mant_dig_plus_two {
                a
            } else {
                (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt |
                ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt
            };

            /* finish: */
            a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */
            a += 1; /* round - this step may add a significant bit */
            a >>= 2; /* dump Q and R */

            /* a is now rounded to mant_dig or mant_dig+1 bits */
            if (a & (1 << mant_dig)) != 0 {
                a >>= 1; e += 1;
            }
            a
            /* a is now rounded to mant_dig bits */
        } else {
            a.wrapping_shl(mant_dig - sd)
            /* a is now rounded to mant_dig bits */
        };

        <$fty>::from_parts(s,
            (e + exponent_bias) as <$fty as Float>::Int,
            a as <$fty as Float>::Int)
    }
    }
}

fp_convert!(__floatsisf: i32, f32);
fp_convert!(__floatsidf: i32, f64);
fp_convert!(__floatdidf: i64, f64);
fp_convert!(__floatunsisf: u32, f32);
fp_convert!(__floatunsidf: u32, f64);
fp_convert!(__floatundidf: u64, f64);

#[derive(PartialEq, Debug)]
enum Sign {
    Positive,
    Negative
}
macro_rules! fp_fix {
    ($intrinsic:ident: $fty:ty, $ity:ty) => {
        pub extern "C" fn $intrinsic(f: $fty) -> $ity {
            let fixint_min = <$ity>::min_value();
            let fixint_max = <$ity>::max_value();
            let fixint_bits = <$ity>::bits() as usize;
            let fixint_unsigned = fixint_min == 0;

            let sign_bit = <$fty>::sign_mask();
            let significand_bits = <$fty>::significand_bits() as usize;
            let exponent_bias = <$fty>::exponent_bias() as usize;
            //let exponent_max = <$fty>::exponent_max() as usize;

            // Break a into sign, exponent, significand
            let a_rep = <$fty>::repr(f);
            let a_abs = a_rep & !sign_bit;

            // this is used to work around -1 not being available for unsigned
            let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative };
            let mut exponent = (a_abs >> significand_bits) as usize;
            let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit();

            // if < 1 or unsigned & negative
            if  exponent < exponent_bias ||
                fixint_unsigned && sign == Sign::Negative {
                return 0
            }
            exponent -= exponent_bias;

            // If the value is infinity, saturate.
            // If the value is too large for the integer type, 0.
            if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) {
                return if sign == Sign::Positive {fixint_max} else {fixint_min}
            }
            // If 0 <= exponent < significand_bits, right shift to get the result.
            // Otherwise, shift left.
            // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
            let r = if exponent < significand_bits {
                (significand >> (significand_bits - exponent)) as $ity
            } else {
                (significand as $ity) << (exponent - significand_bits)
            };

            if sign == Sign::Negative {
                (!r).wrapping_add(1)
            } else {
                r
            }
        }
    }
}

fp_fix!(__fixsfsi: f32, i32);
fp_fix!(__fixsfdi: f32, i64);
fp_fix!(__fixdfsi: f64, i32);
fp_fix!(__fixdfdi: f64, i64);

fp_fix!(__fixunssfsi: f32, u32);
fp_fix!(__fixunssfdi: f32, u64);
fp_fix!(__fixunsdfsi: f64, u32);
fp_fix!(__fixunsdfdi: f64, u64);

// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't
// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
// just avoid testing against them on those targets. Do note that our implementation gives the
// correct answer; gcc_s and compiler-rt are incorrect in this case.
//
#[cfg(all(test, not(arm_linux)))]
mod tests {
    use qc::{I32, U32, I64, U64, F32, F64};

    check! {
        fn __floatsisf(f: extern fn(i32) -> f32,
                    a: I32)
                    -> Option<F32> {
            Some(F32(f(a.0)))
        }
        fn __floatsidf(f: extern fn(i32) -> f64,
                    a: I32)
                    -> Option<F64> {
            Some(F64(f(a.0)))
        }
        fn __floatdidf(f: extern fn(i64) -> f64,
                    a: I64)
                    -> Option<F64> {
            Some(F64(f(a.0)))
        }
        fn __floatunsisf(f: extern fn(u32) -> f32,
                    a: U32)
                    -> Option<F32> {
            Some(F32(f(a.0)))
        }
        fn __floatunsidf(f: extern fn(u32) -> f64,
                    a: U32)
                    -> Option<F64> {
            Some(F64(f(a.0)))
        }
        fn __floatundidf(f: extern fn(u64) -> f64,
                    a: U64)
                    -> Option<F64> {
            Some(F64(f(a.0)))
        }

        fn __fixsfsi(f: extern fn(f32) -> i32,
                    a: F32)
                    -> Option<I32> {
            if a.0 > (i32::max_value() as f32) ||
               a.0 < (i32::min_value() as f32) || a.0.is_nan() {
                   None
           } else { Some(I32(f(a.0))) }
        }
        fn __fixsfdi(f: extern fn(f32) -> i64,
                    a: F32)
                    -> Option<I64> {
            if a.0 > (i64::max_value() as f32) ||
               a.0 < (i64::min_value() as f32) || a.0.is_nan() {
                   None
           } else { Some(I64(f(a.0))) }
        }
        fn __fixdfsi(f: extern fn(f64) -> i32,
                    a: F64)
                    -> Option<I32> {
            if a.0 > (i32::max_value() as f64) ||
               a.0 < (i32::min_value() as f64) || a.0.is_nan() {
                   None
           } else { Some(I32(f(a.0))) }
        }
        fn __fixdfdi(f: extern fn(f64) -> i64,
                    a: F64)
                    -> Option<I64> {
            if a.0 > (i64::max_value() as f64) ||
               a.0 < (i64::min_value() as f64) || a.0.is_nan() {
                   None
           } else { Some(I64(f(a.0))) }
        }

        fn __fixunssfsi(f: extern fn(f32) -> u32,
                    a: F32)
                    -> Option<U32> {
            if a.0 > (u32::max_value() as f32) ||
               a.0 < (u32::min_value() as f32) || a.0.is_nan() {
                   None
           } else { Some(U32(f(a.0))) }
        }
        fn __fixunssfdi(f: extern fn(f32) -> u64,
                    a: F32)
                    -> Option<U64> {
            if a.0 > (u64::max_value() as f32) ||
               a.0 < (u64::min_value() as f32) || a.0.is_nan() {
                   None
           } else { Some(U64(f(a.0))) }
        }
        fn __fixunsdfsi(f: extern fn(f64) -> u32,
                    a: F64)
                    -> Option<U32> {
            if a.0 > (u32::max_value() as f64) ||
               a.0 < (u32::min_value() as f64) || a.0.is_nan() {
                   None
           } else { Some(U32(f(a.0))) }
        }
        fn __fixunsdfdi(f: extern fn(f64) -> u64,
                    a: F64)
                    -> Option<U64> {
            if a.0 <= (u64::max_value() as f64) ||
               a.0 >= (u64::min_value() as f64) || a.0.is_nan() {
                   None
           } else { Some(U64(f(a.0))) }
        }
    }
}
<commit_msg>fix quickcheck tests<commit_after>use float::Float;
use int::Int;

macro_rules! fp_overflow {
    (infinity, $fty:ty, $sign: expr) => {
        return {
            <$fty as Float>::from_parts(
                $sign,
                <$fty as Float>::exponent_max() as <$fty as Float>::Int,
                0 as <$fty as Float>::Int)
        }
    }
}

macro_rules! fp_convert {
    ($intrinsic:ident: $ity:ty, $fty:ty) => {

    pub extern "C" fn $intrinsic(i: $ity) -> $fty {
        if i == 0 {
            return 0.0
        }

        let mant_dig = <$fty>::significand_bits() + 1;
        let exponent_bias = <$fty>::exponent_bias();

        let n = <$ity>::bits();
        let (s, a) = i.extract_sign();
        let mut a = a;

        // number of significant digits
        let sd = n - a.leading_zeros();

        // exponent
        let mut e = sd - 1;

        if <$ity>::bits() < mant_dig {
            return <$fty>::from_parts(s,
                (e + exponent_bias) as <$fty as Float>::Int,
                (a as <$fty as Float>::Int) << (mant_dig - e - 1))
        }

        a = if sd > mant_dig {
            /* start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
            *  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
            *                                                12345678901234567890123456
            *  1 = msb 1 bit
            *  P = bit MANT_DIG-1 bits to the right of 1
            *  Q = bit MANT_DIG bits to the right of 1
            *  R = "or" of all bits to the right of Q
            */
            let mant_dig_plus_one = mant_dig + 1;
            let mant_dig_plus_two = mant_dig + 2;
            a = if sd == mant_dig_plus_one {
                a << 1
            } else if sd == mant_dig_plus_two {
                a
            } else {
                (a >> (sd - mant_dig_plus_two)) as <$ity as Int>::UnsignedInt |
                ((a & <$ity as Int>::UnsignedInt::max_value()).wrapping_shl((n + mant_dig_plus_two) - sd) != 0) as <$ity as Int>::UnsignedInt
            };

            /* finish: */
            a |= ((a & 4) != 0) as <$ity as Int>::UnsignedInt; /* Or P into R */
            a += 1; /* round - this step may add a significant bit */
            a >>= 2; /* dump Q and R */

            /* a is now rounded to mant_dig or mant_dig+1 bits */
            if (a & (1 << mant_dig)) != 0 {
                a >>= 1; e += 1;
            }
            a
            /* a is now rounded to mant_dig bits */
        } else {
            a.wrapping_shl(mant_dig - sd)
            /* a is now rounded to mant_dig bits */
        };

        <$fty>::from_parts(s,
            (e + exponent_bias) as <$fty as Float>::Int,
            a as <$fty as Float>::Int)
    }
    }
}

fp_convert!(__floatsisf: i32, f32);
fp_convert!(__floatsidf: i32, f64);
fp_convert!(__floatdidf: i64, f64);
fp_convert!(__floatunsisf: u32, f32);
fp_convert!(__floatunsidf: u32, f64);
fp_convert!(__floatundidf: u64, f64);

#[derive(PartialEq, Debug)]
enum Sign {
    Positive,
    Negative
}
macro_rules! fp_fix {
    ($intrinsic:ident: $fty:ty, $ity:ty) => {
        pub extern "C" fn $intrinsic(f: $fty) -> $ity {
            let fixint_min = <$ity>::min_value();
            let fixint_max = <$ity>::max_value();
            let fixint_bits = <$ity>::bits() as usize;
            let fixint_unsigned = fixint_min == 0;

            let sign_bit = <$fty>::sign_mask();
            let significand_bits = <$fty>::significand_bits() as usize;
            let exponent_bias = <$fty>::exponent_bias() as usize;
            //let exponent_max = <$fty>::exponent_max() as usize;

            // Break a into sign, exponent, significand
            let a_rep = <$fty>::repr(f);
            let a_abs = a_rep & !sign_bit;

            // this is used to work around -1 not being available for unsigned
            let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative };
            let mut exponent = (a_abs >> significand_bits) as usize;
            let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit();

            // if < 1 or unsigned & negative
            if  exponent < exponent_bias ||
                fixint_unsigned && sign == Sign::Negative {
                return 0
            }
            exponent -= exponent_bias;

            // If the value is infinity, saturate.
            // If the value is too large for the integer type, 0.
            if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) {
                return if sign == Sign::Positive {fixint_max} else {fixint_min}
            }
            // If 0 <= exponent < significand_bits, right shift to get the result.
            // Otherwise, shift left.
            // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
            let r = if exponent < significand_bits {
                (significand >> (significand_bits - exponent)) as $ity
            } else {
                (significand as $ity) << (exponent - significand_bits)
            };

            if sign == Sign::Negative {
                (!r).wrapping_add(1)
            } else {
                r
            }
        }
    }
}

fp_fix!(__fixsfsi: f32, i32);
fp_fix!(__fixsfdi: f32, i64);
fp_fix!(__fixdfsi: f64, i32);
fp_fix!(__fixdfdi: f64, i64);

fp_fix!(__fixunssfsi: f32, u32);
fp_fix!(__fixunssfdi: f32, u64);
fp_fix!(__fixunsdfsi: f64, u32);
fp_fix!(__fixunsdfdi: f64, u64);

// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't
// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
// just avoid testing against them on those targets. Do note that our implementation gives the
// correct answer; gcc_s and compiler-rt are incorrect in this case.
//
#[cfg(all(test, not(arm_linux)))]
mod tests {
    use qc::{I32, U32, I64, U64, F32, F64};

    check! {
        fn __floatsisf(f: extern "C" fn(i32) -> f32,
                    a: I32)
                    -> Option<F32> {
            Some(F32(f(a.0)))
        }
        fn __floatsidf(f: extern "C" fn(i32) -> f64,
                    a: I32)
                    -> Option<F64> {
            Some(F64(f(a.0)))
        }
        fn __floatdidf(f: extern "C" fn(i64) -> f64,
                    a: I64)
                    -> Option<F64> {
            Some(F64(f(a.0)))
        }
        fn __floatunsisf(f: extern "C" fn(u32) -> f32,
                    a: U32)
                    -> Option<F32> {
            Some(F32(f(a.0)))
        }
        fn __floatunsidf(f: extern "C" fn(u32) -> f64,
                    a: U32)
                    -> Option<F64> {
            Some(F64(f(a.0)))
        }
        fn __floatundidf(f: extern "C" fn(u64) -> f64,
                    a: U64)
                    -> Option<F64> {
            Some(F64(f(a.0)))
        }

        fn __fixsfsi(f: extern "C" fn(f32) -> i32,
                    a: F32)
                    -> Option<I32> {
            if a.0 > (i32::max_value() as f32) ||
               a.0 < (i32::min_value() as f32) || a.0.is_nan() {
                   None
           } else { Some(I32(f(a.0))) }
        }
        fn __fixsfdi(f: extern "C" fn(f32) -> i64,
                    a: F32)
                    -> Option<I64> {
            if a.0 > (i64::max_value() as f32) ||
               a.0 < (i64::min_value() as f32) || a.0.is_nan() {
                   None
           } else { Some(I64(f(a.0))) }
        }
        fn __fixdfsi(f: extern "C" fn(f64) -> i32,
                    a: F64)
                    -> Option<I32> {
            if a.0 > (i32::max_value() as f64) ||
               a.0 < (i32::min_value() as f64) || a.0.is_nan() {
                   None
           } else { Some(I32(f(a.0))) }
        }
        fn __fixdfdi(f: extern "C" fn(f64) -> i64,
                    a: F64)
                    -> Option<I64> {
            if a.0 > (i64::max_value() as f64) ||
               a.0 < (i64::min_value() as f64) || a.0.is_nan() {
                   None
           } else { Some(I64(f(a.0))) }
        }

        fn __fixunssfsi(f: extern "C" fn(f32) -> u32,
                    a: F32)
                    -> Option<U32> {
            if a.0 > (u32::max_value() as f32) ||
               a.0 < (u32::min_value() as f32) || a.0.is_nan() {
                   None
           } else { Some(U32(f(a.0))) }
        }
        fn __fixunssfdi(f: extern "C" fn(f32) -> u64,
                    a: F32)
                    -> Option<U64> {
            if a.0 > (u64::max_value() as f32) ||
               a.0 < (u64::min_value() as f32) || a.0.is_nan() {
                   None
           } else { Some(U64(f(a.0))) }
        }
        fn __fixunsdfsi(f: extern "C" fn(f64) -> u32,
                    a: F64)
                    -> Option<U32> {
            if a.0 > (u32::max_value() as f64) ||
               a.0 < (u32::min_value() as f64) || a.0.is_nan() {
                   None
           } else { Some(U32(f(a.0))) }
        }
        fn __fixunsdfdi(f: extern "C" fn(f64) -> u64,
                    a: F64)
                    -> Option<U64> {
            if a.0 <= (u64::max_value() as f64) ||
               a.0 >= (u64::min_value() as f64) || a.0.is_nan() {
                   None
           } else { Some(U64(f(a.0))) }
        }
    }
}
<|endoftext|>


<commit_before>use serde::Serialize;
use serde_json::value::{to_value, Value as Json};

pub(crate) static DEFAULT_VALUE: Json = Json::Null;

/// A JSON wrapper designed for handlebars internal use case
///
/// * Constant: the JSON value hardcoded into template
/// * Context:  the JSON value referenced in your provided data context
/// * Derived:  the owned JSON value computed during rendering process
///
#[derive(Debug)]
pub enum ScopedJson<'reg: 'rc, 'rc> {
    Constant(&'reg Json),
    Derived(Json),
    // represents a json reference to context value, its full path
    Context(&'rc Json, Vec<String>),
    // represents a block param json with resolve full path
    // this path is different from `PathAndJson`
    // TODO: merge this with context?
    BlockContext(&'rc Json, Vec<String>),
    Missing,
}

impl<'reg: 'rc, 'rc> ScopedJson<'reg, 'rc> {
    /// get the JSON reference
    pub fn as_json(&self) -> &Json {
        match self {
            ScopedJson::Constant(j) => j,
            ScopedJson::Derived(ref j) => j,
            ScopedJson::Context(j, _) => j,
            ScopedJson::BlockContext(j, _) => j,
            _ => &DEFAULT_VALUE,
        }
    }

    pub fn render(&self) -> String {
        self.as_json().render()
    }

    pub fn is_missing(&self) -> bool {
        match self {
            ScopedJson::Missing => true,
            _ => false,
        }
    }

    pub fn into_derived(self) -> ScopedJson<'reg, 'rc> {
        let v = self.as_json();
        ScopedJson::Derived(v.clone())
    }

    pub fn context_path(&self) -> Option<&Vec<String>> {
        match self {
            ScopedJson::BlockContext(_, ref p) | ScopedJson::Context(_, ref p) => Some(p),
            _ => None,
        }
    }
}

impl<'reg: 'rc, 'rc> From<Json> for ScopedJson<'reg, 'rc> {
    fn from(v: Json) -> ScopedJson<'reg, 'rc> {
        ScopedJson::Derived(v)
    }
}

/// Json wrapper that holds the Json value and reference path information
///
#[derive(Debug)]
pub struct PathAndJson<'reg: 'rc, 'rc> {
    relative_path: Option<String>,
    value: ScopedJson<'reg, 'rc>,
}

impl<'reg: 'rc, 'rc> PathAndJson<'reg, 'rc> {
    pub fn new(
        relative_path: Option<String>,
        value: ScopedJson<'reg, 'rc>,
    ) -> PathAndJson<'reg, 'rc> {
        PathAndJson {
            relative_path,
            value,
        }
    }

    /// Returns relative path when the value is referenced
    /// If the value is from a literal, the path is `None`
    pub fn relative_path(&self) -> Option<&String> {
        self.relative_path.as_ref()
    }

    /// Returns full path to this value if any
    pub fn context_path(&self) -> Option<&Vec<String>> {
        self.value.context_path()
    }

    /// Returns the value
    pub fn value(&self) -> &Json {
        self.value.as_json()
    }

    /// Test if value is missing
    pub fn is_value_missing(&self) -> bool {
        self.value.is_missing()
    }

    pub fn render(&self) -> String {
        self.value.render()
    }
}

/// Render Json data with default format
pub trait JsonRender {
    fn render(&self) -> String;
}

pub trait JsonTruthy {
    fn is_truthy(&self, include_zero: bool) -> bool;
}

impl JsonRender for Json {
    fn render(&self) -> String {
        match *self {
            Json::String(ref s) => s.to_string(),
            Json::Bool(i) => i.to_string(),
            Json::Number(ref n) => n.to_string(),
            Json::Null => "".to_owned(),
            Json::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    buf.push_str(i.render().as_ref());
                    buf.push_str(", ");
                }
                buf.push(']');
                buf
            }
            Json::Object(_) => "[object]".to_owned(),
        }
    }
}

pub fn to_json<T>(src: T) -> Json
where
    T: Serialize,
{
    to_value(src).unwrap_or_default()
}

pub fn as_string(src: &Json) -> Option<&str> {
    src.as_str()
}

impl JsonTruthy for Json {
    fn is_truthy(&self, include_zero: bool) -> bool {
        match *self {
            Json::Bool(ref i) => *i,
            Json::Number(ref n) => {
                if include_zero {
                    n.as_f64().map(|f| !f.is_nan()).unwrap_or(false)
                } else {
                    // there is no inifity in json/serde_json
                    n.as_f64().map(|f| f.is_normal()).unwrap_or(false)
                }
            }
            Json::Null => false,
            Json::String(ref i) => !i.is_empty(),
            Json::Array(ref i) => !i.is_empty(),
            Json::Object(ref i) => !i.is_empty(),
        }
    }
}

#[test]
fn test_json_render() {
    let raw = "
Hello world
\n<p thing=\"hello\"
";
    let thing = Json::String(raw.to_string());

    assert_eq!(raw, thing.render());
}

#[test]
fn test_json_number_truthy() {
    use std::f64;
    assert!(json!(16i16).is_truthy(false));
    assert!(json!(16i16).is_truthy(true));

    assert!(json!(0i16).is_truthy(true));
    assert!(!json!(0i16).is_truthy(false));

    assert!(json!(1.0f64).is_truthy(false));
    assert!(json!(1.0f64).is_truthy(true));

    assert!(json!(Some(16i16)).is_truthy(false));
    assert!(json!(Some(16i16)).is_truthy(true));

    assert!(!json!(None as Option<i16>).is_truthy(false));
    assert!(!json!(None as Option<i16>).is_truthy(true));

    assert!(!json!(f64::NAN).is_truthy(false));
    assert!(!json!(f64::NAN).is_truthy(true));

    // there is no infinity in json/serde_json
    // assert!(json!(f64::INFINITY).is_truthy(false));
    // assert!(json!(f64::INFINITY).is_truthy(true));

    // assert!(json!(f64::NEG_INFINITY).is_truthy(false));
    // assert!(json!(f64::NEG_INFINITY).is_truthy(true));
}
<commit_msg>(refactor) remove block context from value enum<commit_after>use serde::Serialize;
use serde_json::value::{to_value, Value as Json};

pub(crate) static DEFAULT_VALUE: Json = Json::Null;

/// A JSON wrapper designed for handlebars internal use case
///
/// * Constant: the JSON value hardcoded into template
/// * Context:  the JSON value referenced in your provided data context
/// * Derived:  the owned JSON value computed during rendering process
///
#[derive(Debug)]
pub enum ScopedJson<'reg: 'rc, 'rc> {
    Constant(&'reg Json),
    Derived(Json),
    // represents a json reference to context value, its full path
    Context(&'rc Json, Vec<String>),
    Missing,
}

impl<'reg: 'rc, 'rc> ScopedJson<'reg, 'rc> {
    /// get the JSON reference
    pub fn as_json(&self) -> &Json {
        match self {
            ScopedJson::Constant(j) => j,
            ScopedJson::Derived(ref j) => j,
            ScopedJson::Context(j, _) => j,
            _ => &DEFAULT_VALUE,
        }
    }

    pub fn render(&self) -> String {
        self.as_json().render()
    }

    pub fn is_missing(&self) -> bool {
        match self {
            ScopedJson::Missing => true,
            _ => false,
        }
    }

    pub fn into_derived(self) -> ScopedJson<'reg, 'rc> {
        let v = self.as_json();
        ScopedJson::Derived(v.clone())
    }

    pub fn context_path(&self) -> Option<&Vec<String>> {
        match self {
            ScopedJson::Context(_, ref p) => Some(p),
            _ => None,
        }
    }
}

impl<'reg: 'rc, 'rc> From<Json> for ScopedJson<'reg, 'rc> {
    fn from(v: Json) -> ScopedJson<'reg, 'rc> {
        ScopedJson::Derived(v)
    }
}

/// Json wrapper that holds the Json value and reference path information
///
#[derive(Debug)]
pub struct PathAndJson<'reg: 'rc, 'rc> {
    relative_path: Option<String>,
    value: ScopedJson<'reg, 'rc>,
}

impl<'reg: 'rc, 'rc> PathAndJson<'reg, 'rc> {
    pub fn new(
        relative_path: Option<String>,
        value: ScopedJson<'reg, 'rc>,
    ) -> PathAndJson<'reg, 'rc> {
        PathAndJson {
            relative_path,
            value,
        }
    }

    /// Returns relative path when the value is referenced
    /// If the value is from a literal, the path is `None`
    pub fn relative_path(&self) -> Option<&String> {
        self.relative_path.as_ref()
    }

    /// Returns full path to this value if any
    pub fn context_path(&self) -> Option<&Vec<String>> {
        self.value.context_path()
    }

    /// Returns the value
    pub fn value(&self) -> &Json {
        self.value.as_json()
    }

    /// Test if value is missing
    pub fn is_value_missing(&self) -> bool {
        self.value.is_missing()
    }

    pub fn render(&self) -> String {
        self.value.render()
    }
}

/// Render Json data with default format
pub trait JsonRender {
    fn render(&self) -> String;
}

pub trait JsonTruthy {
    fn is_truthy(&self, include_zero: bool) -> bool;
}

impl JsonRender for Json {
    fn render(&self) -> String {
        match *self {
            Json::String(ref s) => s.to_string(),
            Json::Bool(i) => i.to_string(),
            Json::Number(ref n) => n.to_string(),
            Json::Null => "".to_owned(),
            Json::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    buf.push_str(i.render().as_ref());
                    buf.push_str(", ");
                }
                buf.push(']');
                buf
            }
            Json::Object(_) => "[object]".to_owned(),
        }
    }
}

pub fn to_json<T>(src: T) -> Json
where
    T: Serialize,
{
    to_value(src).unwrap_or_default()
}

pub fn as_string(src: &Json) -> Option<&str> {
    src.as_str()
}

impl JsonTruthy for Json {
    fn is_truthy(&self, include_zero: bool) -> bool {
        match *self {
            Json::Bool(ref i) => *i,
            Json::Number(ref n) => {
                if include_zero {
                    n.as_f64().map(|f| !f.is_nan()).unwrap_or(false)
                } else {
                    // there is no inifity in json/serde_json
                    n.as_f64().map(|f| f.is_normal()).unwrap_or(false)
                }
            }
            Json::Null => false,
            Json::String(ref i) => !i.is_empty(),
            Json::Array(ref i) => !i.is_empty(),
            Json::Object(ref i) => !i.is_empty(),
        }
    }
}

#[test]
fn test_json_render() {
    let raw = "
Hello world
\n<p thing=\"hello\"
";
    let thing = Json::String(raw.to_string());

    assert_eq!(raw, thing.render());
}

#[test]
fn test_json_number_truthy() {
    use std::f64;
    assert!(json!(16i16).is_truthy(false));
    assert!(json!(16i16).is_truthy(true));

    assert!(json!(0i16).is_truthy(true));
    assert!(!json!(0i16).is_truthy(false));

    assert!(json!(1.0f64).is_truthy(false));
    assert!(json!(1.0f64).is_truthy(true));

    assert!(json!(Some(16i16)).is_truthy(false));
    assert!(json!(Some(16i16)).is_truthy(true));

    assert!(!json!(None as Option<i16>).is_truthy(false));
    assert!(!json!(None as Option<i16>).is_truthy(true));

    assert!(!json!(f64::NAN).is_truthy(false));
    assert!(!json!(f64::NAN).is_truthy(true));

    // there is no infinity in json/serde_json
    // assert!(json!(f64::INFINITY).is_truthy(false));
    // assert!(json!(f64::INFINITY).is_truthy(true));

    // assert!(json!(f64::NEG_INFINITY).is_truthy(false));
    // assert!(json!(f64::NEG_INFINITY).is_truthy(true));
}
<|endoftext|>