<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Named pipes

This module contains the ability to communicate over named pipes with
synchronous I/O. On windows, this corresponds to talking over a Named Pipe,
while on Unix it corresponds to UNIX domain sockets.

These pipes are similar to TCP in the sense that you can have both a stream to a
server and a server itself. The server provided accepts other `UnixStream`
instances as clients.

*/

use prelude::*;

use c_str::ToCStr;
use rt::rtio::{IoFactory, RtioUnixListener, with_local_io};
use rt::rtio::{RtioUnixAcceptor, RtioPipe};
use rt::io::pipe::PipeStream;
use rt::io::{io_error, Listener, Acceptor, Reader, Writer};

/// A stream which communicates over a named pipe.
pub struct UnixStream {
    priv obj: PipeStream,
}

impl UnixStream {
    fn new(obj: ~RtioPipe) -> UnixStream {
        UnixStream { obj: PipeStream::new(obj) }
    }

    /// Connect to a pipe named by `path`. This will attempt to open a
    /// connection to the underlying socket.
    ///
    /// The returned stream will be closed when the object falls out of scope.
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if the connection
    /// could not be made.
    ///
    /// # Example
    ///
    ///     use std::rt::io::net::unix::UnixStream;
    ///
    ///     let server = Path("path/to/my/socket");
    ///     let mut stream = UnixStream::connect(&server);
    ///     stream.write([1, 2, 3]);
    ///
    pub fn connect<P: ToCStr>(path: &P) -> Option<UnixStream> {
        do with_local_io |io| {
            match io.unix_connect(&path.to_c_str()) {
                Ok(s) => Some(UnixStream::new(s)),
                Err(ioerr) => {
                    io_error::cond.raise(ioerr);
                    None
                }
            }
        }
    }
}

impl Reader for UnixStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.obj.read(buf) }
    fn eof(&mut self) -> bool { self.obj.eof() }
}

impl Writer for UnixStream {
    fn write(&mut self, buf: &[u8]) { self.obj.write(buf) }
    fn flush(&mut self) { self.obj.flush() }
}

pub struct UnixListener {
    priv obj: ~RtioUnixListener,
}

impl UnixListener {

    /// Creates a new listener, ready to receive incoming connections on the
    /// specified socket. The server will be named by `path`.
    ///
    /// This listener will be closed when it falls out of scope.
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if the specified
    /// path could not be bound.
    ///
    /// # Example
    ///
    ///     use std::rt::io::net::unix::UnixListener;
    ///
    ///     let server = Path("path/to/my/socket");
    ///     let mut stream = UnixListener::bind(&server);
    ///     for client in stream.incoming() {
    ///         let mut client = client;
    ///         client.write([1, 2, 3, 4]);
    ///     }
    ///
    pub fn bind<P: ToCStr>(path: &P) -> Option<UnixListener> {
        do with_local_io |io| {
            match io.unix_bind(&path.to_c_str()) {
                Ok(s) => Some(UnixListener{ obj: s }),
                Err(ioerr) => {
                    io_error::cond.raise(ioerr);
                    None
                }
            }
        }
    }
}

impl Listener<UnixStream, UnixAcceptor> for UnixListener {
    fn listen(self) -> Option<UnixAcceptor> {
        match self.obj.listen() {
            Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                None
            }
        }
    }
}

pub struct UnixAcceptor {
    priv obj: ~RtioUnixAcceptor,
}

impl Acceptor<UnixStream> for UnixAcceptor {
    fn accept(&mut self) -> Option<UnixStream> {
        match self.obj.accept() {
            Ok(s) => Some(UnixStream::new(s)),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                None
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use super::*;
    use cell::Cell;
    use rt::test::*;
    use rt::io::*;
    use rt::comm::oneshot;
    use os;

    fn smalltest(server: ~fn(UnixStream), client: ~fn(UnixStream)) {
        let server = Cell::new(server);
        let client = Cell::new(client);
        do run_in_mt_newsched_task {
            let server = Cell::new(server.take());
            let client = Cell::new(client.take());
            let path1 = next_test_unix();
            let path2 = path1.clone();
            let (port, chan) = oneshot();
            let port = Cell::new(port);
            let chan = Cell::new(chan);

            do spawntask {
                let mut acceptor = UnixListener::bind(&path1).listen();
                chan.take().send(());
                server.take()(acceptor.accept().unwrap());
            }

            do spawntask {
                port.take().recv();
                client.take()(UnixStream::connect(&path2).unwrap());
            }
        }
    }

    #[test]
    fn bind_error() {
        do run_in_mt_newsched_task {
            let mut called = false;
            do io_error::cond.trap(|e| {
                assert!(e.kind == PermissionDenied);
                called = true;
            }).inside {
                let listener = UnixListener::bind(&("path/to/nowhere"));
                assert!(listener.is_none());
            }
            assert!(called);
        }
    }

    #[test]
    fn connect_error() {
        do run_in_mt_newsched_task {
            let mut called = false;
            do io_error::cond.trap(|e| {
                assert_eq!(e.kind, OtherIoError);
                called = true;
            }).inside {
                let stream = UnixStream::connect(&("path/to/nowhere"));
                assert!(stream.is_none());
            }
            assert!(called);
        }
    }

    #[test]
    fn smoke() {
        smalltest(|mut server| {
            let mut buf = [0];
            server.read(buf);
            assert!(buf[0] == 99);
        }, |mut client| {
            client.write([99]);
        })
    }

    #[test]
    fn read_eof() {
        smalltest(|mut server| {
            let mut buf = [0];
            assert!(server.read(buf).is_none());
            assert!(server.read(buf).is_none());
        }, |_client| {
            // drop the client
        })
    }

    #[test]
    fn write_begone() {
        smalltest(|mut server| {
            let buf = [0];
            let mut stop = false;
            while !stop{
                do io_error::cond.trap(|e| {
                    assert_eq!(e.kind, BrokenPipe);
                    stop = true;
                }).inside {
                    server.write(buf);
                }
            }
        }, |_client| {
            // drop the client
        })
    }

    #[test]
    fn accept_lots() {
        do run_in_mt_newsched_task {
            let times = 10;
            let path1 = next_test_unix();
            let path2 = path1.clone();
            let (port, chan) = oneshot();
            let port = Cell::new(port);
            let chan = Cell::new(chan);

            do spawntask {
                let mut acceptor = UnixListener::bind(&path1).listen();
                chan.take().send(());
                do times.times {
                    let mut client = acceptor.accept();
                    let mut buf = [0];
                    client.read(buf);
                    assert_eq!(buf[0], 100);
                }
            }

            do spawntask {
                port.take().recv();
                do times.times {
                    let mut stream = UnixStream::connect(&path2);
                    stream.write([100]);
                }
            }
        }
    }

    #[test]
    fn path_exists() {
        do run_in_mt_newsched_task {
            let path = next_test_unix();
            let _acceptor = UnixListener::bind(&path).listen();
            assert!(os::path_exists(&path));
        }
    }
}
<commit_msg>Handle another possible error in a unix pipe test<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Named pipes

This module contains the ability to communicate over named pipes with
synchronous I/O. On windows, this corresponds to talking over a Named Pipe,
while on Unix it corresponds to UNIX domain sockets.

These pipes are similar to TCP in the sense that you can have both a stream to a
server and a server itself. The server provided accepts other `UnixStream`
instances as clients.

*/

use prelude::*;

use c_str::ToCStr;
use rt::rtio::{IoFactory, RtioUnixListener, with_local_io};
use rt::rtio::{RtioUnixAcceptor, RtioPipe};
use rt::io::pipe::PipeStream;
use rt::io::{io_error, Listener, Acceptor, Reader, Writer};

/// A stream which communicates over a named pipe.
pub struct UnixStream {
    priv obj: PipeStream,
}

impl UnixStream {
    fn new(obj: ~RtioPipe) -> UnixStream {
        UnixStream { obj: PipeStream::new(obj) }
    }

    /// Connect to a pipe named by `path`. This will attempt to open a
    /// connection to the underlying socket.
    ///
    /// The returned stream will be closed when the object falls out of scope.
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if the connection
    /// could not be made.
    ///
    /// # Example
    ///
    ///     use std::rt::io::net::unix::UnixStream;
    ///
    ///     let server = Path("path/to/my/socket");
    ///     let mut stream = UnixStream::connect(&server);
    ///     stream.write([1, 2, 3]);
    ///
    pub fn connect<P: ToCStr>(path: &P) -> Option<UnixStream> {
        do with_local_io |io| {
            match io.unix_connect(&path.to_c_str()) {
                Ok(s) => Some(UnixStream::new(s)),
                Err(ioerr) => {
                    io_error::cond.raise(ioerr);
                    None
                }
            }
        }
    }
}

impl Reader for UnixStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.obj.read(buf) }
    fn eof(&mut self) -> bool { self.obj.eof() }
}

impl Writer for UnixStream {
    fn write(&mut self, buf: &[u8]) { self.obj.write(buf) }
    fn flush(&mut self) { self.obj.flush() }
}

pub struct UnixListener {
    priv obj: ~RtioUnixListener,
}

impl UnixListener {

    /// Creates a new listener, ready to receive incoming connections on the
    /// specified socket. The server will be named by `path`.
    ///
    /// This listener will be closed when it falls out of scope.
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if the specified
    /// path could not be bound.
    ///
    /// # Example
    ///
    ///     use std::rt::io::net::unix::UnixListener;
    ///
    ///     let server = Path("path/to/my/socket");
    ///     let mut stream = UnixListener::bind(&server);
    ///     for client in stream.incoming() {
    ///         let mut client = client;
    ///         client.write([1, 2, 3, 4]);
    ///     }
    ///
    pub fn bind<P: ToCStr>(path: &P) -> Option<UnixListener> {
        do with_local_io |io| {
            match io.unix_bind(&path.to_c_str()) {
                Ok(s) => Some(UnixListener{ obj: s }),
                Err(ioerr) => {
                    io_error::cond.raise(ioerr);
                    None
                }
            }
        }
    }
}

impl Listener<UnixStream, UnixAcceptor> for UnixListener {
    fn listen(self) -> Option<UnixAcceptor> {
        match self.obj.listen() {
            Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                None
            }
        }
    }
}

pub struct UnixAcceptor {
    priv obj: ~RtioUnixAcceptor,
}

impl Acceptor<UnixStream> for UnixAcceptor {
    fn accept(&mut self) -> Option<UnixStream> {
        match self.obj.accept() {
            Ok(s) => Some(UnixStream::new(s)),
            Err(ioerr) => {
                io_error::cond.raise(ioerr);
                None
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use prelude::*;
    use super::*;
    use cell::Cell;
    use rt::test::*;
    use rt::io::*;
    use rt::comm::oneshot;
    use os;

    fn smalltest(server: ~fn(UnixStream), client: ~fn(UnixStream)) {
        let server = Cell::new(server);
        let client = Cell::new(client);
        do run_in_mt_newsched_task {
            let server = Cell::new(server.take());
            let client = Cell::new(client.take());
            let path1 = next_test_unix();
            let path2 = path1.clone();
            let (port, chan) = oneshot();
            let port = Cell::new(port);
            let chan = Cell::new(chan);

            do spawntask {
                let mut acceptor = UnixListener::bind(&path1).listen();
                chan.take().send(());
                server.take()(acceptor.accept().unwrap());
            }

            do spawntask {
                port.take().recv();
                client.take()(UnixStream::connect(&path2).unwrap());
            }
        }
    }

    #[test]
    fn bind_error() {
        do run_in_mt_newsched_task {
            let mut called = false;
            do io_error::cond.trap(|e| {
                assert!(e.kind == PermissionDenied);
                called = true;
            }).inside {
                let listener = UnixListener::bind(&("path/to/nowhere"));
                assert!(listener.is_none());
            }
            assert!(called);
        }
    }

    #[test]
    fn connect_error() {
        do run_in_mt_newsched_task {
            let mut called = false;
            do io_error::cond.trap(|e| {
                assert_eq!(e.kind, OtherIoError);
                called = true;
            }).inside {
                let stream = UnixStream::connect(&("path/to/nowhere"));
                assert!(stream.is_none());
            }
            assert!(called);
        }
    }

    #[test]
    fn smoke() {
        smalltest(|mut server| {
            let mut buf = [0];
            server.read(buf);
            assert!(buf[0] == 99);
        }, |mut client| {
            client.write([99]);
        })
    }

    #[test]
    fn read_eof() {
        smalltest(|mut server| {
            let mut buf = [0];
            assert!(server.read(buf).is_none());
            assert!(server.read(buf).is_none());
        }, |_client| {
            // drop the client
        })
    }

    #[test]
    fn write_begone() {
        smalltest(|mut server| {
            let buf = [0];
            let mut stop = false;
            while !stop{
                do io_error::cond.trap(|e| {
                    assert!(e.kind == BrokenPipe || e.kind == NotConnected,
                            "unknown error {:?}", e);
                    stop = true;
                }).inside {
                    server.write(buf);
                }
            }
        }, |_client| {
            // drop the client
        })
    }

    #[test]
    fn accept_lots() {
        do run_in_mt_newsched_task {
            let times = 10;
            let path1 = next_test_unix();
            let path2 = path1.clone();
            let (port, chan) = oneshot();
            let port = Cell::new(port);
            let chan = Cell::new(chan);

            do spawntask {
                let mut acceptor = UnixListener::bind(&path1).listen();
                chan.take().send(());
                do times.times {
                    let mut client = acceptor.accept();
                    let mut buf = [0];
                    client.read(buf);
                    assert_eq!(buf[0], 100);
                }
            }

            do spawntask {
                port.take().recv();
                do times.times {
                    let mut stream = UnixStream::connect(&path2);
                    stream.write([100]);
                }
            }
        }
    }

    #[test]
    fn path_exists() {
        do run_in_mt_newsched_task {
            let path = next_test_unix();
            let _acceptor = UnixListener::bind(&path).listen();
            assert!(os::path_exists(&path));
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Hook into libgraphviz for rendering dataflow graphs for MIR.

use syntax::ast::NodeId;
use rustc::mir::repr::{BasicBlock, Mir};

use dot;
use dot::IntoCow;

use std::fmt::Debug;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::marker::PhantomData;
use std::mem;
use std::path::Path;

use super::super::MoveDataParamEnv;
use super::super::MirBorrowckCtxtPreDataflow;
use bitslice::bits_to_string;
use indexed_set::{Idx, IdxSet};
use super::{BitDenotation, DataflowState};

impl<O: BitDenotation> DataflowState<O> {
    fn each_bit<F>(&self, ctxt: &O::Ctxt, words: &IdxSet<O::Idx>, mut f: F)
        where F: FnMut(O::Idx) {
        //! Helper for iterating over the bits in a bitvector.

        let bits_per_block = self.operator.bits_per_block(ctxt);
        let usize_bits: usize = mem::size_of::<usize>() * 8;

        for (word_index, &word) in words.words().iter().enumerate() {
            if word != 0 {
                let base_index = word_index * usize_bits;
                for offset in 0..usize_bits {
                    let bit = 1 << offset;
                    if (word & bit) != 0 {
                        // NB: we round up the total number of bits
                        // that we store in any given bit set so that
                        // it is an even multiple of usize::BITS. This
                        // means that there may be some stray bits at
                        // the end that do not correspond to any
                        // actual value; that's why we first check
                        // that we are in range of bits_per_block.
                        let bit_index = base_index + offset as usize;
                        if bit_index >= bits_per_block {
                            return;
                        } else {
                            f(O::Idx::new(bit_index));
                        }
                    }
                }
            }
        }
    }

    pub fn interpret_set<'c, P>(&self,
                                ctxt: &'c O::Ctxt,
                                words: &IdxSet<O::Idx>,
                                render_idx: &P)
                                -> Vec<&'c Debug>
        where P: for <'b> Fn(&'b O::Ctxt, O::Idx) -> &'b Debug
    {
        let mut v = Vec::new();
        self.each_bit(ctxt, words, |i| {
            v.push(render_idx(ctxt, i));
        });
        v
    }
}

pub trait MirWithFlowState<'tcx> {
    type BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>;
    fn node_id(&self) -> NodeId;
    fn mir(&self) -> &Mir<'tcx>;
    fn analysis_ctxt(&self) -> &<Self::BD as BitDenotation>::Ctxt;
    fn flow_state(&self) -> &DataflowState<Self::BD>;
}

impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
    where 'a, 'tcx: 'a, BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>
{
    type BD = BD;
    fn node_id(&self) -> NodeId { self.node_id }
    fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
    fn analysis_ctxt(&self) -> &BD::Ctxt { &self.flow_state.ctxt }
    fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
}

struct Graph<'a, 'tcx, MWF:'a, P> where
    MWF: MirWithFlowState<'tcx>
{
    mbcx: &'a MWF,
    phantom: PhantomData<&'tcx ()>,
    render_idx: P,
}

pub fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
    mbcx: &MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>,
    path: &Path,
    render_idx: P)
    -> io::Result<()>
    where BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>,
          P: for <'b> Fn(&'b BD::Ctxt, BD::Idx) -> &'b Debug
{
    let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx };
    let mut v = Vec::new();
    dot::render(&g, &mut v)?;
    debug!("print_borrowck_graph_to path: {} node_id: {}",
           path.display(), mbcx.node_id);
    File::create(path).and_then(|mut f| f.write_all(&v))
}

pub type Node = BasicBlock;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Edge { source: BasicBlock, index: usize }

fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
    let succ_len = mir.basic_block_data(bb).terminator().successors().len();
    (0..succ_len).map(|index| Edge { source: bb, index: index}).collect()
}

impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
    where MWF: MirWithFlowState<'tcx>,
          P: for <'b> Fn(&'b <MWF::BD as BitDenotation>::Ctxt, <MWF::BD as BitDenotation>::Idx) -> &'b Debug,
{
    type Node = Node;
    type Edge = Edge;
    fn graph_id(&self) -> dot::Id {
        dot::Id::new(format!("graph_for_node_{}",
                             self.mbcx.node_id()))
            .unwrap()
    }

    fn node_id(&self, n: &Node) -> dot::Id {
        dot::Id::new(format!("bb_{}", n.index()))
            .unwrap()
    }

    fn node_label(&self, n: &Node) -> dot::LabelText {
        // A standard MIR label, as generated by write_node_label, is
        // presented in a single column in a table.
        //
        // The code below does a bunch of formatting work to format a
        // node (i.e. MIR basic-block) label with extra
        // dataflow-enriched information.  In particular, the goal is
        // to add extra columns that present the three dataflow
        // bitvectors, and the data those bitvectors represent.
        //
        // It presents it in the following format (where I am
        // presenting the table rendering via ASCII art, one line per
        // row of the table, and a chunk size of 3 rather than 5):
        //
        // ------  -----------------------  ------------  --------------------
        //                    [e1, e3, e4]
        //             [e8, e9] "= ENTRY:"  <ENTRY-BITS>
        // ------  -----------------------  ------------  --------------------
        // Left
        // Most
        // Column
        // Is
        // Just
        // Normal
        // Series
        // Of
        // MIR
        // Stmts
        // ------  -----------------------  ------------  --------------------
        //           [g1, g4, g5] "= GEN:"  <GEN-BITS>
        // ------  -----------------------  ------------  --------------------
        //                         "KILL:"  <KILL-BITS>   "=" [k1, k3, k8]
        //                                                [k9]
        // ------  -----------------------  ------------  --------------------
        //
        // (In addition, the added dataflow is rendered with a colored
        // background just so it will stand out compared to the
        // statements.)
        let mut v = Vec::new();
        let i = n.index();
        let chunk_size = 5;
        const BG_FLOWCONTENT: &'static str = r#"bgcolor="pink""#;
        const ALIGN_RIGHT: &'static str = r#"align="right""#;
        const FACE_MONOSPACE: &'static str = r#"FACE="Courier""#;
        fn chunked_present_left<W:io::Write>(w: &mut W,
                                             interpreted: &[&Debug],
                                             chunk_size: usize)
                                             -> io::Result<()>
        {
            // This function may emit a sequence of
's, but it
            // always finishes with an (unfinished)
            //

            //
            // Thus, after being called, one should finish both the
            // pending  as well as the
 itself.
            let mut seen_one = false;
            for c in interpreted.chunks(chunk_size) {
                if seen_one {
                    // if not the first row, finish off the previous row
                    write!(w, "
")?;
                }
                write!(w, "
	{objs:?}",
                       bg = BG_FLOWCONTENT,
                       align = ALIGN_RIGHT,
                       objs = c)?;
                seen_one = true;
            }
            if !seen_one {
                write!(w, "
	[]",
                       bg = BG_FLOWCONTENT,
                       align = ALIGN_RIGHT)?;
            }
            Ok(())
        }
        ::rustc_mir::graphviz::write_node_label(
            *n, self.mbcx.mir(), &mut v, 4,
            |w| {
                let ctxt = self.mbcx.analysis_ctxt();
                let flow = self.mbcx.flow_state();
                let entry_interp = flow.interpret_set(ctxt,
                                                      flow.sets.on_entry_set_for(i),
                                                      &self.render_idx);
                chunked_present_left(w, &entry_interp[..], chunk_size)?;
                let bits_per_block = flow.sets.bits_per_block();
                let entry = flow.sets.on_entry_set_for(i);
                debug!("entry set for i={i} bits_per_block: {bpb} entry: {e:?} interp: {ei:?}",
                       i=i, e=entry, bpb=bits_per_block, ei=entry_interp);
                write!(w, "= ENTRY:	{entrybits:?}	\

",
                       bg = BG_FLOWCONTENT,
                       face = FACE_MONOSPACE,
                       entrybits=bits_to_string(entry.words(), bits_per_block))
            },
            |w| {
                let ctxt = self.mbcx.analysis_ctxt();
                let flow = self.mbcx.flow_state();
                let gen_interp = flow.interpret_set(ctxt, flow.sets.gen_set_for(i), &self.render_idx);
                let kill_interp = flow.interpret_set(ctxt, flow.sets.kill_set_for(i), &self.render_idx);
                chunked_present_left(w, &gen_interp[..], chunk_size)?;
                let bits_per_block = flow.sets.bits_per_block();
                {
                    let gen = flow.sets.gen_set_for(i);
                    debug!("gen set for i={i} bits_per_block: {bpb} gen: {g:?} interp: {gi:?}",
                           i=i, g=gen, bpb=bits_per_block, gi=gen_interp);
                    write!(w, " = GEN:	{genbits:?}	\

",
                           bg = BG_FLOWCONTENT,
                           face = FACE_MONOSPACE,
                           genbits=bits_to_string(gen.words(), bits_per_block))?;
                }

                {
                    let kill = flow.sets.kill_set_for(i);
                    debug!("kill set for i={i} bits_per_block: {bpb} kill: {k:?} interp: {ki:?}",
                           i=i, k=kill, bpb=bits_per_block, ki=kill_interp);
                    write!(w, "
	KILL:	\
                                            {killbits:?}	",
                           bg = BG_FLOWCONTENT,
                           align = ALIGN_RIGHT,
                           face = FACE_MONOSPACE,
                           killbits=bits_to_string(kill.words(), bits_per_block))?;
                }

                // (chunked_present_right)
                let mut seen_one = false;
                for k in kill_interp.chunks(chunk_size) {
                    if !seen_one {
                        // continuation of row; this is fourth
                        write!(w, "= {kill:?}
",
                               bg = BG_FLOWCONTENT,
                               kill=k)?;
                    } else {
                        // new row, with indent of three 's
                        write!(w, "
			{kill:?}
",
                               bg = BG_FLOWCONTENT,
                               kill=k)?;
                    }
                    seen_one = true;
                }
                if !seen_one {
                    write!(w, "= []
",
                           bg = BG_FLOWCONTENT)?;
                }

                Ok(())
            })
            .unwrap();
        dot::LabelText::html(String::from_utf8(v).unwrap())
    }

    fn node_shape(&self, _n: &Node) -> Option<dot::LabelText> {
        Some(dot::LabelText::label("none"))
    }
}

impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
    where MWF: MirWithFlowState<'tcx>
{
    type Node = Node;
    type Edge = Edge;
    fn nodes(&self) -> dot::Nodes<Node> {
        self.mbcx.mir().all_basic_blocks().into_cow()
    }

    fn edges(&self) -> dot::Edges<Edge> {
        let mir = self.mbcx.mir();
        let blocks = mir.all_basic_blocks();
        // base initial capacity on assumption every block has at
        // least one outgoing edge (Which should be true for all
        // blocks but one, the exit-block).
        let mut edges = Vec::with_capacity(blocks.len());
        for bb in blocks {
            let outgoing = outgoing(mir, bb);
            edges.extend(outgoing.into_iter());
        }
        edges.into_cow()
    }

    fn source(&self, edge: &Edge) -> Node {
        edge.source
    }

    fn target(&self, edge: &Edge) -> Node {
        let mir = self.mbcx.mir();
        mir.basic_block_data(edge.source).terminator().successors()[edge.index]
    }
}
<commit_msg>placate tidy in `mir::dataflow::graphviz`.<commit_after>// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Hook into libgraphviz for rendering dataflow graphs for MIR.

use syntax::ast::NodeId;
use rustc::mir::repr::{BasicBlock, Mir};

use dot;
use dot::IntoCow;

use std::fmt::Debug;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::marker::PhantomData;
use std::mem;
use std::path::Path;

use super::super::MoveDataParamEnv;
use super::super::MirBorrowckCtxtPreDataflow;
use bitslice::bits_to_string;
use indexed_set::{Idx, IdxSet};
use super::{BitDenotation, DataflowState};

impl<O: BitDenotation> DataflowState<O> {
    fn each_bit<F>(&self, ctxt: &O::Ctxt, words: &IdxSet<O::Idx>, mut f: F)
        where F: FnMut(O::Idx) {
        //! Helper for iterating over the bits in a bitvector.

        let bits_per_block = self.operator.bits_per_block(ctxt);
        let usize_bits: usize = mem::size_of::<usize>() * 8;

        for (word_index, &word) in words.words().iter().enumerate() {
            if word != 0 {
                let base_index = word_index * usize_bits;
                for offset in 0..usize_bits {
                    let bit = 1 << offset;
                    if (word & bit) != 0 {
                        // NB: we round up the total number of bits
                        // that we store in any given bit set so that
                        // it is an even multiple of usize::BITS. This
                        // means that there may be some stray bits at
                        // the end that do not correspond to any
                        // actual value; that's why we first check
                        // that we are in range of bits_per_block.
                        let bit_index = base_index + offset as usize;
                        if bit_index >= bits_per_block {
                            return;
                        } else {
                            f(O::Idx::new(bit_index));
                        }
                    }
                }
            }
        }
    }

    pub fn interpret_set<'c, P>(&self,
                                ctxt: &'c O::Ctxt,
                                words: &IdxSet<O::Idx>,
                                render_idx: &P)
                                -> Vec<&'c Debug>
        where P: for <'b> Fn(&'b O::Ctxt, O::Idx) -> &'b Debug
    {
        let mut v = Vec::new();
        self.each_bit(ctxt, words, |i| {
            v.push(render_idx(ctxt, i));
        });
        v
    }
}

pub trait MirWithFlowState<'tcx> {
    type BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>;
    fn node_id(&self) -> NodeId;
    fn mir(&self) -> &Mir<'tcx>;
    fn analysis_ctxt(&self) -> &<Self::BD as BitDenotation>::Ctxt;
    fn flow_state(&self) -> &DataflowState<Self::BD>;
}

impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
    where 'a, 'tcx: 'a, BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>
{
    type BD = BD;
    fn node_id(&self) -> NodeId { self.node_id }
    fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
    fn analysis_ctxt(&self) -> &BD::Ctxt { &self.flow_state.ctxt }
    fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
}

struct Graph<'a, 'tcx, MWF:'a, P> where
    MWF: MirWithFlowState<'tcx>
{
    mbcx: &'a MWF,
    phantom: PhantomData<&'tcx ()>,
    render_idx: P,
}

pub fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
    mbcx: &MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>,
    path: &Path,
    render_idx: P)
    -> io::Result<()>
    where BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>,
          P: for <'b> Fn(&'b BD::Ctxt, BD::Idx) -> &'b Debug
{
    let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx };
    let mut v = Vec::new();
    dot::render(&g, &mut v)?;
    debug!("print_borrowck_graph_to path: {} node_id: {}",
           path.display(), mbcx.node_id);
    File::create(path).and_then(|mut f| f.write_all(&v))
}

pub type Node = BasicBlock;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Edge { source: BasicBlock, index: usize }

fn outgoing(mir: &Mir, bb: BasicBlock) -> Vec<Edge> {
    let succ_len = mir.basic_block_data(bb).terminator().successors().len();
    (0..succ_len).map(|index| Edge { source: bb, index: index}).collect()
}

impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
    where MWF: MirWithFlowState<'tcx>,
          P: for <'b> Fn(&'b <MWF::BD as BitDenotation>::Ctxt,
                         <MWF::BD as BitDenotation>::Idx)
                         -> &'b Debug,
{
    type Node = Node;
    type Edge = Edge;
    fn graph_id(&self) -> dot::Id {
        dot::Id::new(format!("graph_for_node_{}",
                             self.mbcx.node_id()))
            .unwrap()
    }

    fn node_id(&self, n: &Node) -> dot::Id {
        dot::Id::new(format!("bb_{}", n.index()))
            .unwrap()
    }

    fn node_label(&self, n: &Node) -> dot::LabelText {
        // A standard MIR label, as generated by write_node_label, is
        // presented in a single column in a table.
        //
        // The code below does a bunch of formatting work to format a
        // node (i.e. MIR basic-block) label with extra
        // dataflow-enriched information.  In particular, the goal is
        // to add extra columns that present the three dataflow
        // bitvectors, and the data those bitvectors represent.
        //
        // It presents it in the following format (where I am
        // presenting the table rendering via ASCII art, one line per
        // row of the table, and a chunk size of 3 rather than 5):
        //
        // ------  -----------------------  ------------  --------------------
        //                    [e1, e3, e4]
        //             [e8, e9] "= ENTRY:"  <ENTRY-BITS>
        // ------  -----------------------  ------------  --------------------
        // Left
        // Most
        // Column
        // Is
        // Just
        // Normal
        // Series
        // Of
        // MIR
        // Stmts
        // ------  -----------------------  ------------  --------------------
        //           [g1, g4, g5] "= GEN:"  <GEN-BITS>
        // ------  -----------------------  ------------  --------------------
        //                         "KILL:"  <KILL-BITS>   "=" [k1, k3, k8]
        //                                                [k9]
        // ------  -----------------------  ------------  --------------------
        //
        // (In addition, the added dataflow is rendered with a colored
        // background just so it will stand out compared to the
        // statements.)
        let mut v = Vec::new();
        let i = n.index();
        let chunk_size = 5;
        const BG_FLOWCONTENT: &'static str = r#"bgcolor="pink""#;
        const ALIGN_RIGHT: &'static str = r#"align="right""#;
        const FACE_MONOSPACE: &'static str = r#"FACE="Courier""#;
        fn chunked_present_left<W:io::Write>(w: &mut W,
                                             interpreted: &[&Debug],
                                             chunk_size: usize)
                                             -> io::Result<()>
        {
            // This function may emit a sequence of
's, but it
            // always finishes with an (unfinished)
            //

            //
            // Thus, after being called, one should finish both the
            // pending  as well as the
 itself.
            let mut seen_one = false;
            for c in interpreted.chunks(chunk_size) {
                if seen_one {
                    // if not the first row, finish off the previous row
                    write!(w, "
")?;
                }
                write!(w, "
	{objs:?}",
                       bg = BG_FLOWCONTENT,
                       align = ALIGN_RIGHT,
                       objs = c)?;
                seen_one = true;
            }
            if !seen_one {
                write!(w, "
	[]",
                       bg = BG_FLOWCONTENT,
                       align = ALIGN_RIGHT)?;
            }
            Ok(())
        }
        ::rustc_mir::graphviz::write_node_label(
            *n, self.mbcx.mir(), &mut v, 4,
            |w| {
                let ctxt = self.mbcx.analysis_ctxt();
                let flow = self.mbcx.flow_state();
                let entry_interp = flow.interpret_set(ctxt,
                                                      flow.sets.on_entry_set_for(i),
                                                      &self.render_idx);
                chunked_present_left(w, &entry_interp[..], chunk_size)?;
                let bits_per_block = flow.sets.bits_per_block();
                let entry = flow.sets.on_entry_set_for(i);
                debug!("entry set for i={i} bits_per_block: {bpb} entry: {e:?} interp: {ei:?}",
                       i=i, e=entry, bpb=bits_per_block, ei=entry_interp);
                write!(w, "= ENTRY:	{entrybits:?}	\

",
                       bg = BG_FLOWCONTENT,
                       face = FACE_MONOSPACE,
                       entrybits=bits_to_string(entry.words(), bits_per_block))
            },
            |w| {
                let ctxt = self.mbcx.analysis_ctxt();
                let flow = self.mbcx.flow_state();
                let gen_interp =
                    flow.interpret_set(ctxt, flow.sets.gen_set_for(i), &self.render_idx);
                let kill_interp =
                    flow.interpret_set(ctxt, flow.sets.kill_set_for(i), &self.render_idx);
                chunked_present_left(w, &gen_interp[..], chunk_size)?;
                let bits_per_block = flow.sets.bits_per_block();
                {
                    let gen = flow.sets.gen_set_for(i);
                    debug!("gen set for i={i} bits_per_block: {bpb} gen: {g:?} interp: {gi:?}",
                           i=i, g=gen, bpb=bits_per_block, gi=gen_interp);
                    write!(w, " = GEN:	{genbits:?}	\

",
                           bg = BG_FLOWCONTENT,
                           face = FACE_MONOSPACE,
                           genbits=bits_to_string(gen.words(), bits_per_block))?;
                }

                {
                    let kill = flow.sets.kill_set_for(i);
                    debug!("kill set for i={i} bits_per_block: {bpb} kill: {k:?} interp: {ki:?}",
                           i=i, k=kill, bpb=bits_per_block, ki=kill_interp);
                    write!(w, "
	KILL:	\
                                            {killbits:?}	",
                           bg = BG_FLOWCONTENT,
                           align = ALIGN_RIGHT,
                           face = FACE_MONOSPACE,
                           killbits=bits_to_string(kill.words(), bits_per_block))?;
                }

                // (chunked_present_right)
                let mut seen_one = false;
                for k in kill_interp.chunks(chunk_size) {
                    if !seen_one {
                        // continuation of row; this is fourth
                        write!(w, "= {kill:?}
",
                               bg = BG_FLOWCONTENT,
                               kill=k)?;
                    } else {
                        // new row, with indent of three 's
                        write!(w, "
			{kill:?}
",
                               bg = BG_FLOWCONTENT,
                               kill=k)?;
                    }
                    seen_one = true;
                }
                if !seen_one {
                    write!(w, "= []
",
                           bg = BG_FLOWCONTENT)?;
                }

                Ok(())
            })
            .unwrap();
        dot::LabelText::html(String::from_utf8(v).unwrap())
    }

    fn node_shape(&self, _n: &Node) -> Option<dot::LabelText> {
        Some(dot::LabelText::label("none"))
    }
}

impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
    where MWF: MirWithFlowState<'tcx>
{
    type Node = Node;
    type Edge = Edge;
    fn nodes(&self) -> dot::Nodes<Node> {
        self.mbcx.mir().all_basic_blocks().into_cow()
    }

    fn edges(&self) -> dot::Edges<Edge> {
        let mir = self.mbcx.mir();
        let blocks = mir.all_basic_blocks();
        // base initial capacity on assumption every block has at
        // least one outgoing edge (Which should be true for all
        // blocks but one, the exit-block).
        let mut edges = Vec::with_capacity(blocks.len());
        for bb in blocks {
            let outgoing = outgoing(mir, bb);
            edges.extend(outgoing.into_iter());
        }
        edges.into_cow()
    }

    fn source(&self, edge: &Edge) -> Node {
        edge.source
    }

    fn target(&self, edge: &Edge) -> Node {
        let mir = self.mbcx.mir();
        mir.basic_block_data(edge.source).terminator().successors()[edge.index]
    }
}
<|endoftext|>


<commit_before>//! Implements `StdTimeManager`.

use std::sync::RwLock;
use std::time::SystemTime;
use board::*;
use depth::*;
use value::*;
use search_executor::*;
use hash_table::Variation;
use search_node::SearchNode;
use time_manager::{TimeManager, RemainingTime};
use uci::{SetOption, OptionDescription};

/// Implements the `TimeManager` trait.
pub struct StdTimeManager {
    started_at: SystemTime,
    depth: Depth,
    value: Value,
    extrapolation_points: Vec<(f64, f64)>,
    hard_limit: f64,
    allotted_time: f64,
    must_play: bool,
}

impl<S> TimeManager<S> for StdTimeManager
    where S: SearchExecutor<ReportData = Vec<Variation>>
{
    fn new(position: &S::SearchNode, time: RemainingTime) -> StdTimeManager {
        // Get our remaining time and increment (in milliseconds).
        let (t, inc) = if position.board().to_move == WHITE {
            (time.white_millis as f64, time.winc_millis as f64)
        } else {
            (time.black_millis as f64, time.binc_millis as f64)
        };

        // Get the number of moves until the next time control, or if
        // not available, guess the number of moves to the end of the
        // game.
        let n = match time.movestogo.unwrap_or(0) {
            0 => 40,
            n => n,
        } as f64;

        // Calculate the total time we have.
        let time_heap = t + inc * (n - 1.0);

        // Set a hard limit for the time we will spend on this
        // move. Thinking longer that that would be reckless.
        let hard_limit = (t / n.sqrt() + inc).min(t - 1000.0);

        StdTimeManager {
            started_at: SystemTime::now(),
            depth: 0,
            value: VALUE_UNKNOWN,
            extrapolation_points: Vec::with_capacity(32),
            hard_limit: if position.legal_moves().len() > 1 {
                hard_limit
            } else {
                // When there is only one legal move, the engine is
                // allowed to think just a fraction of a second in
                // order to find a good ponder move.
                hard_limit.min(500.0)
            },
            allotted_time: if *PONDERING_IS_ALLOWED.read().unwrap() {
                // Statistically, the move we ponder will be played in
                // 50% of the cases. Therefore, in principal we should
                // add half of opponent's thinking time to our time
                // heap. In reality we do not know how opponent's time
                // will be spend, so we speculatively increase our
                // time heap by 50%.
                1.5 * time_heap / n
            } else {
                time_heap / n
            },
            must_play: false,
        }
    }

    fn update(&mut self, report: &SearchReport<Vec<Variation>>) {
        let &SearchReport { ref depth, ref value, ref searched_nodes, .. } = report;
        if *depth > self.depth {
            self.depth = *depth;
            if *searched_nodes < 100 {
                return; // We ignore the first few depths.
            }
            let t = elapsed_millis(&self.started_at);
            let depth = *depth as f64;
            let searched_nodes = *searched_nodes as f64;

            // We maintain a list of data points so as to be able to
            // intelligently guess how much time it will take for the
            // next search depth to complete. (We apply an exponential
            // regression over the last `M` points in the list.)
            const M: usize = 5;
            self.extrapolation_points.push((depth, searched_nodes.ln()));
            let expected_duration = match self.extrapolation_points.len() {
                n if n >= M => {
                    let last_m = &self.extrapolation_points[n - M..];
                    let factor = extrapolate(last_m, depth + 1.0).exp() / searched_nodes;

                    // Update `BRANCHING_FACTOR`. This is an average
                    // branching factor calculated over the last few
                    // moves.
                    if n == M {
                        let mut bf = BRANCHING_FACTOR.write().unwrap();
                        *bf = (*bf * 2.0 + factor) / 3.0;
                    }

                    factor * t
                }
                _ => *BRANCHING_FACTOR.read().unwrap() * t,
            };

            // We may need to revise the allotted time if position's
            // evaluation has changed a lot with the newly completed
            // depth.
            if (expected_duration > self.allotted_time) &&
               (self.value != VALUE_UNKNOWN && *value != VALUE_UNKNOWN) &&
               (self.value as isize - *value as isize).abs() >= 25 {
                self.allotted_time = expected_duration;
            }
            self.value = *value;

            // We try to stay as close as possible to the allotted
            // time, without crossing the hard limit.
            self.must_play = expected_duration > self.hard_limit ||
                             expected_duration > self.allotted_time &&
                             expected_duration - self.allotted_time > self.allotted_time - t;
        }
    }

    #[allow(unused_variables)]
    fn must_play(&self, search: &S) -> bool {
        self.must_play || elapsed_millis(&self.started_at) > self.hard_limit
    }
}

impl SetOption for StdTimeManager {
    fn options() -> Vec<(String, OptionDescription)> {
        vec![("Ponder".to_string(), OptionDescription::Check { default: false })]
    }

    fn set_option(name: &str, value: &str) {
        if name == "Ponder" {
            match value {
                "true" => *PONDERING_IS_ALLOWED.write().unwrap() = true,
                "false" => *PONDERING_IS_ALLOWED.write().unwrap() = false,
                _ => (),
            }
        }
    }
}

lazy_static! {
    static ref PONDERING_IS_ALLOWED: RwLock<bool> = RwLock::new(false);
    static ref BRANCHING_FACTOR: RwLock<f64> = RwLock::new(2.0);
}

/// A helper function. It calculates the elapsed milliseconds since a
/// given time.
fn elapsed_millis(since: &SystemTime) -> f64 {
    let d = since.elapsed().unwrap();
    (1000 * d.as_secs()) as f64 + (d.subsec_nanos() / 1_000_000) as f64
}

/// A helper function. It linearly extrapolates the value y(x) using
/// the (x, y) values in `points` as a reference.
fn extrapolate(points: &[(f64, f64)], x: f64) -> f64 {
    debug_assert!(points.len() > 1);
    let sum_x = points.iter().fold(0.0, |acc, &p| acc + p.0);
    let sum_y = points.iter().fold(0.0, |acc, &p| acc + p.1);
    let sum_xx = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.0);
    let sum_xy = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.1);
    let n = points.len() as f64;
    let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
    let intercept = (sum_y - slope * sum_x) / n;
    slope * x + intercept
}

#[cfg(test)]
mod tests {
    #[test]
    fn linear_regression() {
        use super::extrapolate;
        let points = vec![(21.0, 1.0), (22.0, 2.0), (23.0, 3.0), (24.0, 4.0)];
        let x = 25.0;
        let y = extrapolate(&points, x);
        assert!(4.99 < y && y < 5.01);
    }
}
<commit_msg>make sure the branching factor is >= 1.0<commit_after>//! Implements `StdTimeManager`.

use std::sync::RwLock;
use std::time::SystemTime;
use board::*;
use depth::*;
use value::*;
use search_executor::*;
use hash_table::Variation;
use search_node::SearchNode;
use time_manager::{TimeManager, RemainingTime};
use uci::{SetOption, OptionDescription};

/// Implements the `TimeManager` trait.
pub struct StdTimeManager {
    started_at: SystemTime,
    depth: Depth,
    value: Value,
    extrapolation_points: Vec<(f64, f64)>,
    hard_limit: f64,
    allotted_time: f64,
    must_play: bool,
}

impl<S> TimeManager<S> for StdTimeManager
    where S: SearchExecutor<ReportData = Vec<Variation>>
{
    fn new(position: &S::SearchNode, time: RemainingTime) -> StdTimeManager {
        // Get our remaining time and increment (in milliseconds).
        let (t, inc) = if position.board().to_move == WHITE {
            (time.white_millis as f64, time.winc_millis as f64)
        } else {
            (time.black_millis as f64, time.binc_millis as f64)
        };

        // Get the number of moves until the next time control, or if
        // not available, guess the number of moves to the end of the
        // game.
        let n = match time.movestogo.unwrap_or(0) {
            0 => 40,
            n => n,
        } as f64;

        // Calculate the total time we have.
        let time_heap = t + inc * (n - 1.0);

        // Set a hard limit for the time we will spend on this
        // move. Thinking longer that that would be reckless.
        let hard_limit = (t / n.sqrt() + inc).min(t - 1000.0);

        StdTimeManager {
            started_at: SystemTime::now(),
            depth: 0,
            value: VALUE_UNKNOWN,
            extrapolation_points: Vec::with_capacity(32),
            hard_limit: if position.legal_moves().len() > 1 {
                hard_limit
            } else {
                // When there is only one legal move, the engine is
                // allowed to think just a fraction of a second in
                // order to find a good ponder move.
                hard_limit.min(500.0)
            },
            allotted_time: if *PONDERING_IS_ALLOWED.read().unwrap() {
                // Statistically, the move we ponder will be played in
                // 50% of the cases. Therefore, in principal we should
                // add half of opponent's thinking time to our time
                // heap. In reality we do not know how opponent's time
                // will be spend, so we speculatively increase our
                // time heap by 50%.
                1.5 * time_heap / n
            } else {
                time_heap / n
            },
            must_play: false,
        }
    }

    fn update(&mut self, report: &SearchReport<Vec<Variation>>) {
        let &SearchReport { ref depth, ref value, ref searched_nodes, .. } = report;
        if *depth > self.depth {
            self.depth = *depth;
            if *searched_nodes < 100 {
                return; // We ignore the first few depths.
            }
            let t = elapsed_millis(&self.started_at);
            let depth = *depth as f64;
            let searched_nodes = *searched_nodes as f64;

            // We maintain a list of data points so as to be able to
            // intelligently guess how much time it will take for the
            // next search depth to complete. (We apply an exponential
            // regression over the last `M` points in the list.)
            const M: usize = 5;
            self.extrapolation_points.push((depth, searched_nodes.ln()));
            let expected_duration = match self.extrapolation_points.len() {
                n if n >= M => {
                    let last_m = &self.extrapolation_points[n - M..];
                    let factor = (extrapolate(last_m, depth + 1.0).exp() / searched_nodes).max(1.0);

                    // Update `BRANCHING_FACTOR`. This is an average
                    // branching factor calculated over the last few
                    // moves.
                    if n == M {
                        let mut bf = BRANCHING_FACTOR.write().unwrap();
                        *bf = (*bf * 2.0 + factor) / 3.0;
                    }

                    factor * t
                }
                _ => *BRANCHING_FACTOR.read().unwrap() * t,
            };

            // We may need to revise the allotted time if position's
            // evaluation has changed a lot with the newly completed
            // depth.
            if (expected_duration > self.allotted_time) &&
               (self.value != VALUE_UNKNOWN && *value != VALUE_UNKNOWN) &&
               (self.value as isize - *value as isize).abs() >= 25 {
                self.allotted_time = expected_duration;
            }
            self.value = *value;

            // We try to stay as close as possible to the allotted
            // time, without crossing the hard limit.
            self.must_play = expected_duration > self.hard_limit ||
                             expected_duration > self.allotted_time &&
                             expected_duration - self.allotted_time > self.allotted_time - t;
        }
    }

    #[allow(unused_variables)]
    fn must_play(&self, search: &S) -> bool {
        self.must_play || elapsed_millis(&self.started_at) > self.hard_limit
    }
}

impl SetOption for StdTimeManager {
    fn options() -> Vec<(String, OptionDescription)> {
        vec![("Ponder".to_string(), OptionDescription::Check { default: false })]
    }

    fn set_option(name: &str, value: &str) {
        if name == "Ponder" {
            match value {
                "true" => *PONDERING_IS_ALLOWED.write().unwrap() = true,
                "false" => *PONDERING_IS_ALLOWED.write().unwrap() = false,
                _ => (),
            }
        }
    }
}

lazy_static! {
    static ref PONDERING_IS_ALLOWED: RwLock<bool> = RwLock::new(false);
    static ref BRANCHING_FACTOR: RwLock<f64> = RwLock::new(2.0);
}

/// A helper function. It calculates the elapsed milliseconds since a
/// given time.
fn elapsed_millis(since: &SystemTime) -> f64 {
    let d = since.elapsed().unwrap();
    (1000 * d.as_secs()) as f64 + (d.subsec_nanos() / 1_000_000) as f64
}

/// A helper function. It linearly extrapolates the value y(x) using
/// the (x, y) values in `points` as a reference.
fn extrapolate(points: &[(f64, f64)], x: f64) -> f64 {
    debug_assert!(points.len() > 1);
    let sum_x = points.iter().fold(0.0, |acc, &p| acc + p.0);
    let sum_y = points.iter().fold(0.0, |acc, &p| acc + p.1);
    let sum_xx = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.0);
    let sum_xy = points.iter().fold(0.0, |acc, &p| acc + p.0 * p.1);
    let n = points.len() as f64;
    let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
    let intercept = (sum_y - slope * sum_x) / n;
    slope * x + intercept
}

#[cfg(test)]
mod tests {
    #[test]
    fn linear_regression() {
        use super::extrapolate;
        let points = vec![(21.0, 1.0), (22.0, 2.0), (23.0, 3.0), (24.0, 4.0)];
        let x = 25.0;
        let y = extrapolate(&points, x);
        assert!(4.99 < y && y < 5.01);
    }
}
<|endoftext|>


<commit_before>use libimagstore::store::Entry;

use builtin::header::field_path::FieldPath;
use filter::Filter;

use toml::Value;

pub struct FieldIsEmpty {
    header_field_path: FieldPath,
}

impl FieldIsEmpty {

    pub fn new(path: FieldPath) -> FieldIsEmpty {
        FieldIsEmpty {
            header_field_path: path,
        }
    }

}

impl Filter for FieldIsEmpty {

    fn filter(&self, e: &Entry) -> bool {
        e.get_header()
            .read(&self.header_field_path[..])
            .map(|v| {
                match v {
                    Some(Value::Array(a))   => a.is_empty(),
                    Some(Value::Boolean(_)) => false,
                    Some(Value::Float(_))   => false,
                    Some(Value::Integer(_)) => false,
                    Some(Value::String(_))  => false,
                    Some(Value::Table(t))   => t.is_empty(),
                    _                       => true,
                }
            })
            .unwrap_or(false)
    }

}

<commit_msg>Fix semantics if is-empty filter<commit_after>use libimagstore::store::Entry;

use builtin::header::field_path::FieldPath;
use filter::Filter;

use toml::Value;

pub struct FieldIsEmpty {
    header_field_path: FieldPath,
}

impl FieldIsEmpty {

    pub fn new(path: FieldPath) -> FieldIsEmpty {
        FieldIsEmpty {
            header_field_path: path,
        }
    }

}

impl Filter for FieldIsEmpty {

    fn filter(&self, e: &Entry) -> bool {
        e.get_header()
            .read(&self.header_field_path[..])
            .map(|v| {
                match v {
                    Some(Value::Array(a))   => a.is_empty(),
                    Some(Value::Boolean(_)) => false,
                    Some(Value::Float(_))   => false,
                    Some(Value::Integer(_)) => false,
                    Some(Value::String(s))  => s.is_empty(),
                    Some(Value::Table(t))   => t.is_empty(),
                    _                       => true,
                }
            })
            .unwrap_or(false)
    }

}

<|endoftext|>


<commit_before>use crate::{pagecache::*, *};

/// A pending log reservation which can be aborted or completed.
/// NB the holder should quickly call `complete` or `abort` as
/// taking too long to decide will cause the underlying IO
/// buffer to become blocked.
#[derive(Debug)]
pub struct Reservation<'a> {
    pub(super) log: &'a Log,
    pub(super) iobuf: Arc<IoBuf>,
    pub(super) buf: &'a mut [u8],
    pub(super) flushed: bool,
    pub pointer: DiskPtr,
    pub lsn: Lsn,
    pub(super) is_heap_item_rewrite: bool,
    pub(super) header_len: usize,
}

impl<'a> Drop for Reservation<'a> {
    fn drop(&mut self) {
        // We auto-abort if the user never uses a reservation.
        if !self.flushed {
            if let Err(e) = self.flush(false) {
                self.log.iobufs.set_global_error(e);
            }
        }
    }
}

impl<'a> Reservation<'a> {
    /// Cancel the reservation, placing a failed flush on disk, returning
    /// the (cancelled) log sequence number and file offset.
    pub fn abort(mut self) -> Result<(Lsn, DiskPtr)> {
        if self.pointer.is_heap_item() && !self.is_heap_item_rewrite {
            // we can instantly free this heap item because its pointer
            // is assumed to have failed to have been installed into
            // the pagetable, so we can assume nobody is operating
            // on it.

            trace!(
                "removing heap item for aborted reservation at lsn {}",
                self.pointer
            );

            self.log.config.heap.free(self.pointer.heap_id().unwrap());
        }

        self.flush(false)
    }

    /// Complete the reservation, placing the buffer on disk. returns
    /// the log sequence number of the write, and the file offset.
    pub fn complete(mut self) -> Result<(Lsn, DiskPtr)> {
        self.flush(true)
    }

    /// Refills the reservation buffer with new data.
    /// Must supply a buffer of an identical length
    /// as the one initially provided. Don't use this
    /// on messages subject to compression etc...
    ///
    /// # Panics
    ///
    /// Will panic if the reservation is not the correct
    /// size to hold a serialized Lsn.
    #[doc(hidden)]
    pub fn mark_writebatch(self, peg_lsn: Lsn) -> Result<(Lsn, DiskPtr)> {
        trace!(
            "writing batch required stable lsn {} into \
             BatchManifest at lid {:?} peg_lsn {}",
            peg_lsn,
            self.pointer.lid(),
            self.lsn
        );

        if self.lsn == peg_lsn {
            // this can happen because high-level tree updates
            // may result in no work happening.
            self.abort()
        } else {
            self.buf[4] = MessageKind::BatchManifest.into();

            let buf = lsn_to_arr(peg_lsn);

            let dst = &mut self.buf[self.header_len..];

            dst.copy_from_slice(&buf);

            let mut intervals = self.log.iobufs.intervals.lock();
            intervals.mark_batch((self.lsn, peg_lsn));
            drop(intervals);

            self.complete()
        }
    }

    fn flush(&mut self, valid: bool) -> Result<(Lsn, DiskPtr)> {
        if self.flushed {
            panic!("flushing already-flushed reservation!");
        }

        self.flushed = true;

        if !valid {
            // don't actually zero the message, still check its hash
            // on recovery to find corruption.
            self.buf[4] = MessageKind::Canceled.into();
        }

        let crc32 = calculate_message_crc32(
            self.buf[..self.header_len].as_ref(),
            &self.buf[self.header_len..],
        );
        let crc32_arr = u32_to_arr(crc32);

        #[allow(unsafe_code)]
        unsafe {
            std::ptr::copy_nonoverlapping(
                crc32_arr.as_ptr(),
                self.buf.as_mut_ptr(),
                std::mem::size_of::<u32>(),
            );
        }
        self.log.exit_reservation(&self.iobuf)?;

        Ok((self.lsn, self.pointer))
    }
}
<commit_msg>Zero uninitialized reservation bytes to avoid UB<commit_after>use crate::{pagecache::*, *};

/// A pending log reservation which can be aborted or completed.
/// NB the holder should quickly call `complete` or `abort` as
/// taking too long to decide will cause the underlying IO
/// buffer to become blocked.
#[derive(Debug)]
pub struct Reservation<'a> {
    pub(super) log: &'a Log,
    pub(super) iobuf: Arc<IoBuf>,
    pub(super) buf: &'a mut [u8],
    pub(super) flushed: bool,
    pub pointer: DiskPtr,
    pub lsn: Lsn,
    pub(super) is_heap_item_rewrite: bool,
    pub(super) header_len: usize,
}

impl<'a> Drop for Reservation<'a> {
    fn drop(&mut self) {
        // We auto-abort if the user never uses a reservation.
        if !self.flushed {
            if let Err(e) = self.flush(false) {
                self.log.iobufs.set_global_error(e);
            }
        }
    }
}

impl<'a> Reservation<'a> {
    /// Cancel the reservation, placing a failed flush on disk, returning
    /// the (cancelled) log sequence number and file offset.
    pub fn abort(mut self) -> Result<(Lsn, DiskPtr)> {
        if self.pointer.is_heap_item() && !self.is_heap_item_rewrite {
            // we can instantly free this heap item because its pointer
            // is assumed to have failed to have been installed into
            // the pagetable, so we can assume nobody is operating
            // on it.

            trace!(
                "removing heap item for aborted reservation at lsn {}",
                self.pointer
            );

            self.log.config.heap.free(self.pointer.heap_id().unwrap());
        }

        self.flush(false)
    }

    /// Complete the reservation, placing the buffer on disk. returns
    /// the log sequence number of the write, and the file offset.
    pub fn complete(mut self) -> Result<(Lsn, DiskPtr)> {
        self.flush(true)
    }

    /// Refills the reservation buffer with new data.
    /// Must supply a buffer of an identical length
    /// as the one initially provided. Don't use this
    /// on messages subject to compression etc...
    ///
    /// # Panics
    ///
    /// Will panic if the reservation is not the correct
    /// size to hold a serialized Lsn.
    #[doc(hidden)]
    pub fn mark_writebatch(self, peg_lsn: Lsn) -> Result<(Lsn, DiskPtr)> {
        trace!(
            "writing batch required stable lsn {} into \
             BatchManifest at lid {:?} peg_lsn {}",
            peg_lsn,
            self.pointer.lid(),
            self.lsn
        );

        if self.lsn == peg_lsn {
            // this can happen because high-level tree updates
            // may result in no work happening.
            self.abort()
        } else {
            self.buf[4] = MessageKind::BatchManifest.into();

            let buf = lsn_to_arr(peg_lsn);

            let dst = &mut self.buf[self.header_len..];

            dst.copy_from_slice(&buf);

            let mut intervals = self.log.iobufs.intervals.lock();
            intervals.mark_batch((self.lsn, peg_lsn));
            drop(intervals);

            self.complete()
        }
    }

    fn flush(&mut self, valid: bool) -> Result<(Lsn, DiskPtr)> {
        if self.flushed {
            panic!("flushing already-flushed reservation!");
        }

        self.flushed = true;

        if !valid {
            self.buf[4] = MessageKind::Canceled.into();

            // zero the message contents to prevent UB
            #[allow(unsafe_code)]
            unsafe {
                std::ptr::write_bytes(
                    self.buf[self.header_len..].as_mut_ptr(),
                    0,
                    self.buf.len() - self.header_len,
                )
            }
        }

        // zero the crc bytes to prevent UB
        #[allow(unsafe_code)]
        unsafe {
            std::ptr::write_bytes(
                self.buf[..].as_mut_ptr(),
                0,
                std::mem::size_of::<u32>(),
            )
        }

        let crc32 = calculate_message_crc32(
            self.buf[..self.header_len].as_ref(),
            &self.buf[self.header_len..],
        );
        let crc32_arr = u32_to_arr(crc32);

        #[allow(unsafe_code)]
        unsafe {
            std::ptr::copy_nonoverlapping(
                crc32_arr.as_ptr(),
                self.buf.as_mut_ptr(),
                std::mem::size_of::<u32>(),
            );
        }
        self.log.exit_reservation(&self.iobuf)?;

        Ok((self.lsn, self.pointer))
    }
}
<|endoftext|>


<commit_before>
// Sys mods
use std::io::BufRead;
use std::cell::RefCell;

// Internal mods
use parser::Component;
use property::{Property, PropertyParser};
use parser::errors::*;

#[derive(Debug, Clone, Default)]
/// An ICAL calendar.
pub struct IcalCalendar {
    pub properties: Vec<Property>,
    pub events: Vec<IcalEvent>,
    pub alarms: Vec<IcalAlarm>,
    pub todos: Vec<IcalTodo>,
    pub journals: Vec<IcalJournal>,
    pub free_busys: Vec<IcalFreeBusy>,
    pub timezones: Vec<IcalTimeZone>,
}

impl IcalCalendar {
    pub fn new() -> IcalCalendar {
        IcalCalendar {
            properties: Vec::new(),
            events: Vec::new(),
            alarms: Vec::new(),
            todos: Vec::new(),
            journals: Vec::new(),
            free_busys: Vec::new(),
            timezones: Vec::new(),
        }
    }
}

impl Component for IcalCalendar {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     value: &str,
                                     line_parser: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {

        match value {
            "VALARM" => {
                let mut alarm = IcalAlarm::new();
                alarm.parse(line_parser)?;
                self.alarms.push(alarm);
            }
            "VEVENT" => {
                let mut event = IcalEvent::new();
                event.parse(line_parser)?;
                self.events.push(event);
            }
            "VTODO" => {
                let mut todo = IcalTodo::new();
                todo.parse(line_parser)?;
                self.todos.push(todo);
            }
            "VJOURNAL" => {
                let mut journal = IcalJournal::new();
                journal.parse(line_parser)?;
                self.journals.push(journal);
            }
            "VFREEBUSY" => {
                let mut free_busy = IcalFreeBusy::new();
                free_busy.parse(line_parser)?;
                self.free_busys.push(free_busy);
            }
            "VTIMEZONE" => {
                let mut timezone = IcalTimeZone::new();
                timezone.parse(line_parser)?;
                self.timezones.push(timezone);
            }
            _ => return Err(ErrorKind::InvalidComponent.into()),

        };

        Ok(())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalAlarm {
    pub properties: Vec<Property>,
}

impl IcalAlarm {
    pub fn new() -> IcalAlarm {
        IcalAlarm { properties: Vec::new() }
    }
}

impl Component for IcalAlarm {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     _: &str,
                                     _: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        Err(ErrorKind::InvalidComponent.into())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalEvent {
    pub properties: Vec<Property>,
    pub alarms: Vec<IcalAlarm>,
}

impl IcalEvent {
    pub fn new() -> IcalEvent {
        IcalEvent {
            properties: Vec::new(),
            alarms: Vec::new(),
        }
    }
}

impl Component for IcalEvent {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     value: &str,
                                     line_parser: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {

        match value {
            "VALARM" => {
                let mut alarm = IcalAlarm::new();
                alarm.parse(line_parser)?;
                self.alarms.push(alarm);
            }
            _ => return Err(ErrorKind::InvalidComponent.into()),
        };

        Ok(())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalJournal {
    pub properties: Vec<Property>,
}

impl IcalJournal {
    pub fn new() -> IcalJournal {
        IcalJournal { properties: Vec::new() }
    }
}

impl Component for IcalJournal {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     _: &str,
                                     _: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        Err(ErrorKind::InvalidComponent.into())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalTodo {
    pub properties: Vec<Property>,
    pub alarms: Vec<IcalAlarm>,
}

impl IcalTodo {
    pub fn new() -> IcalTodo {
        IcalTodo {
            properties: Vec::new(),
            alarms: Vec::new(),
        }
    }
}

impl Component for IcalTodo {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     value: &str,
                                     line_parser: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {

        match value {
            "VALARM" => {
                let mut alarm = IcalAlarm::new();
                alarm.parse(line_parser)?;
                self.alarms.push(alarm);
            }
            _ => return Err(ErrorKind::InvalidComponent.into()),

        };

        Ok(())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalTimeZone {
    pub properties: Vec<Property>,
}

impl IcalTimeZone {
    pub fn new() -> IcalTimeZone {
        IcalTimeZone { properties: Vec::new() }
    }
}

impl Component for IcalTimeZone {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     value: &str,
                                     _line_parser: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        match value {
            "STANDARD" => {

            }
            "DAYLIGHT" => {

            }
            _ => return Err(ErrorKind::InvalidComponent.into())
        };

        Ok(())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalFreeBusy {
    pub properties: Vec<Property>,
}

impl IcalFreeBusy {
    pub fn new() -> IcalFreeBusy {
        IcalFreeBusy { properties: Vec::new() }
    }
}

impl Component for IcalFreeBusy {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     _: &str,
                                     _: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        Err(ErrorKind::InvalidComponent.into())
    }
}
<commit_msg>implemented time zone transitions<commit_after>
// Sys mods
use std::io::BufRead;
use std::cell::RefCell;

// Internal mods
use parser::Component;
use property::{Property, PropertyParser};
use parser::errors::*;

#[derive(Debug, Clone, Default)]
/// An ICAL calendar.
pub struct IcalCalendar {
    pub properties: Vec<Property>,
    pub events: Vec<IcalEvent>,
    pub alarms: Vec<IcalAlarm>,
    pub todos: Vec<IcalTodo>,
    pub journals: Vec<IcalJournal>,
    pub free_busys: Vec<IcalFreeBusy>,
    pub timezones: Vec<IcalTimeZone>,
}

impl IcalCalendar {
    pub fn new() -> IcalCalendar {
        IcalCalendar {
            properties: Vec::new(),
            events: Vec::new(),
            alarms: Vec::new(),
            todos: Vec::new(),
            journals: Vec::new(),
            free_busys: Vec::new(),
            timezones: Vec::new(),
        }
    }
}

impl Component for IcalCalendar {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     value: &str,
                                     line_parser: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {

        match value {
            "VALARM" => {
                let mut alarm = IcalAlarm::new();
                alarm.parse(line_parser)?;
                self.alarms.push(alarm);
            }
            "VEVENT" => {
                let mut event = IcalEvent::new();
                event.parse(line_parser)?;
                self.events.push(event);
            }
            "VTODO" => {
                let mut todo = IcalTodo::new();
                todo.parse(line_parser)?;
                self.todos.push(todo);
            }
            "VJOURNAL" => {
                let mut journal = IcalJournal::new();
                journal.parse(line_parser)?;
                self.journals.push(journal);
            }
            "VFREEBUSY" => {
                let mut free_busy = IcalFreeBusy::new();
                free_busy.parse(line_parser)?;
                self.free_busys.push(free_busy);
            }
            "VTIMEZONE" => {
                let mut timezone = IcalTimeZone::new();
                timezone.parse(line_parser)?;
                self.timezones.push(timezone);
            }
            _ => return Err(ErrorKind::InvalidComponent.into()),

        };

        Ok(())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalAlarm {
    pub properties: Vec<Property>,
}

impl IcalAlarm {
    pub fn new() -> IcalAlarm {
        IcalAlarm { properties: Vec::new() }
    }
}

impl Component for IcalAlarm {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     _: &str,
                                     _: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        Err(ErrorKind::InvalidComponent.into())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalEvent {
    pub properties: Vec<Property>,
    pub alarms: Vec<IcalAlarm>,
}

impl IcalEvent {
    pub fn new() -> IcalEvent {
        IcalEvent {
            properties: Vec::new(),
            alarms: Vec::new(),
        }
    }
}

impl Component for IcalEvent {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     value: &str,
                                     line_parser: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {

        match value {
            "VALARM" => {
                let mut alarm = IcalAlarm::new();
                alarm.parse(line_parser)?;
                self.alarms.push(alarm);
            }
            _ => return Err(ErrorKind::InvalidComponent.into()),
        };

        Ok(())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalJournal {
    pub properties: Vec<Property>,
}

impl IcalJournal {
    pub fn new() -> IcalJournal {
        IcalJournal { properties: Vec::new() }
    }
}

impl Component for IcalJournal {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     _: &str,
                                     _: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        Err(ErrorKind::InvalidComponent.into())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalTodo {
    pub properties: Vec<Property>,
    pub alarms: Vec<IcalAlarm>,
}

impl IcalTodo {
    pub fn new() -> IcalTodo {
        IcalTodo {
            properties: Vec::new(),
            alarms: Vec::new(),
        }
    }
}

impl Component for IcalTodo {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     value: &str,
                                     line_parser: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {

        match value {
            "VALARM" => {
                let mut alarm = IcalAlarm::new();
                alarm.parse(line_parser)?;
                self.alarms.push(alarm);
            }
            _ => return Err(ErrorKind::InvalidComponent.into()),

        };

        Ok(())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalTimeZone {
    pub properties: Vec<Property>,
    pub transitions: Vec<IcalTimeZoneTransition>,
}

impl IcalTimeZone {
    pub fn new() -> IcalTimeZone {
        IcalTimeZone { properties: Vec::new(), transitions: Vec::new() }
    }
}

impl Component for IcalTimeZone {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     value: &str,
                                     line_parser: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        match value {
            "STANDARD" | "DAYLIGHT" => {
                let mut transition = IcalTimeZoneTransition::new();
                transition.parse(line_parser)?;
                self.transitions.push(transition);
            }
            _ => return Err(ErrorKind::InvalidComponent.into())
        };

        Ok(())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalTimeZoneTransition {
    pub properties: Vec<Property>,
}

impl IcalTimeZoneTransition {
    pub fn new() -> IcalTimeZoneTransition {
        IcalTimeZoneTransition { properties: Vec::new() }
    }
}

impl Component for IcalTimeZoneTransition {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     _: &str,
                                     _: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        Err(ErrorKind::InvalidComponent.into())
    }
}

#[derive(Debug, Clone, Default)]
pub struct IcalFreeBusy {
    pub properties: Vec<Property>,
}

impl IcalFreeBusy {
    pub fn new() -> IcalFreeBusy {
        IcalFreeBusy { properties: Vec::new() }
    }
}

impl Component for IcalFreeBusy {
    fn add_property(&mut self, property: Property) {
        self.properties.push(property);
    }

    fn add_sub_component<B: BufRead>(&mut self,
                                     _: &str,
                                     _: &RefCell<PropertyParser<B>>)
                                     -> Result<()> {
        Err(ErrorKind::InvalidComponent.into())
    }
}
<|endoftext|>


<commit_before>//! Types for rectangles.

mod rect {
    use crate::float_eq_cairo::ApproxEqCairo;
    use core::ops::{Add, Range, Sub};
    use num_traits::Zero;

    // Use our own min() and max() that are acceptable for floating point

    fn min<T: PartialOrd>(x: T, y: T) -> T {
        if x <= y {
            x
        } else {
            y
        }
    }

    fn max<T: PartialOrd>(x: T, y: T) -> T {
        if x >= y {
            x
        } else {
            y
        }
    }

    #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
    pub struct Rect<T> {
        pub x0: T,
        pub y0: T,
        pub x1: T,
        pub y1: T,
    }

    impl<T> Rect<T> {
        #[inline]
        pub fn new(x0: T, y0: T, x1: T, y1: T) -> Self {
            Self { x0, y0, x1, y1 }
        }
    }

    impl<T> Rect<T>
    where
        T: Copy + PartialOrd + PartialEq + Add<T, Output = T> + Sub<T, Output = T> + Zero,
    {
        #[inline]
        pub fn from_size(w: T, h: T) -> Self {
            Self {
                x0: Zero::zero(),
                y0: Zero::zero(),
                x1: w,
                y1: h,
            }
        }

        #[inline]
        pub fn width(&self) -> T {
            self.x1 - self.x0
        }

        #[inline]
        pub fn height(&self) -> T {
            self.y1 - self.y0
        }

        #[inline]
        pub fn size(&self) -> (T, T) {
            (self.width(), self.height())
        }

        #[inline]
        pub fn x_range(&self) -> Range<T> {
            self.x0..self.x1
        }

        #[inline]
        pub fn y_range(&self) -> Range<T> {
            self.y0..self.y1
        }

        #[inline]
        pub fn contains(self, x: T, y: T) -> bool {
            x >= self.x0 && x < self.x1 && y >= self.y0 && y < self.y1
        }

        #[inline]
        pub fn translate(&self, by: (T, T)) -> Self {
            Self {
                x0: self.x0 + by.0,
                y0: self.y0 + by.1,
                x1: self.x1 + by.0,
                y1: self.y1 + by.1,
            }
        }

        #[inline]
        pub fn intersection(&self, rect: &Self) -> Option<Self> {
            let (x0, y0, x1, y1) = (
                max(self.x0, rect.x0),
                max(self.y0, rect.y0),
                min(self.x1, rect.x1),
                min(self.y1, rect.y1),
            );

            if x1 > x0 && y1 > y0 {
                Some(Self { x0, y0, x1, y1 })
            } else {
                None
            }
        }

        #[inline]
        pub fn union(&self, rect: &Self) -> Self {
            Self {
                x0: min(self.x0, rect.x0),
                y0: min(self.y0, rect.y0),
                x1: max(self.x1, rect.x1),
                y1: max(self.y1, rect.y1),
            }
        }
    }

    impl Rect<i32> {
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.width() == Zero::zero() || self.height() == Zero::zero()
        }

        #[inline]
        pub fn scale(self, x: f64, y: f64) -> Self {
            Self {
                x0: (f64::from(self.x0) * x).floor() as i32,
                y0: (f64::from(self.y0) * y).floor() as i32,
                x1: (f64::from(self.x1) * x).ceil() as i32,
                y1: (f64::from(self.y1) * y).ceil() as i32,
            }
        }
    }

    impl Rect<f64> {
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.width().approx_eq_cairo(0.0) || self.height().approx_eq_cairo(0.0)
        }

        #[inline]
        pub fn scale(self, x: f64, y: f64) -> Self {
            Self {
                x0: self.x0 * x,
                y0: self.y0 * y,
                x1: self.x1 * x,
                y1: self.y1 * y,
            }
        }
    }
}

pub type Rect = rect::Rect<f64>;

impl From<Rect> for IRect {
    #[inline]
    fn from(r: Rect) -> Self {
        Self {
            x0: r.x0.floor() as i32,
            y0: r.y0.floor() as i32,
            x1: r.x1.ceil() as i32,
            y1: r.y1.ceil() as i32,
        }
    }
}

impl From<cairo::Rectangle> for Rect {
    #[inline]
    fn from(r: cairo::Rectangle) -> Self {
        Self {
            x0: r.x,
            y0: r.y,
            x1: r.x + r.width,
            y1: r.y + r.height,
        }
    }
}

impl From<Rect> for cairo::Rectangle {
    #[inline]
    fn from(r: Rect) -> Self {
        Self {
            x: r.x0,
            y: r.y0,
            width: r.x1 - r.x0,
            height: r.y1 - r.y0,
        }
    }
}

pub type IRect = rect::Rect<i32>;

impl From<IRect> for Rect {
    #[inline]
    fn from(r: IRect) -> Self {
        Self {
            x0: f64::from(r.x0),
            y0: f64::from(r.y0),
            x1: f64::from(r.x1),
            y1: f64::from(r.y1),
        }
    }
}

impl From<cairo::Rectangle> for IRect {
    #[inline]
    fn from(r: cairo::Rectangle) -> Self {
        Self {
            x0: r.x.floor() as i32,
            y0: r.y.floor() as i32,
            x1: (r.x + r.width).ceil() as i32,
            y1: (r.y + r.height).ceil() as i32,
        }
    }
}

impl From<IRect> for cairo::Rectangle {
    #[inline]
    fn from(r: IRect) -> Self {
        Self {
            x: f64::from(r.x0),
            y: f64::from(r.y0),
            width: f64::from(r.x1 - r.x0),
            height: f64::from(r.y1 - r.y0),
        }
    }
}
<commit_msg>Suppress warning about module inception, this is intentional here<commit_after>//! Types for rectangles.

#[allow(clippy::module_inception)]
mod rect {
    use crate::float_eq_cairo::ApproxEqCairo;
    use core::ops::{Add, Range, Sub};
    use num_traits::Zero;

    // Use our own min() and max() that are acceptable for floating point

    fn min<T: PartialOrd>(x: T, y: T) -> T {
        if x <= y {
            x
        } else {
            y
        }
    }

    fn max<T: PartialOrd>(x: T, y: T) -> T {
        if x >= y {
            x
        } else {
            y
        }
    }

    #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
    pub struct Rect<T> {
        pub x0: T,
        pub y0: T,
        pub x1: T,
        pub y1: T,
    }

    impl<T> Rect<T> {
        #[inline]
        pub fn new(x0: T, y0: T, x1: T, y1: T) -> Self {
            Self { x0, y0, x1, y1 }
        }
    }

    impl<T> Rect<T>
    where
        T: Copy + PartialOrd + PartialEq + Add<T, Output = T> + Sub<T, Output = T> + Zero,
    {
        #[inline]
        pub fn from_size(w: T, h: T) -> Self {
            Self {
                x0: Zero::zero(),
                y0: Zero::zero(),
                x1: w,
                y1: h,
            }
        }

        #[inline]
        pub fn width(&self) -> T {
            self.x1 - self.x0
        }

        #[inline]
        pub fn height(&self) -> T {
            self.y1 - self.y0
        }

        #[inline]
        pub fn size(&self) -> (T, T) {
            (self.width(), self.height())
        }

        #[inline]
        pub fn x_range(&self) -> Range<T> {
            self.x0..self.x1
        }

        #[inline]
        pub fn y_range(&self) -> Range<T> {
            self.y0..self.y1
        }

        #[inline]
        pub fn contains(self, x: T, y: T) -> bool {
            x >= self.x0 && x < self.x1 && y >= self.y0 && y < self.y1
        }

        #[inline]
        pub fn translate(&self, by: (T, T)) -> Self {
            Self {
                x0: self.x0 + by.0,
                y0: self.y0 + by.1,
                x1: self.x1 + by.0,
                y1: self.y1 + by.1,
            }
        }

        #[inline]
        pub fn intersection(&self, rect: &Self) -> Option<Self> {
            let (x0, y0, x1, y1) = (
                max(self.x0, rect.x0),
                max(self.y0, rect.y0),
                min(self.x1, rect.x1),
                min(self.y1, rect.y1),
            );

            if x1 > x0 && y1 > y0 {
                Some(Self { x0, y0, x1, y1 })
            } else {
                None
            }
        }

        #[inline]
        pub fn union(&self, rect: &Self) -> Self {
            Self {
                x0: min(self.x0, rect.x0),
                y0: min(self.y0, rect.y0),
                x1: max(self.x1, rect.x1),
                y1: max(self.y1, rect.y1),
            }
        }
    }

    impl Rect<i32> {
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.width() == Zero::zero() || self.height() == Zero::zero()
        }

        #[inline]
        pub fn scale(self, x: f64, y: f64) -> Self {
            Self {
                x0: (f64::from(self.x0) * x).floor() as i32,
                y0: (f64::from(self.y0) * y).floor() as i32,
                x1: (f64::from(self.x1) * x).ceil() as i32,
                y1: (f64::from(self.y1) * y).ceil() as i32,
            }
        }
    }

    impl Rect<f64> {
        #[inline]
        pub fn is_empty(&self) -> bool {
            self.width().approx_eq_cairo(0.0) || self.height().approx_eq_cairo(0.0)
        }

        #[inline]
        pub fn scale(self, x: f64, y: f64) -> Self {
            Self {
                x0: self.x0 * x,
                y0: self.y0 * y,
                x1: self.x1 * x,
                y1: self.y1 * y,
            }
        }
    }
}

pub type Rect = rect::Rect<f64>;

impl From<Rect> for IRect {
    #[inline]
    fn from(r: Rect) -> Self {
        Self {
            x0: r.x0.floor() as i32,
            y0: r.y0.floor() as i32,
            x1: r.x1.ceil() as i32,
            y1: r.y1.ceil() as i32,
        }
    }
}

impl From<cairo::Rectangle> for Rect {
    #[inline]
    fn from(r: cairo::Rectangle) -> Self {
        Self {
            x0: r.x,
            y0: r.y,
            x1: r.x + r.width,
            y1: r.y + r.height,
        }
    }
}

impl From<Rect> for cairo::Rectangle {
    #[inline]
    fn from(r: Rect) -> Self {
        Self {
            x: r.x0,
            y: r.y0,
            width: r.x1 - r.x0,
            height: r.y1 - r.y0,
        }
    }
}

pub type IRect = rect::Rect<i32>;

impl From<IRect> for Rect {
    #[inline]
    fn from(r: IRect) -> Self {
        Self {
            x0: f64::from(r.x0),
            y0: f64::from(r.y0),
            x1: f64::from(r.x1),
            y1: f64::from(r.y1),
        }
    }
}

impl From<cairo::Rectangle> for IRect {
    #[inline]
    fn from(r: cairo::Rectangle) -> Self {
        Self {
            x0: r.x.floor() as i32,
            y0: r.y.floor() as i32,
            x1: (r.x + r.width).ceil() as i32,
            y1: (r.y + r.height).ceil() as i32,
        }
    }
}

impl From<IRect> for cairo::Rectangle {
    #[inline]
    fn from(r: IRect) -> Self {
        Self {
            x: f64::from(r.x0),
            y: f64::from(r.y0),
            width: f64::from(r.x1 - r.x0),
            height: f64::from(r.y1 - r.y0),
        }
    }
}
<|endoftext|>