<commit_before>/*
 * Copyright 2017 Ben Ashford
 *
 * 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.
 */

use std::collections::VecDeque;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};

use futures::{future, Future, Sink, Stream};
use futures::sync::{mpsc, oneshot};

use tokio_core::reactor::Handle;

use error;
use resp;
use super::connect::{connect, ClientConnection};

type PairedConnectionBox = Box<Future<Item = PairedConnection, Error = error::Error>>;

/// The default starting point to use most default Redis functionality.
///
/// Returns a future that resolves to a `PairedConnection`.
pub fn paired_connect(addr: &SocketAddr, handle: &Handle) -> PairedConnectionBox {
    let handle = handle.clone();
    let paired_con = connect(addr, &handle)
        .map(move |connection| {
            let ClientConnection { sender, receiver } = connection;
            let (out_tx, out_rx) = mpsc::unbounded();
            let sender = out_rx.fold(sender, |sender, msg| sender.send(msg).map_err(|_| ()));
            let resp_queue: Arc<Mutex<VecDeque<oneshot::Sender<resp::RespValue>>>> =
                Arc::new(Mutex::new(VecDeque::new()));
            let receiver_queue = resp_queue.clone();
            let receiver = receiver.for_each(move |msg| {
                let mut queue = receiver_queue.lock().expect("Lock is tainted");
                let dest = queue.pop_front().expect("Queue is empty");
                match dest.send(msg) {
                    Ok(()) => Ok(()),
                    // Ignore error as the channel may have been legitimately closed in the meantime
                    Err(_) => Ok(())
                }
            });
            handle.spawn(sender.map(|_| ()));
            handle.spawn(receiver.map_err(|_| ()));
            PairedConnection {
                out_tx: out_tx,
                resp_queue: resp_queue,
            }
        })
        .map_err(|e| e.into());
    Box::new(paired_con)
}

pub struct PairedConnection {
    out_tx: mpsc::UnboundedSender<resp::RespValue>,
    resp_queue: Arc<Mutex<VecDeque<oneshot::Sender<resp::RespValue>>>>,
}

type SendBox<T> = Box<Future<Item = T, Error = error::Error>>;

impl PairedConnection {
    /// Sends a command to Redis.
    ///
    /// The message must be in the format of a single RESP message (or a format for which a
    /// conversion trait is defined).  Returned is a future that resolves to the value returned
    /// from Redis.  The type must be one for which the `resp::FromResp` trait is defined.
    ///
    /// The future will fail for numerous reasons, including but not limited to: IO issues, conversion
    /// problems, and server-side errors being returned by Redis.
    ///
    /// Behind the scenes the message is queued up and sent to Redis asynchronously before the
    /// future is realised.  As such, it is guaranteed that messages are sent in the same order
    /// that `send` is called.
    pub fn send<R, T: resp::FromResp + 'static>(&self, msg: R) -> SendBox<T>
        where R: Into<resp::RespValue>
    {
        let (tx, rx) = oneshot::channel();
        let mut queue = self.resp_queue.lock().expect("Tainted queue");
        queue.push_back(tx);
        self.out_tx
            .unbounded_send(msg.into())
            .expect("Failed to send");
        let future = rx.then(|v| match v {
                                 Ok(v) => future::result(T::from_resp(v)),
                                 Err(e) => future::err(e.into()),
                             });
        Box::new(future)
    }

    /// Send to Redis, similar to `send` but not future is returned.  The data will be sent, errors will
    /// be swallowed.
    pub fn send_and_forget<R>(&self, msg: R)
        where R: Into<resp::RespValue>
    {
        let _: SendBox<String> = self.send(msg);
    }
}

mod commands {
    use resp::{ToRespString, RespValue};

    use super::SendBox;

    impl super::PairedConnection {
        pub fn append<K, V>(&self, (key, value): (K, V)) -> SendBox<usize>
            where K: ToRespString,
                  V: ToRespString
        {
            self.send(RespValue::Array(vec!["APPEND".to_resp_string(),
                                            key.to_resp_string(),
                                            value.to_resp_string()]))
        }
    }

    // MARKER - all accounted for above this line

    pub trait DelCommand {
        fn to_resp(&self) -> RespValue;
    }

    impl<'a> DelCommand for (&'a str) {
        fn to_resp(&self) -> RespValue {
            RespValue::Array(vec!["DEL".to_resp_string(), self.to_resp_string()])
        }
    }

    impl<'a, S: AsRef<str>> DelCommand for (&'a [S]) {
        fn to_resp(&self) -> RespValue {
            let mut keys = Vec::with_capacity(self.len() + 1);
            keys.push("DEL".to_resp_string());
            keys.extend(self.iter().map(|key| key.as_ref().to_resp_string()));
            RespValue::Array(keys)
        }
    }

    impl super::PairedConnection {
        pub fn del<C>(&self, cmd: C) -> SendBox<usize>
            where C: DelCommand
        {
            self.send(cmd.to_resp())
        }
    }

    #[cfg(test)]
    mod test {
        use futures::future;
        use futures::Future;

        use tokio_core::reactor::Core;

        fn setup() -> (Core, super::super::PairedConnectionBox) {
            let core = Core::new().unwrap();
            let handle = core.handle();
            let addr = "127.0.0.1:6379".parse().unwrap();

            (core, super::super::paired_connect(&addr, &handle))
        }

        fn setup_and_delete(keys: &[&str]) -> (Core, super::super::PairedConnectionBox) {
            let (mut core, connection) = setup();

            let delete = connection.and_then(|connection| connection.del(keys).map(|_| connection));

            let connection = core.run(delete).unwrap();
            (core, Box::new(future::ok(connection)))
        }

        #[test]
        fn append_test() {
            let (mut core, connection) = setup_and_delete(&["APPENDKEY"]);

            let connection = connection
                .and_then(|connection| connection.append(("APPENDKEY", "ABC")));

            let count = core.run(connection).unwrap();
            assert_eq!(count, 3);
        }

        #[test]
        fn del_test() {
            let (mut core, connection) = setup();

            let del_keys = "DEL_KEY";
            let connection = connection.and_then(|connection| connection.del((del_keys)));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_string() {
            let (mut core, connection) = setup();

            let del_keys = String::from("DEL_KEY");
            let connection = connection.and_then(|connection| connection.del((del_keys.as_str())));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_vec() {
            let (mut core, connection) = setup();

            let del_keys = vec!["DEL_KEY_1", "DEL_KEY_2"];
            let connection = connection
                .and_then(|connection| connection.del((del_keys.as_slice())));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_vec_string() {
            let (mut core, connection) = setup();

            let del_keys = vec![String::from("DEL_KEY_1"), String::from("DEL_KEY_2")];
            let connection = connection
                .and_then(|connection| connection.del((del_keys.as_slice())));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_ary() {
            let (mut core, connection) = setup();

            let del_keys = ["DEL_KEY_1", "DEL_KEY_2"];
            let connection = connection.and_then(|connection| connection.del((&del_keys[..])));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_ary_string() {
            let (mut core, connection) = setup();

            let del_keys = [String::from("DEL_KEY_1"), String::from("DEL_KEY_2")];
            let connection = connection.and_then(|connection| connection.del((&del_keys[..])));

            let _ = core.run(connection).unwrap();
        }
    }
}<commit_msg>Better conversions<commit_after>/*
 * Copyright 2017 Ben Ashford
 *
 * 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.
 */

use std::collections::VecDeque;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};

use futures::{future, Future, Sink, Stream};
use futures::sync::{mpsc, oneshot};

use tokio_core::reactor::Handle;

use error;
use resp;
use super::connect::{connect, ClientConnection};

type PairedConnectionBox = Box<Future<Item = PairedConnection, Error = error::Error>>;

/// The default starting point to use most default Redis functionality.
///
/// Returns a future that resolves to a `PairedConnection`.
pub fn paired_connect(addr: &SocketAddr, handle: &Handle) -> PairedConnectionBox {
    let handle = handle.clone();
    let paired_con = connect(addr, &handle)
        .map(move |connection| {
            let ClientConnection { sender, receiver } = connection;
            let (out_tx, out_rx) = mpsc::unbounded();
            let sender = out_rx.fold(sender, |sender, msg| sender.send(msg).map_err(|_| ()));
            let resp_queue: Arc<Mutex<VecDeque<oneshot::Sender<resp::RespValue>>>> =
                Arc::new(Mutex::new(VecDeque::new()));
            let receiver_queue = resp_queue.clone();
            let receiver = receiver.for_each(move |msg| {
                let mut queue = receiver_queue.lock().expect("Lock is tainted");
                let dest = queue.pop_front().expect("Queue is empty");
                match dest.send(msg) {
                    Ok(()) => Ok(()),
                    // Ignore error as the channel may have been legitimately closed in the meantime
                    Err(_) => Ok(())
                }
            });
            handle.spawn(sender.map(|_| ()));
            handle.spawn(receiver.map_err(|_| ()));
            PairedConnection {
                out_tx: out_tx,
                resp_queue: resp_queue,
            }
        })
        .map_err(|e| e.into());
    Box::new(paired_con)
}

pub struct PairedConnection {
    out_tx: mpsc::UnboundedSender<resp::RespValue>,
    resp_queue: Arc<Mutex<VecDeque<oneshot::Sender<resp::RespValue>>>>,
}

type SendBox<T> = Box<Future<Item = T, Error = error::Error>>;

impl PairedConnection {
    /// Sends a command to Redis.
    ///
    /// The message must be in the format of a single RESP message (or a format for which a
    /// conversion trait is defined).  Returned is a future that resolves to the value returned
    /// from Redis.  The type must be one for which the `resp::FromResp` trait is defined.
    ///
    /// The future will fail for numerous reasons, including but not limited to: IO issues, conversion
    /// problems, and server-side errors being returned by Redis.
    ///
    /// Behind the scenes the message is queued up and sent to Redis asynchronously before the
    /// future is realised.  As such, it is guaranteed that messages are sent in the same order
    /// that `send` is called.
    pub fn send<R, T: resp::FromResp + 'static>(&self, msg: R) -> SendBox<T>
        where R: Into<resp::RespValue>
    {
        let (tx, rx) = oneshot::channel();
        let mut queue = self.resp_queue.lock().expect("Tainted queue");
        queue.push_back(tx);
        self.out_tx
            .unbounded_send(msg.into())
            .expect("Failed to send");
        let future = rx.then(|v| match v {
                                 Ok(v) => future::result(T::from_resp(v)),
                                 Err(e) => future::err(e.into()),
                             });
        Box::new(future)
    }

    /// Send to Redis, similar to `send` but not future is returned.  The data will be sent, errors will
    /// be swallowed.
    pub fn send_and_forget<R>(&self, msg: R)
        where R: Into<resp::RespValue>
    {
        let _: SendBox<String> = self.send(msg);
    }
}

mod commands {
    use resp::{ToRespString, RespValue};

    use super::SendBox;

    impl super::PairedConnection {
        pub fn append<K, V>(&self, (key, value): (K, V)) -> SendBox<usize>
            where K: ToRespString,
                  V: ToRespString
        {
            self.send(RespValue::Array(vec!["APPEND".to_resp_string(),
                                            key.to_resp_string(),
                                            value.to_resp_string()]))
        }
    }

    // MARKER - all accounted for above this line

    pub trait DelCommand {
        fn to_resp(&self) -> RespValue;
    }

    impl<'a, T: ToRespString> DelCommand for (T) {
        fn to_resp(&self) -> RespValue {
            RespValue::Array(vec!["DEL".to_resp_string(), self.to_resp_string()])
        }
    }

    impl<'a, T: ToRespString> DelCommand for (&'a [T]) {
        fn to_resp(&self) -> RespValue {
            let mut keys = Vec::with_capacity(self.len() + 1);
            keys.push("DEL".to_resp_string());
            keys.extend(self.iter().map(|key| key.to_resp_string()));
            RespValue::Array(keys)
        }
    }

    impl super::PairedConnection {
        pub fn del<C>(&self, cmd: C) -> SendBox<usize>
            where C: DelCommand
        {
            self.send(cmd.to_resp())
        }
    }

    #[cfg(test)]
    mod test {
        use futures::future;
        use futures::Future;

        use tokio_core::reactor::Core;

        fn setup() -> (Core, super::super::PairedConnectionBox) {
            let core = Core::new().unwrap();
            let handle = core.handle();
            let addr = "127.0.0.1:6379".parse().unwrap();

            (core, super::super::paired_connect(&addr, &handle))
        }

        fn setup_and_delete(keys: &[&str]) -> (Core, super::super::PairedConnectionBox) {
            let (mut core, connection) = setup();

            let delete = connection.and_then(|connection| connection.del(keys).map(|_| connection));

            let connection = core.run(delete).unwrap();
            (core, Box::new(future::ok(connection)))
        }

        #[test]
        fn append_test() {
            let (mut core, connection) = setup_and_delete(&["APPENDKEY"]);

            let connection = connection
                .and_then(|connection| connection.append(("APPENDKEY", "ABC")));

            let count = core.run(connection).unwrap();
            assert_eq!(count, 3);
        }

        #[test]
        fn del_test() {
            let (mut core, connection) = setup();

            let del_keys = "DEL_KEY";
            let connection = connection.and_then(|connection| connection.del((del_keys)));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_string() {
            let (mut core, connection) = setup();

            let del_keys = String::from("DEL_KEY");
            let connection = connection.and_then(|connection| connection.del((del_keys)));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_vec() {
            let (mut core, connection) = setup();

            let del_keys = vec!["DEL_KEY_1", "DEL_KEY_2"];
            let connection = connection
                .and_then(|connection| connection.del((del_keys.as_slice())));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_vec_string() {
            let (mut core, connection) = setup();

            let del_keys = vec![String::from("DEL_KEY_1"), String::from("DEL_KEY_2")];
            let connection = connection
                .and_then(|connection| connection.del((del_keys.as_slice())));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_ary() {
            let (mut core, connection) = setup();

            let del_keys = ["DEL_KEY_1", "DEL_KEY_2"];
            let connection = connection.and_then(|connection| connection.del((&del_keys[..])));

            let _ = core.run(connection).unwrap();
        }

        #[test]
        fn del_test_ary_string() {
            let (mut core, connection) = setup();

            let del_keys = [String::from("DEL_KEY_1"), String::from("DEL_KEY_2")];
            let connection = connection.and_then(|connection| connection.del((&del_keys[..])));

            let _ = core.run(connection).unwrap();
        }
    }
}<|endoftext|>


<commit_before>//! The module contains an implementation of a simple HTTP/2 client.

use std::net::TcpStream;

use super::super::http::connection::ClientConnection;
use super::super::http::connection::HttpConnection;
use super::super::http::session::{DefaultSession, Stream};
use super::super::http::{StreamId, HttpResult, HttpError, HttpScheme, Response, Header, Request};

/// A struct implementing a simple HTTP/2 client.
///
/// This client works as an HTTP/1.1 client with a Keep-Alive connection and
/// pipelining might work.
///
/// Multiple requests can be queued up (and sent to the server) by calling
/// `request` multiple times, before any `get_response`.
///
/// Once a `get_response` is issued, the client blocks until it receives the
/// response for the particular request that was referenced in the `get_response`
/// call.
///
/// Therefore, by doing `request` -> `get_response` we can use the HTTP/2
/// connection as a `Keep-Alive` HTTP/1.1 connection and a pipelined flow by
/// queuing up a sequence of requests and then "joining" over them by calling
/// `get_response` for each of them.
///
/// The responses that are returned by the client are very raw representations
/// of the response.
///
/// # Notes
///
/// - For now (temporarily) no requests with bodies are supported.
/// - For now, only HTTP/2 over a cleartext TCP connection is supported.
/// - A direct HTTP/2 connection is used (not an upgrade of an HTTP/1.1
///   connection)
///
/// # Examples
///
/// Issue a simple GET request using the helper `get` method.
///
/// ```no_run
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let mut client = SimpleClient::connect("nghttp2.org", 80).ok().unwrap();
/// let response = client.get(b"/", &[]).ok().unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().ok().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
#[unstable = "This is unstable"]
pub struct SimpleClient {
    /// The underlying `ClientConnection` that the client uses
    conn: ClientConnection<TcpStream, DefaultSession>,
    /// Holds the ID that can be assigned to the next stream to be opened by the
    /// client.
    next_stream_id: u32,
}

impl SimpleClient {
    /// Establishes an HTTP/2 connection to a server, given its host name and
    /// port number. If it is not possible to establish the connection, an error
    /// is returned.
    pub fn connect(host: &str, port: u16) -> HttpResult<SimpleClient> {
        let conn = HttpConnection::new(try!(TcpStream::connect(&(host, port))),
                                       HttpScheme::Http,
                                       host.into());
        let mut client = SimpleClient {
            conn: ClientConnection::with_connection(conn, DefaultSession::new()),
            next_stream_id: 1,
        };

        try!(client.init());

        Ok(client)
    }

    /// Internal helper method that performs the initialization of the client's
    /// connection.
    #[inline]
    fn init(&mut self) -> HttpResult<()> {
        self.conn.init()
    }

    /// Send a request to the server. Blocks until the entire request has been
    /// sent.
    ///
    /// The request is described by the method, the path on which it should be
    /// invoked and the "real" headers that should be included. Clients should
    /// never put pseudo-headers in the `headers` parameter, as those are
    /// automatically included based on metadata.
    ///
    /// # Returns
    ///
    /// If the full request is successfully sent, returns the ID of the stream
    /// on which the request was sent. Clients can use this ID to refer to the
    /// response.
    ///
    /// Any IO errors are propagated.
    pub fn request(&mut self, method: &[u8], path: &[u8], extras: &[Header])
            -> HttpResult<StreamId> {
        let stream_id = self.new_stream();
        let mut headers: Vec<Header> = vec![
            (b":method".to_vec(), method.to_vec()),
            (b":path".to_vec(), path.to_vec()),
            (b":authority".to_vec(), self.conn.host().as_bytes().to_vec()),
            (b":scheme".to_vec(), self.conn.scheme().as_bytes().to_vec()),
        ];
        headers.extend(extras.to_vec().into_iter());

        try!(self.conn.send_request(Request {
            stream_id: stream_id,
            headers: headers,
            body: Vec::new(),
        }));

        Ok(stream_id)
    }

    /// Gets the response for the stream with the given ID. If a valid stream ID
    /// is given, it blocks until a response is received.
    ///
    /// # Returns
    ///
    /// A `Response` if the response can be successfully read.
    ///
    /// Any underlying IO errors are propagated. Errors in the HTTP/2 protocol
    /// also stop processing and are returned to the client.
    pub fn get_response(&mut self, stream_id: StreamId) -> HttpResult<Response> {
        match self.conn.session.get_stream(stream_id) {
            None => return Err(HttpError::UnknownStreamId),
            Some(_) => {},
        };
        loop {
            if let Some(stream) = self.conn.session.get_stream(stream_id) {
                if stream.is_closed() {
                    return Ok(Response {
                        stream_id: stream.id(),
                        headers: stream.headers.clone().unwrap(),
                        body: stream.body.clone(),
                    });
                }
            }
            try!(self.handle_next_frame());
        }
    }

    /// Performs a GET request on the given path. This is a shortcut method for
    /// calling `request` followed by `get_response` for the returned stream ID.
    pub fn get(&mut self, path: &[u8], extra_headers: &[Header])
            -> HttpResult<Response> {
        let stream_id = try!(self.request(b"GET", path, extra_headers));
        self.get_response(stream_id)
    }

    /// Internal helper method that initializes a new stream and returns its
    /// ID once done.
    fn new_stream(&mut self) -> StreamId {
        let stream_id = self.get_next_stream_id();
        self.conn.session.new_stream(stream_id);

        stream_id
    }

    /// Internal helper method that gets the next valid stream ID number.
    fn get_next_stream_id(&mut self) -> StreamId {
        let ret = self.next_stream_id;
        self.next_stream_id += 2;

        ret
    }

    /// Internal helper method that triggers the client to handle the next
    /// frame off the HTTP/2 connection.
    #[inline]
    fn handle_next_frame(&mut self) -> HttpResult<()> {
        self.conn.handle_next_frame()
    }
}
<commit_msg>SimpleClient: Make it generic over stream type<commit_after>//! The module contains an implementation of a simple HTTP/2 client.

use super::super::http::connection::ClientConnection;
use super::super::http::connection::HttpConnection;
use super::super::http::transport::TransportStream;
use super::super::http::session::{DefaultSession, Stream};
use super::super::http::{StreamId, HttpResult, HttpError, Response, Header, Request};

/// A struct implementing a simple HTTP/2 client.
///
/// This client works as an HTTP/1.1 client with a Keep-Alive connection and
/// pipelining might work.
///
/// Multiple requests can be queued up (and sent to the server) by calling
/// `request` multiple times, before any `get_response`.
///
/// Once a `get_response` is issued, the client blocks until it receives the
/// response for the particular request that was referenced in the `get_response`
/// call.
///
/// Therefore, by doing `request` -> `get_response` we can use the HTTP/2
/// connection as a `Keep-Alive` HTTP/1.1 connection and a pipelined flow by
/// queuing up a sequence of requests and then "joining" over them by calling
/// `get_response` for each of them.
///
/// The responses that are returned by the client are very raw representations
/// of the response.
///
/// # Notes
///
/// - For now (temporarily) no requests with bodies are supported.
/// - For now, only HTTP/2 over a cleartext TCP connection is supported.
/// - A direct HTTP/2 connection is used (not an upgrade of an HTTP/1.1
///   connection)
///
/// # Examples
///
/// Issue a simple GET request using the helper `get` method.
///
/// ```no_run
/// use std::net::TcpStream;
/// use solicit::http::HttpScheme;
/// use solicit::http::connection::HttpConnection;
/// use solicit::client::SimpleClient;
/// use std::str;
///
/// // Connect to an HTTP/2 aware server
/// let conn = HttpConnection::new(TcpStream::connect(&("http2bin.org", 80)).unwrap(),
///                                HttpScheme::Http,
///                                "http2bin.org".into());
/// let mut client = SimpleClient::with_connection(conn).unwrap();
/// let response = client.get(b"/", &[]).unwrap();
/// assert_eq!(response.stream_id, 1);
/// assert_eq!(response.status_code().unwrap(), 200);
/// // Dump the headers and the response body to stdout.
/// // They are returned as raw bytes for the user to do as they please.
/// // (Note: in general directly decoding assuming a utf8 encoding might not
/// // always work -- this is meant as a simple example that shows that the
/// // response is well formed.)
/// for header in response.headers.iter() {
///     println!("{}: {}",
///         str::from_utf8(&header.0).unwrap(),
///         str::from_utf8(&header.1).unwrap());
/// }
/// println!("{}", str::from_utf8(&response.body).unwrap());
/// ```
#[unstable = "This is unstable"]
pub struct SimpleClient<S> where S: TransportStream {
    /// The underlying `ClientConnection` that the client uses
    conn: ClientConnection<S, DefaultSession>,
    /// Holds the ID that can be assigned to the next stream to be opened by the
    /// client.
    next_stream_id: u32,
}

impl<S> SimpleClient<S> where S: TransportStream {
    /// Create a new `SimpleClient` instance that will use the given `HttpConnection`
    /// to communicate to the server.
    ///
    /// It assumes that the connection is in an uninitialized state and will try
    /// to send the client preface and make sure it receives the server preface
    /// before returning.
    pub fn with_connection(conn: HttpConnection<S>) -> HttpResult<SimpleClient<S>> {
        let mut client = SimpleClient {
            conn: ClientConnection::with_connection(conn, DefaultSession::new()),
            next_stream_id: 1,
        };

        try!(client.init());

        Ok(client)
    }

    /// Internal helper method that performs the initialization of the client's
    /// connection.
    #[inline]
    fn init(&mut self) -> HttpResult<()> {
        self.conn.init()
    }

    /// Send a request to the server. Blocks until the entire request has been
    /// sent.
    ///
    /// The request is described by the method, the path on which it should be
    /// invoked and the "real" headers that should be included. Clients should
    /// never put pseudo-headers in the `headers` parameter, as those are
    /// automatically included based on metadata.
    ///
    /// # Returns
    ///
    /// If the full request is successfully sent, returns the ID of the stream
    /// on which the request was sent. Clients can use this ID to refer to the
    /// response.
    ///
    /// Any IO errors are propagated.
    pub fn request(&mut self, method: &[u8], path: &[u8], extras: &[Header])
            -> HttpResult<StreamId> {
        let stream_id = self.new_stream();
        let mut headers: Vec<Header> = vec![
            (b":method".to_vec(), method.to_vec()),
            (b":path".to_vec(), path.to_vec()),
            (b":authority".to_vec(), self.conn.host().as_bytes().to_vec()),
            (b":scheme".to_vec(), self.conn.scheme().as_bytes().to_vec()),
        ];
        headers.extend(extras.to_vec().into_iter());

        try!(self.conn.send_request(Request {
            stream_id: stream_id,
            headers: headers,
            body: Vec::new(),
        }));

        Ok(stream_id)
    }

    /// Gets the response for the stream with the given ID. If a valid stream ID
    /// is given, it blocks until a response is received.
    ///
    /// # Returns
    ///
    /// A `Response` if the response can be successfully read.
    ///
    /// Any underlying IO errors are propagated. Errors in the HTTP/2 protocol
    /// also stop processing and are returned to the client.
    pub fn get_response(&mut self, stream_id: StreamId) -> HttpResult<Response> {
        match self.conn.session.get_stream(stream_id) {
            None => return Err(HttpError::UnknownStreamId),
            Some(_) => {},
        };
        loop {
            if let Some(stream) = self.conn.session.get_stream(stream_id) {
                if stream.is_closed() {
                    return Ok(Response {
                        stream_id: stream.id(),
                        headers: stream.headers.clone().unwrap(),
                        body: stream.body.clone(),
                    });
                }
            }
            try!(self.handle_next_frame());
        }
    }

    /// Performs a GET request on the given path. This is a shortcut method for
    /// calling `request` followed by `get_response` for the returned stream ID.
    pub fn get(&mut self, path: &[u8], extra_headers: &[Header])
            -> HttpResult<Response> {
        let stream_id = try!(self.request(b"GET", path, extra_headers));
        self.get_response(stream_id)
    }

    /// Internal helper method that initializes a new stream and returns its
    /// ID once done.
    fn new_stream(&mut self) -> StreamId {
        let stream_id = self.get_next_stream_id();
        self.conn.session.new_stream(stream_id);

        stream_id
    }

    /// Internal helper method that gets the next valid stream ID number.
    fn get_next_stream_id(&mut self) -> StreamId {
        let ret = self.next_stream_id;
        self.next_stream_id += 2;

        ret
    }

    /// Internal helper method that triggers the client to handle the next
    /// frame off the HTTP/2 connection.
    #[inline]
    fn handle_next_frame(&mut self) -> HttpResult<()> {
        self.conn.handle_next_frame()
    }
}
<|endoftext|>


<commit_before>use proc_macro2::{Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::str::FromStr;
use syn::{Lit, LitFloat, LitInt};

fn lit(s: &str) -> Lit {
    match TokenStream::from_str(s)
        .unwrap()
        .into_iter()
        .next()
        .unwrap()
    {
        TokenTree::Literal(lit) => Lit::new(lit),
        _ => panic!(),
    }
}

#[test]
fn strings() {
    fn test_string(s: &str, value: &str) {
        match lit(s) {
            Lit::Str(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_string(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_string("\"a\"", "a");
    test_string("\"\\n\"", "\n");
    test_string("\"\\r\"", "\r");
    test_string("\"\\t\"", "\t");
    test_string("\"🐕\"", "🐕"); // NOTE: This is an emoji
    test_string("\"\\\"\"", "\"");
    test_string("\"'\"", "'");
    test_string("\"\"", "");
    test_string("\"\\u{1F415}\"", "\u{1F415}");
    test_string(
        "\"contains\nnewlines\\\nescaped newlines\"",
        "contains\nnewlinesescaped newlines",
    );
    test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere");
}

#[test]
fn byte_strings() {
    fn test_byte_string(s: &str, value: &[u8]) {
        match lit(s) {
            Lit::ByteStr(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_byte_string(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_byte_string("b\"a\"", b"a");
    test_byte_string("b\"\\n\"", b"\n");
    test_byte_string("b\"\\r\"", b"\r");
    test_byte_string("b\"\\t\"", b"\t");
    test_byte_string("b\"\\\"\"", b"\"");
    test_byte_string("b\"'\"", b"'");
    test_byte_string("b\"\"", b"");
    test_byte_string(
        "b\"contains\nnewlines\\\nescaped newlines\"",
        b"contains\nnewlinesescaped newlines",
    );
    test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere");
}

#[test]
fn bytes() {
    fn test_byte(s: &str, value: u8) {
        match lit(s) {
            Lit::Byte(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                assert_eq!(again, s);
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_byte("b'a'", b'a');
    test_byte("b'\\n'", b'\n');
    test_byte("b'\\r'", b'\r');
    test_byte("b'\\t'", b'\t');
    test_byte("b'\\''", b'\'');
    test_byte("b'\"'", b'"');
}

#[test]
fn chars() {
    fn test_char(s: &str, value: char) {
        match lit(s) {
            Lit::Char(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_char(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_char("'a'", 'a');
    test_char("'\\n'", '\n');
    test_char("'\\r'", '\r');
    test_char("'\\t'", '\t');
    test_char("'🐕'", '🐕'); // NOTE: This is an emoji
    test_char("'\\''", '\'');
    test_char("'\"'", '"');
    test_char("'\\u{1F415}'", '\u{1F415}');
}

#[test]
fn ints() {
    fn test_int(s: &str, value: u64, suffix: &str) {
        match lit(s) {
            Lit::Int(lit) => {
                assert_eq!(lit.base10_digits().parse::<u64>().unwrap(), value);
                assert_eq!(lit.suffix(), suffix);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_int(&again, value, suffix);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_int("5", 5, "");
    test_int("5u32", 5, "u32");
    test_int("5_0", 50, "");
    test_int("5_____0_____", 50, "");
    test_int("0x7f", 127, "");
    test_int("0x7F", 127, "");
    test_int("0b1001", 9, "");
    test_int("0o73", 59, "");
    test_int("0x7Fu8", 127, "u8");
    test_int("0b1001i8", 9, "i8");
    test_int("0o73u32", 59, "u32");
    test_int("0x__7___f_", 127, "");
    test_int("0x__7___F_", 127, "");
    test_int("0b_1_0__01", 9, "");
    test_int("0o_7__3", 59, "");
    test_int("0x_7F__u8", 127, "u8");
    test_int("0b__10__0_1i8", 9, "i8");
    test_int("0o__7__________________3u32", 59, "u32");
}

#[test]
fn floats() {
    #[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
    fn test_float(s: &str, value: f64, suffix: &str) {
        match lit(s) {
            Lit::Float(lit) => {
                assert_eq!(lit.base10_digits().parse::<f64>().unwrap(), value);
                assert_eq!(lit.suffix(), suffix);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_float(&again, value, suffix);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_float("5.5", 5.5, "");
    test_float("5.5E12", 5.5e12, "");
    test_float("5.5e12", 5.5e12, "");
    test_float("1.0__3e-12", 1.03e-12, "");
    test_float("1.03e+12", 1.03e12, "");
}

#[test]
fn negative() {
    let span = Span::call_site();
    assert_eq!("-1", LitInt::new("-1", span).to_string());
    assert_eq!("-1i8", LitInt::new("-1i8", span).to_string());
    assert_eq!("-1i16", LitInt::new("-1i16", span).to_string());
    assert_eq!("-1i32", LitInt::new("-1i32", span).to_string());
    assert_eq!("-1i64", LitInt::new("-1i64", span).to_string());
    assert_eq!("-1.5", LitFloat::new("-1.5", span).to_string());
    assert_eq!("-1.5f32", LitFloat::new("-1.5f32", span).to_string());
    assert_eq!("-1.5f64", LitFloat::new("-1.5f64", span).to_string());
}
<commit_msg>Add failing test for literal suffixes<commit_after>use proc_macro2::{Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::str::FromStr;
use syn::{Lit, LitFloat, LitInt};

fn lit(s: &str) -> Lit {
    match TokenStream::from_str(s)
        .unwrap()
        .into_iter()
        .next()
        .unwrap()
    {
        TokenTree::Literal(lit) => Lit::new(lit),
        _ => panic!(),
    }
}

#[test]
fn strings() {
    fn test_string(s: &str, value: &str) {
        match lit(s) {
            Lit::Str(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_string(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_string("\"a\"", "a");
    test_string("\"\\n\"", "\n");
    test_string("\"\\r\"", "\r");
    test_string("\"\\t\"", "\t");
    test_string("\"🐕\"", "🐕"); // NOTE: This is an emoji
    test_string("\"\\\"\"", "\"");
    test_string("\"'\"", "'");
    test_string("\"\"", "");
    test_string("\"\\u{1F415}\"", "\u{1F415}");
    test_string(
        "\"contains\nnewlines\\\nescaped newlines\"",
        "contains\nnewlinesescaped newlines",
    );
    test_string("r\"raw\nstring\\\nhere\"", "raw\nstring\\\nhere");
}

#[test]
fn byte_strings() {
    fn test_byte_string(s: &str, value: &[u8]) {
        match lit(s) {
            Lit::ByteStr(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_byte_string(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_byte_string("b\"a\"", b"a");
    test_byte_string("b\"\\n\"", b"\n");
    test_byte_string("b\"\\r\"", b"\r");
    test_byte_string("b\"\\t\"", b"\t");
    test_byte_string("b\"\\\"\"", b"\"");
    test_byte_string("b\"'\"", b"'");
    test_byte_string("b\"\"", b"");
    test_byte_string(
        "b\"contains\nnewlines\\\nescaped newlines\"",
        b"contains\nnewlinesescaped newlines",
    );
    test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere");
}

#[test]
fn bytes() {
    fn test_byte(s: &str, value: u8) {
        match lit(s) {
            Lit::Byte(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                assert_eq!(again, s);
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_byte("b'a'", b'a');
    test_byte("b'\\n'", b'\n');
    test_byte("b'\\r'", b'\r');
    test_byte("b'\\t'", b'\t');
    test_byte("b'\\''", b'\'');
    test_byte("b'\"'", b'"');
}

#[test]
fn chars() {
    fn test_char(s: &str, value: char) {
        match lit(s) {
            Lit::Char(lit) => {
                assert_eq!(lit.value(), value);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_char(&again, value);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_char("'a'", 'a');
    test_char("'\\n'", '\n');
    test_char("'\\r'", '\r');
    test_char("'\\t'", '\t');
    test_char("'🐕'", '🐕'); // NOTE: This is an emoji
    test_char("'\\''", '\'');
    test_char("'\"'", '"');
    test_char("'\\u{1F415}'", '\u{1F415}');
}

#[test]
fn ints() {
    fn test_int(s: &str, value: u64, suffix: &str) {
        match lit(s) {
            Lit::Int(lit) => {
                assert_eq!(lit.base10_digits().parse::<u64>().unwrap(), value);
                assert_eq!(lit.suffix(), suffix);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_int(&again, value, suffix);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_int("5", 5, "");
    test_int("5u32", 5, "u32");
    test_int("5_0", 50, "");
    test_int("5_____0_____", 50, "");
    test_int("0x7f", 127, "");
    test_int("0x7F", 127, "");
    test_int("0b1001", 9, "");
    test_int("0o73", 59, "");
    test_int("0x7Fu8", 127, "u8");
    test_int("0b1001i8", 9, "i8");
    test_int("0o73u32", 59, "u32");
    test_int("0x__7___f_", 127, "");
    test_int("0x__7___F_", 127, "");
    test_int("0b_1_0__01", 9, "");
    test_int("0o_7__3", 59, "");
    test_int("0x_7F__u8", 127, "u8");
    test_int("0b__10__0_1i8", 9, "i8");
    test_int("0o__7__________________3u32", 59, "u32");
}

#[test]
fn floats() {
    #[cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
    fn test_float(s: &str, value: f64, suffix: &str) {
        match lit(s) {
            Lit::Float(lit) => {
                assert_eq!(lit.base10_digits().parse::<f64>().unwrap(), value);
                assert_eq!(lit.suffix(), suffix);
                let again = lit.into_token_stream().to_string();
                if again != s {
                    test_float(&again, value, suffix);
                }
            }
            wrong => panic!("{:?}", wrong),
        }
    }

    test_float("5.5", 5.5, "");
    test_float("5.5E12", 5.5e12, "");
    test_float("5.5e12", 5.5e12, "");
    test_float("1.0__3e-12", 1.03e-12, "");
    test_float("1.03e+12", 1.03e12, "");
}

#[test]
fn negative() {
    let span = Span::call_site();
    assert_eq!("-1", LitInt::new("-1", span).to_string());
    assert_eq!("-1i8", LitInt::new("-1i8", span).to_string());
    assert_eq!("-1i16", LitInt::new("-1i16", span).to_string());
    assert_eq!("-1i32", LitInt::new("-1i32", span).to_string());
    assert_eq!("-1i64", LitInt::new("-1i64", span).to_string());
    assert_eq!("-1.5", LitFloat::new("-1.5", span).to_string());
    assert_eq!("-1.5f32", LitFloat::new("-1.5f32", span).to_string());
    assert_eq!("-1.5f64", LitFloat::new("-1.5f64", span).to_string());
}

#[test]
fn suffix() {
    fn get_suffix(token: &str) -> String {
        let lit = syn::parse_str::<Lit>(token).unwrap();
        match lit {
            Lit::Str(lit) => lit.suffix().to_owned(),
            //Lit::ByteStr(lit) => lit.suffix().to_owned(),
            //Lit::Byte(lit) => lit.suffix().to_owned(),
            //Lit::Char(lit) => lit.suffix().to_owned(),
            _ => unimplemented!(),
        }
    }

    assert_eq!(get_suffix("\"\"s"), "s");
    assert_eq!(get_suffix("r\"\"r"), "r");
    assert_eq!(get_suffix("b\"\"b"), "b");
    assert_eq!(get_suffix("br\"\"br"), "br");
    assert_eq!(get_suffix("r#\"\"#r"), "r");
    assert_eq!(get_suffix("'c'c"), "c");
    assert_eq!(get_suffix("b'b'b"), "b");
}
<|endoftext|>


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

//! Traits for algebra.

#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_results)]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]

#[macro_use]
extern crate approx;
#[cfg(feature = "decimal")]
extern crate decimal;
#[cfg(not(feature = "std"))]
extern crate libm;
extern crate num_complex;
extern crate num_traits as num;

#[cfg(not(feature = "std"))]
use core as std;

#[macro_use]
mod macros;
pub mod general;
pub mod linear;
<commit_msg>Add macro_use for the decimal crate.<commit_after>// Copyright 2013-2014 The Algebra Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Traits for algebra.

#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_results)]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]

#[macro_use]
extern crate approx;
#[cfg(feature = "decimal")]
#[macro_use]
extern crate decimal;
#[cfg(not(feature = "std"))]
extern crate libm;
extern crate num_complex;
extern crate num_traits as num;

#[cfg(not(feature = "std"))]
use core as std;

#[macro_use]
mod macros;
pub mod general;
pub mod linear;
<|endoftext|>


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

//! CSS tables.

#![deny(unsafe_block)]

use block::{BlockFlow, BlockNonReplaced, FloatNonReplaced, ISizeAndMarginsComputer};
use block::{ISizeConstraintInput, MarginsMayNotCollapse};
use construct::FlowConstructor;
use context::LayoutContext;
use floats::FloatKind;
use flow::{TableWrapperFlowClass, FlowClass, Flow, ImmutableFlowUtils};
use fragment::Fragment;
use model::{Specified, Auto, specified};
use wrapper::ThreadSafeLayoutNode;

use servo_util::geometry::Au;
use std::cmp::max;
use std::fmt;
use style::computed_values::{float, table_layout};

#[deriving(Encodable)]
pub enum TableLayout {
    FixedLayout,
    AutoLayout
}

/// A table wrapper flow based on a block formatting context.
#[deriving(Encodable)]
pub struct TableWrapperFlow {
    pub block_flow: BlockFlow,

    /// Column inline-sizes
    pub col_inline_sizes: Vec<Au>,

    /// Table-layout property
    pub table_layout: TableLayout,
}

impl TableWrapperFlow {
    pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
                                  fragment: Fragment)
                                  -> TableWrapperFlow {
        let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment);
        let table_layout = if block_flow.fragment().style().get_table().table_layout ==
                              table_layout::fixed {
            FixedLayout
        } else {
            AutoLayout
        };
        TableWrapperFlow {
            block_flow: block_flow,
            col_inline_sizes: vec!(),
            table_layout: table_layout
        }
    }

    pub fn from_node(constructor: &mut FlowConstructor,
                     node: &ThreadSafeLayoutNode)
                     -> TableWrapperFlow {
        let mut block_flow = BlockFlow::from_node(constructor, node);
        let table_layout = if block_flow.fragment().style().get_table().table_layout ==
                              table_layout::fixed {
            FixedLayout
        } else {
            AutoLayout
        };
        TableWrapperFlow {
            block_flow: block_flow,
            col_inline_sizes: vec!(),
            table_layout: table_layout
        }
    }

    pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
                                        fragment: Fragment,
                                        float_kind: FloatKind)
                                        -> TableWrapperFlow {
        let mut block_flow = BlockFlow::float_from_node_and_fragment(node, fragment, float_kind);
        let table_layout = if block_flow.fragment().style().get_table().table_layout ==
                              table_layout::fixed {
            FixedLayout
        } else {
            AutoLayout
        };
        TableWrapperFlow {
            block_flow: block_flow,
            col_inline_sizes: vec!(),
            table_layout: table_layout
        }
    }

    pub fn build_display_list_table_wrapper(&mut self, layout_context: &LayoutContext) {
        debug!("build_display_list_table_wrapper: same process as block flow");
        self.block_flow.build_display_list_block(layout_context);
    }

    fn calculate_table_column_sizes(&mut self, mut input: ISizeConstraintInput)
                                    -> ISizeConstraintInput {
        let style = self.block_flow.fragment.style();

        // Get inline-start and inline-end paddings, borders for table.
        // We get these values from the fragment's style since table_wrapper doesn't have its own
        // border or padding. input.available_inline_size is same as containing_block_inline_size
        // in table_wrapper.
        let padding = style.logical_padding();
        let border = style.logical_border_width();
        let padding_and_borders =
            specified(padding.inline_start, input.available_inline_size) +
            specified(padding.inline_end, input.available_inline_size) +
            border.inline_start +
            border.inline_end;

        let computed_inline_size = match self.table_layout {
            FixedLayout => {
                let fixed_cells_inline_size = self.col_inline_sizes
                                                  .iter()
                                                  .fold(Au(0), |sum, inline_size| {
                        sum.add(inline_size)
                    });

                let mut computed_inline_size = input.computed_inline_size.specified_or_zero();

                // Compare border-edge inline-sizes. Because fixed_cells_inline_size indicates
                // content-inline-size, padding and border values are added to
                // fixed_cells_inline_size.
                computed_inline_size = max(
                    fixed_cells_inline_size + padding_and_borders, computed_inline_size);
                computed_inline_size
            },
            AutoLayout => {
                // Automatic table layout is calculated according to CSS 2.1 § 17.5.2.2.
                let mut cap_min = Au(0);
                let mut cols_min = Au(0);
                let mut cols_max = Au(0);
                let mut col_min_inline_sizes = &vec!();
                let mut col_pref_inline_sizes = &vec!();
                for kid in self.block_flow.base.child_iter() {
                    if kid.is_table_caption() {
                        cap_min = kid.as_block().base.intrinsic_inline_sizes.minimum_inline_size;
                    } else {
                        assert!(kid.is_table());
                        cols_min = kid.as_block().base.intrinsic_inline_sizes.minimum_inline_size;
                        cols_max = kid.as_block()
                                      .base
                                      .intrinsic_inline_sizes
                                      .preferred_inline_size;
                        col_min_inline_sizes = kid.col_min_inline_sizes();
                        col_pref_inline_sizes = kid.col_pref_inline_sizes();
                    }
                }
                // 'extra_inline-size': difference between the calculated table inline-size and
                // minimum inline-size required by all columns. It will be distributed over the
                // columns.
                let (inline_size, extra_inline_size) = match input.computed_inline_size {
                    Auto => {
                        if input.available_inline_size > max(cols_max, cap_min) {
                            if cols_max > cap_min {
                                self.col_inline_sizes = col_pref_inline_sizes.clone();
                                (cols_max, Au(0))
                            } else {
                                (cap_min, cap_min - cols_min)
                            }
                        } else {
                            let max = if cols_min >= input.available_inline_size &&
                                    cols_min >= cap_min {
                                self.col_inline_sizes = col_min_inline_sizes.clone();
                                cols_min
                            } else {
                                max(input.available_inline_size, cap_min)
                            };
                            (max, max - cols_min)
                        }
                    },
                    Specified(inline_size) => {
                        let max = if cols_min >= inline_size && cols_min >= cap_min {
                            self.col_inline_sizes = col_min_inline_sizes.clone();
                            cols_min
                        } else {
                            max(inline_size, cap_min)
                        };
                        (max, max - cols_min)
                    }
                };
                // The extra inline-size is distributed over the columns
                if extra_inline_size > Au(0) {
                    let cell_len = self.col_inline_sizes.len() as f64;
                    self.col_inline_sizes = col_min_inline_sizes.iter()
                                                                         .map(|inline_size| {
                        inline_size + extra_inline_size.scale_by(1.0 / cell_len)
                    }).collect();
                }
                inline_size + padding_and_borders
            }
        };
        input.computed_inline_size = Specified(computed_inline_size);
        input
    }

    fn compute_used_inline_size(&mut self,
                                layout_context: &LayoutContext,
                                parent_flow_inline_size: Au) {
        // Delegate to the appropriate inline size computer to find the constraint inputs.
        let mut input = if self.is_float() {
            FloatNonReplaced.compute_inline_size_constraint_inputs(&mut self.block_flow,
                                                                   parent_flow_inline_size,
                                                                   layout_context)
        } else {
            BlockNonReplaced.compute_inline_size_constraint_inputs(&mut self.block_flow,
                                                                   parent_flow_inline_size,
                                                                   layout_context)
        };

        // Compute the inline sizes of the columns.
        input = self.calculate_table_column_sizes(input);

        // Delegate to the appropriate inline size computer to write the constraint solutions in.
        if self.is_float() {
            let solution = FloatNonReplaced.solve_inline_size_constraints(&mut self.block_flow,
                                                                          &input);
            FloatNonReplaced.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
            FloatNonReplaced.set_flow_x_coord_if_necessary(&mut self.block_flow, solution);
        } else {
            let solution = BlockNonReplaced.solve_inline_size_constraints(&mut self.block_flow,
                                                                          &input);
            BlockNonReplaced.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
            BlockNonReplaced.set_flow_x_coord_if_necessary(&mut self.block_flow, solution);
        }
    }
}

impl Flow for TableWrapperFlow {
    fn class(&self) -> FlowClass {
        TableWrapperFlowClass
    }

    fn is_float(&self) -> bool {
        self.block_flow.is_float()
    }

    fn as_table_wrapper<'a>(&'a mut self) -> &'a mut TableWrapperFlow {
        self
    }

    fn as_block<'a>(&'a mut self) -> &'a mut BlockFlow {
        &mut self.block_flow
    }

    fn float_kind(&self) -> float::T {
        self.block_flow.float_kind()
    }

    fn bubble_inline_sizes(&mut self, ctx: &LayoutContext) {
        // get column inline-sizes info from table flow
        for kid in self.block_flow.base.child_iter() {
            assert!(kid.is_table_caption() || kid.is_table());

            if kid.is_table() {
                self.col_inline_sizes.push_all(kid.as_table().col_inline_sizes.as_slice());
            }
        }

        self.block_flow.bubble_inline_sizes(ctx);
    }

    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
        debug!("assign_inline_sizes({}): assigning inline_size for flow",
               if self.is_float() {
                   "floated table_wrapper"
               } else {
                   "table_wrapper"
               });

        // Table wrappers are essentially block formatting contexts and are therefore never
        // impacted by floats.
        self.block_flow.base.flags.set_impacted_by_left_floats(false);
        self.block_flow.base.flags.set_impacted_by_right_floats(false);

        // Our inline-size was set to the inline-size of the containing block by the flow's parent.
        // Now compute the real value.
        let containing_block_inline_size = self.block_flow.base.position.size.inline;
        if self.is_float() {
            self.block_flow.float.get_mut_ref().containing_inline_size =
                containing_block_inline_size;
        }

        self.compute_used_inline_size(layout_context, containing_block_inline_size);

        let inline_start_content_edge = self.block_flow.fragment.border_box.start.i;
        let content_inline_size = self.block_flow.fragment.border_box.size.inline;

        // In case of fixed layout, column inline-sizes are calculated in table flow.
        let assigned_col_inline_sizes = match self.table_layout {
            FixedLayout => None,
            AutoLayout => Some(self.col_inline_sizes.clone())
        };

        self.block_flow.propagate_assigned_inline_size_to_children(inline_start_content_edge,
                                                                   content_inline_size,
                                                                   assigned_col_inline_sizes);
    }

    fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
        debug!("assign_block_size: assigning block_size for table_wrapper");
        self.block_flow.assign_block_size_block_base(ctx, MarginsMayNotCollapse);
    }

    fn compute_absolute_position(&mut self) {
        self.block_flow.compute_absolute_position()
    }

    fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self,
                                                            layout_context: &'a LayoutContext<'a>)
                                                            -> bool {
        if self.block_flow.is_float() {
            self.block_flow.place_float();
            return true
        }

        let impacted = self.block_flow.base.flags.impacted_by_floats();
        if impacted {
            self.assign_block_size(layout_context);
        }
        impacted
    }
}

impl fmt::Show for TableWrapperFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.is_float() {
            write!(f, "TableWrapperFlow(Float): {}", self.block_flow.fragment)
        } else {
            write!(f, "TableWrapperFlow: {}", self.block_flow.fragment)
        }
    }
}

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

//! CSS tables.

#![deny(unsafe_block)]

use block::{BlockFlow, BlockNonReplaced, FloatNonReplaced, ISizeAndMarginsComputer};
use block::{ISizeConstraintInput, MarginsMayNotCollapse};
use construct::FlowConstructor;
use context::LayoutContext;
use floats::FloatKind;
use flow::{TableWrapperFlowClass, FlowClass, Flow, ImmutableFlowUtils};
use fragment::Fragment;
use model::{Specified, Auto, specified};
use wrapper::ThreadSafeLayoutNode;

use servo_util::geometry::Au;
use std::cmp::max;
use std::fmt;
use style::computed_values::{float, table_layout};

#[deriving(Encodable)]
pub enum TableLayout {
    FixedLayout,
    AutoLayout
}

/// A table wrapper flow based on a block formatting context.
#[deriving(Encodable)]
pub struct TableWrapperFlow {
    pub block_flow: BlockFlow,

    /// Column inline-sizes
    pub col_inline_sizes: Vec<Au>,

    /// Table-layout property
    pub table_layout: TableLayout,
}

impl TableWrapperFlow {
    pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
                                  fragment: Fragment)
                                  -> TableWrapperFlow {
        let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment);
        let table_layout = if block_flow.fragment().style().get_table().table_layout ==
                              table_layout::fixed {
            FixedLayout
        } else {
            AutoLayout
        };
        TableWrapperFlow {
            block_flow: block_flow,
            col_inline_sizes: vec!(),
            table_layout: table_layout
        }
    }

    pub fn from_node(constructor: &mut FlowConstructor,
                     node: &ThreadSafeLayoutNode)
                     -> TableWrapperFlow {
        let mut block_flow = BlockFlow::from_node(constructor, node);
        let table_layout = if block_flow.fragment().style().get_table().table_layout ==
                              table_layout::fixed {
            FixedLayout
        } else {
            AutoLayout
        };
        TableWrapperFlow {
            block_flow: block_flow,
            col_inline_sizes: vec!(),
            table_layout: table_layout
        }
    }

    pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
                                        fragment: Fragment,
                                        float_kind: FloatKind)
                                        -> TableWrapperFlow {
        let mut block_flow = BlockFlow::float_from_node_and_fragment(node, fragment, float_kind);
        let table_layout = if block_flow.fragment().style().get_table().table_layout ==
                              table_layout::fixed {
            FixedLayout
        } else {
            AutoLayout
        };
        TableWrapperFlow {
            block_flow: block_flow,
            col_inline_sizes: vec!(),
            table_layout: table_layout
        }
    }

    pub fn build_display_list_table_wrapper(&mut self, layout_context: &LayoutContext) {
        debug!("build_display_list_table_wrapper: same process as block flow");
        self.block_flow.build_display_list_block(layout_context);
    }

    fn calculate_table_column_sizes(&mut self, mut input: ISizeConstraintInput)
                                    -> ISizeConstraintInput {
        let style = self.block_flow.fragment.style();

        // Get inline-start and inline-end paddings, borders for table.
        // We get these values from the fragment's style since table_wrapper doesn't have its own
        // border or padding. input.available_inline_size is same as containing_block_inline_size
        // in table_wrapper.
        let padding = style.logical_padding();
        let border = style.logical_border_width();
        let padding_and_borders =
            specified(padding.inline_start, input.available_inline_size) +
            specified(padding.inline_end, input.available_inline_size) +
            border.inline_start +
            border.inline_end;

        let computed_inline_size = match self.table_layout {
            FixedLayout => {
                let fixed_cells_inline_size = self.col_inline_sizes
                                                  .iter()
                                                  .fold(Au(0), |sum, inline_size| {
                        sum.add(inline_size)
                    });

                let mut computed_inline_size = input.computed_inline_size.specified_or_zero();

                // Compare border-edge inline-sizes. Because fixed_cells_inline_size indicates
                // content-inline-size, padding and border values are added to
                // fixed_cells_inline_size.
                computed_inline_size = max(
                    fixed_cells_inline_size + padding_and_borders, computed_inline_size);
                computed_inline_size
            },
            AutoLayout => {
                // Automatic table layout is calculated according to CSS 2.1 § 17.5.2.2.
                let mut cap_min = Au(0);
                let mut cols_min = Au(0);
                let mut cols_max = Au(0);
                let mut col_min_inline_sizes = &vec!();
                let mut col_pref_inline_sizes = &vec!();
                for kid in self.block_flow.base.child_iter() {
                    if kid.is_table_caption() {
                        cap_min = kid.as_block().base.intrinsic_inline_sizes.minimum_inline_size;
                    } else {
                        assert!(kid.is_table());
                        cols_min = kid.as_block().base.intrinsic_inline_sizes.minimum_inline_size;
                        cols_max = kid.as_block()
                                      .base
                                      .intrinsic_inline_sizes
                                      .preferred_inline_size;
                        col_min_inline_sizes = kid.col_min_inline_sizes();
                        col_pref_inline_sizes = kid.col_pref_inline_sizes();
                    }
                }
                // 'extra_inline-size': difference between the calculated table inline-size and
                // minimum inline-size required by all columns. It will be distributed over the
                // columns.
                let (inline_size, extra_inline_size) = match input.computed_inline_size {
                    Auto => {
                        if input.available_inline_size > max(cols_max, cap_min) {
                            if cols_max > cap_min {
                                self.col_inline_sizes = col_pref_inline_sizes.clone();
                                (cols_max, Au(0))
                            } else {
                                (cap_min, cap_min - cols_min)
                            }
                        } else {
                            let max = if cols_min >= input.available_inline_size &&
                                    cols_min >= cap_min {
                                self.col_inline_sizes = col_min_inline_sizes.clone();
                                cols_min
                            } else {
                                max(input.available_inline_size, cap_min)
                            };
                            (max, max - cols_min)
                        }
                    },
                    Specified(inline_size) => {
                        let max = if cols_min >= inline_size && cols_min >= cap_min {
                            self.col_inline_sizes = col_min_inline_sizes.clone();
                            cols_min
                        } else {
                            max(inline_size, cap_min)
                        };
                        (max, max - cols_min)
                    }
                };
                // The extra inline-size is distributed over the columns
                if extra_inline_size > Au(0) {
                    let cell_len = self.col_inline_sizes.len() as f64;
                    self.col_inline_sizes = col_min_inline_sizes.iter()
                                                                         .map(|inline_size| {
                        inline_size + extra_inline_size.scale_by(1.0 / cell_len)
                    }).collect();
                }
                inline_size + padding_and_borders
            }
        };
        input.computed_inline_size = Specified(computed_inline_size);
        input
    }

    fn compute_used_inline_size(&mut self,
                                layout_context: &LayoutContext,
                                parent_flow_inline_size: Au) {
        // Delegate to the appropriate inline size computer to find the constraint inputs.
        let mut input = if self.is_float() {
            FloatNonReplaced.compute_inline_size_constraint_inputs(&mut self.block_flow,
                                                                   parent_flow_inline_size,
                                                                   layout_context)
        } else {
            BlockNonReplaced.compute_inline_size_constraint_inputs(&mut self.block_flow,
                                                                   parent_flow_inline_size,
                                                                   layout_context)
        };

        // Compute the inline sizes of the columns.
        input = self.calculate_table_column_sizes(input);

        // Delegate to the appropriate inline size computer to write the constraint solutions in.
        if self.is_float() {
            let solution = FloatNonReplaced.solve_inline_size_constraints(&mut self.block_flow,
                                                                          &input);
            FloatNonReplaced.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
            FloatNonReplaced.set_flow_x_coord_if_necessary(&mut self.block_flow, solution);
        } else {
            let solution = BlockNonReplaced.solve_inline_size_constraints(&mut self.block_flow,
                                                                          &input);
            BlockNonReplaced.set_inline_size_constraint_solutions(&mut self.block_flow, solution);
            BlockNonReplaced.set_flow_x_coord_if_necessary(&mut self.block_flow, solution);
        }
    }
}

impl Flow for TableWrapperFlow {
    fn class(&self) -> FlowClass {
        TableWrapperFlowClass
    }

    fn is_float(&self) -> bool {
        self.block_flow.is_float()
    }

    fn as_table_wrapper<'a>(&'a mut self) -> &'a mut TableWrapperFlow {
        self
    }

    fn as_block<'a>(&'a mut self) -> &'a mut BlockFlow {
        &mut self.block_flow
    }

    fn float_kind(&self) -> float::T {
        self.block_flow.float_kind()
    }

    fn bubble_inline_sizes(&mut self, ctx: &LayoutContext) {
        // get column inline-sizes info from table flow
        for kid in self.block_flow.base.child_iter() {
            assert!(kid.is_table_caption() || kid.is_table());

            if kid.is_table() {
                self.col_inline_sizes.push_all(kid.as_table().col_inline_sizes.as_slice());
            }
        }

        self.block_flow.bubble_inline_sizes(ctx);
    }

    fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
        debug!("assign_inline_sizes({}): assigning inline_size for flow",
               if self.is_float() {
                   "floated table_wrapper"
               } else {
                   "table_wrapper"
               });

        // Table wrappers are essentially block formatting contexts and are therefore never
        // impacted by floats.
        self.block_flow.base.flags.set_impacted_by_left_floats(false);
        self.block_flow.base.flags.set_impacted_by_right_floats(false);

        // Our inline-size was set to the inline-size of the containing block by the flow's parent.
        // Now compute the real value.
        let containing_block_inline_size = self.block_flow.base.position.size.inline;
        if self.is_float() {
            self.block_flow.float.as_mut().unwrap().containing_inline_size =
                containing_block_inline_size;
        }

        self.compute_used_inline_size(layout_context, containing_block_inline_size);

        let inline_start_content_edge = self.block_flow.fragment.border_box.start.i;
        let content_inline_size = self.block_flow.fragment.border_box.size.inline;

        // In case of fixed layout, column inline-sizes are calculated in table flow.
        let assigned_col_inline_sizes = match self.table_layout {
            FixedLayout => None,
            AutoLayout => Some(self.col_inline_sizes.clone())
        };

        self.block_flow.propagate_assigned_inline_size_to_children(inline_start_content_edge,
                                                                   content_inline_size,
                                                                   assigned_col_inline_sizes);
    }

    fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
        debug!("assign_block_size: assigning block_size for table_wrapper");
        self.block_flow.assign_block_size_block_base(ctx, MarginsMayNotCollapse);
    }

    fn compute_absolute_position(&mut self) {
        self.block_flow.compute_absolute_position()
    }

    fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self,
                                                            layout_context: &'a LayoutContext<'a>)
                                                            -> bool {
        if self.block_flow.is_float() {
            self.block_flow.place_float();
            return true
        }

        let impacted = self.block_flow.base.flags.impacted_by_floats();
        if impacted {
            self.assign_block_size(layout_context);
        }
        impacted
    }
}

impl fmt::Show for TableWrapperFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.is_float() {
            write!(f, "TableWrapperFlow(Float): {}", self.block_flow.fragment)
        } else {
            write!(f, "TableWrapperFlow: {}", self.block_flow.fragment)
        }
    }
}

<|endoftext|>


<commit_before>#[allow(unstable)]
extern crate core;

use core::marker::Copy;
use core::option::Option;
use core::iter::Iterator;
use core::str::StrExt;

use asm;
use interrupt;

pub struct Console {
    position:u32
}

#[allow(dead_code)]
pub enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

struct IntRange {
    cur: isize,
    max: isize
}

impl IntRange {
    fn next(&mut self) -> Option<isize> {
        if self.cur < self.max {
            self.cur += 1;
            Option::Some(self.cur - 1)
        } else {
            Option::None
        }
    }
}

fn range(lo: isize, hi: isize) -> IntRange {
    IntRange { cur: lo, max: hi }
}

impl Copy for Color {}

static mut console: Console = Console {position: 0};

impl Console {
    pub fn init() -> &'static mut Console {
        interrupt::register_handler(on_keyboard_interrupt);
        unsafe {
            return &mut console;
        }
    }

    pub fn clear_screen(&self,background: Color) {
        let mut r = range(0, 80 * 25);
        loop {
            match r.next() {
                Option::Some(x) => {
                    unsafe {
                        *((0xb8000 + x * 2) as *mut u16) = (background as u16) << 12;
                    }
                },
                Option::None =>{break}
            }
        }
        self.move_cursor(0);
    }

    #[allow(unstable)]
    #[no_stack_check]
    pub fn print_string(&mut self,string: &str) {
        let mut bytes = string.chars();
        loop {
            match bytes.next() {
                Option::Some(x) => {
                    self.print_char(x);
                },
                Option::None =>{break}
            }
        }
    }

    pub fn print_char(&mut self,c: char) {
        if c == '\n' {
            self.position += 80;
            let col = self.position % 80;
            self.position -= col;
        } else {
            unsafe {
                *((0xb8000 + self.position*2) as *mut u8) = c as u8;
                *((0xb8000 + self.position*2 + 1) as *mut u8) = 0x0f;
            }
            self.position += 1;
        }
        self.update_cursor();
    }

    pub fn print_int(&mut self, number: u32) {
        let mut length = 0;
        let output:[u8;64] = [0;64];
        let mut left = number;
        loop {
            //TODO: Must be a better way to write to vector without bounds checking
            let output_addr:*const u8 = &output[0];
            let output_addr_u32:u32=output_addr as u32;
            unsafe {
                *((output_addr_u32 + length) as *mut u8) = (left % 10) as u8;
            }
            length += 1;
            left = left / 10;
            if left == 0 {
                break;
            }
        }
        loop {
            let c:char = (output[(length-1) as usize] + 0x30) as char;
            self.print_char(c);
            length -= 1;
            if length == 0 {
                break;
            }
        }
    }

    fn update_cursor(&self) {
        self.move_cursor(self.position);
    }

    fn move_cursor(&self,pos: u32) {
        asm::outb(0x3D4,15);
        asm::outb(0x3D5,(pos & 0xff) as u8);
        asm::outb(0x3D4,14);
        asm::outb(0x3D5,((pos >> 8) & 0xff) as u8);
    }
}

#[no_stack_check]
fn on_keyboard_interrupt() {
    let scancode = asm::inb(0x60);
    // Keydown
    if scancode & 0b10000000 == 0 {
        let c = scancode_to_char(scancode);
        unsafe {
            console.print_char(c);
        }
    }
}

fn scancode_to_char(scancode: u8) -> char {
    let mut charmap:[char;256] = ['?';256];
    charmap[0x2] = '1';
    charmap[0x3] = '2';
    charmap[0x4] = '3';
    charmap[0x5] = '4';
    charmap[0x6] = '5';
    charmap[0x7] = '6';
    charmap[0x8] = '7';
    charmap[0x9] = '8';
    charmap[0xA] = '9';
    charmap[0xB] = '0';
    charmap[0x1C] = '\n';

    return charmap[scancode as usize];
}
<commit_msg>Use range from libcore<commit_after>#[allow(unstable)]
extern crate core;

use core::marker::Copy;
use core::option::Option;
use core::iter::Iterator;
use core::str::StrExt;
use core::iter::range;

use asm;
use interrupt;

pub struct Console {
    position:u32
}

#[allow(dead_code)]
pub enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

impl Copy for Color {}

static mut console: Console = Console {position: 0};

impl Console {
    pub fn init() -> &'static mut Console {
        interrupt::register_handler(on_keyboard_interrupt);
        unsafe {
            return &mut console;
        }
    }

    pub fn clear_screen(&self,background: Color) {
        let mut r = range(0, 80 * 25);
        loop {
            match r.next() {
                Option::Some(x) => {
                    unsafe {
                        *((0xb8000 + x * 2) as *mut u16) = (background as u16) << 12;
                    }
                },
                Option::None =>{break}
            }
        }
        self.move_cursor(0);
    }

    #[allow(unstable)]
    #[no_stack_check]
    pub fn print_string(&mut self,string: &str) {
        let mut bytes = string.chars();
        loop {
            match bytes.next() {
                Option::Some(x) => {
                    self.print_char(x);
                },
                Option::None =>{break}
            }
        }
    }

    pub fn print_char(&mut self,c: char) {
        if c == '\n' {
            self.position += 80;
            let col = self.position % 80;
            self.position -= col;
        } else {
            unsafe {
                *((0xb8000 + self.position*2) as *mut u8) = c as u8;
                *((0xb8000 + self.position*2 + 1) as *mut u8) = 0x0f;
            }
            self.position += 1;
        }
        self.update_cursor();
    }

    pub fn print_int(&mut self, number: u32) {
        let mut length = 0;
        let output:[u8;64] = [0;64];
        let mut left = number;
        loop {
            //TODO: Must be a better way to write to vector without bounds checking
            let output_addr:*const u8 = &output[0];
            let output_addr_u32:u32=output_addr as u32;
            unsafe {
                *((output_addr_u32 + length) as *mut u8) = (left % 10) as u8;
            }
            length += 1;
            left = left / 10;
            if left == 0 {
                break;
            }
        }
        loop {
            let c:char = (output[(length-1) as usize] + 0x30) as char;
            self.print_char(c);
            length -= 1;
            if length == 0 {
                break;
            }
        }
    }

    fn update_cursor(&self) {
        self.move_cursor(self.position);
    }

    fn move_cursor(&self,pos: u32) {
        asm::outb(0x3D4,15);
        asm::outb(0x3D5,(pos & 0xff) as u8);
        asm::outb(0x3D4,14);
        asm::outb(0x3D5,((pos >> 8) & 0xff) as u8);
    }
}

#[no_stack_check]
fn on_keyboard_interrupt() {
    let scancode = asm::inb(0x60);
    // Keydown
    if scancode & 0b10000000 == 0 {
        let c = scancode_to_char(scancode);
        unsafe {
            console.print_char(c);
        }
    }
}

fn scancode_to_char(scancode: u8) -> char {
    let mut charmap:[char;256] = ['?';256];
    charmap[0x2] = '1';
    charmap[0x3] = '2';
    charmap[0x4] = '3';
    charmap[0x5] = '4';
    charmap[0x6] = '5';
    charmap[0x7] = '6';
    charmap[0x8] = '7';
    charmap[0x9] = '8';
    charmap[0xA] = '9';
    charmap[0xB] = '0';
    charmap[0x1C] = '\n';

    return charmap[scancode as usize];
}
<|endoftext|>


<commit_before>#![feature(pin, arbitrary_self_types, futures_api)]

#[macro_use]
extern crate futures;

use futures::executor::block_on;
use futures::future;
use futures::prelude::*;

#[test]
fn smoke() {
    let mut counter = 0;

    {
        let work = future::ready::<i32>(40).inspect(|val| { counter += *val; });
        assert_eq!(block_on(work), 40);
    }

    assert_eq!(counter, 40);
}
<commit_msg>Remove unused macro use warning<commit_after>#![feature(pin, arbitrary_self_types, futures_api)]

use futures::executor::block_on;
use futures::future;
use futures::prelude::*;

#[test]
fn smoke() {
    let mut counter = 0;

    {
        let work = future::ready::<i32>(40).inspect(|val| { counter += *val; });
        assert_eq!(block_on(work), 40);
    }

    assert_eq!(counter, 40);
}
<|endoftext|>


<commit_before>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// TODO(b/213149158): Remove after uses are added.
#![allow(dead_code)]

#[cfg(test)]
use lazy_static::lazy_static;
#[cfg(test)]
use std::arch::x86_64::CpuidResult;
#[cfg(not(test))]
use std::arch::x86_64::__cpuid_count;
#[cfg(test)]
use std::sync::Arc;
#[cfg(test)]
use sync::Mutex;

/// Gets the TSC frequency for cpuid leaf 0x15 from the existing leaves 0x15 and 0x16
pub fn tsc_frequency_cpuid() -> Option<hypervisor::CpuIdEntry> {
    // Safe because we pass 0 and 0 for this call and the host supports the `cpuid` instruction.
    let result = unsafe { __cpuid_count(0, 0) };
    if result.eax < 0x15 {
        return None;
    }

    let mut tsc_freq = hypervisor::CpuIdEntry {
        // 0x15 is the TSC frequency leaf.
        function: 0x15,
        index: 0,
        flags: 0,
        eax: 0,
        ebx: 0,
        ecx: 0,
        edx: 0,
    };
    // Safe because we pass 0 and 0 for this call and the host supports the `cpuid` instruction.
    unsafe {
        let result = __cpuid_count(tsc_freq.function, tsc_freq.index);
        tsc_freq.eax = result.eax;
        tsc_freq.ebx = result.ebx;
        tsc_freq.ecx = result.ecx;
        tsc_freq.edx = result.edx;
    }

    if tsc_freq.ecx != 0 {
        Some(tsc_freq)
    } else {
        // The core crystal frequency is missing. Old kernels (<5.3) don't try to derive it from the
        // CPU base clock speed. Here, we essentially implement
        // https://lore.kernel.org/patchwork/patch/1064690/ so that old kernels can calibrate TSC.
        // Safe because the host supports `cpuid` instruction.
        let cpu_clock = unsafe {
            // 0x16 is the base clock frequency leaf.
            __cpuid_count(0x16, 0)
        };
        if cpu_clock.eax > 0 {
            // Here, we assume the CPU base clock is the core crystal clock, as is done in the patch
            // that exists in 5.3+ kernels. We further assume that the core crystal clock is exactly
            // the TSC frequency. As such, we expose the base clock scaled by the _inverse_ of the
            // "tsc freq" / "core crystal clock freq" ratio. That way when the kernel extracts
            // the frequency & multiplies by the ratio, it obtains the TSC frequency.
            //
            // base_mhz = cpu_clock.eax
            // tsc_to_base_ratio = tsc_freq.eax / tsc_freq.ebx
            // crystal_hz = base_mhz * tsc_base_to_clock_ratio * 10^6
            tsc_freq.ecx = (cpu_clock.eax as f64 * tsc_freq.eax as f64 * 1_000_000_f64
                / tsc_freq.ebx as f64)
                .round() as u32;
            Some(tsc_freq)
        } else {
            None
        }
    }
}

/// Given the tsc frequency in Hz and the bus frequency in Hz, return a fake version of
/// cpuid leaf 0x15.
pub fn fake_tsc_frequency_cpuid(tsc_hz: u64, bus_hz: u32) -> hypervisor::CpuIdEntry {
    // We use 1000 for the crystal clock ratio denominator so we can preserve precision in case
    // tsc_hz is not neatly divisible by bus_hz
    let crystal_clock_ratio_denominator: u32 = 1000;
    let crystal_clock_ratio_numerator: u32 =
        (tsc_hz * crystal_clock_ratio_denominator as u64 / bus_hz as u64) as u32;

    hypervisor::CpuIdEntry {
        function: 0x15,
        index: 0,
        flags: 0,
        eax: crystal_clock_ratio_denominator,
        ebx: crystal_clock_ratio_numerator,
        ecx: bus_hz,
        edx: 0,
    }
}

/// Returns the Bus frequency in Hz, based on reading Intel-specific cpuids, or None
/// if the frequency can't be determined from cpuids.
pub fn bus_freq_hz() -> Option<u32> {
    tsc_frequency_cpuid().map(|cpuid| cpuid.ecx)
}

/// Returns the TSC frequency in Hz, based on reading Intel-specific cpuids, or None
/// if the frequency can't be determined from cpuids.
pub fn tsc_freq_hz() -> Option<u32> {
    tsc_frequency_cpuid()
        .map(|cpuid| (cpuid.ecx as u64 * cpuid.ebx as u64 / cpuid.eax as u64) as u32)
}

// This function is safe, but we mark it as unsafe so the signature matches the external
// __cpuid_count function so we don't get warnings.
#[cfg(test)]
unsafe fn __cpuid_count(function: u32, index: u32) -> CpuidResult {
    let cpuids = CPUIDS.lock();
    let entry = cpuids
        .iter()
        .find(|c| c.function == function && c.index == index)
        .map_or(hypervisor::CpuIdEntry::default(), |c| *c);

    CpuidResult {
        eax: entry.eax,
        ebx: entry.ebx,
        ecx: entry.ecx,
        edx: entry.edx,
    }
}

// Note: to use this mock without cross test pollution, tests must be run serially. Since there
// is exactly one test using it at the moment, serial running is not required.
#[cfg(test)]
lazy_static! {
    static ref CPUIDS: Arc<Mutex<Vec<hypervisor::CpuIdEntry>>> = Arc::new(Mutex::new(Vec::new()));
}

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

    #[test]
    // It seems that most Intel CPUs don't have any TSC frequency information in CPUID.15H.ECX. The
    // linux kernel only treats the TSC frequency as a "known" frequency if it comes from
    // CPUID.15H.ECX, and we want our TSC frequency to be "known" to prevent clock watchdogs from
    // invalidating the TSC clocksource. So we derive CPUID.15H.ECX from the values in CPUID.16H.
    // This test verifies that that derivation is working correctly.
    fn test_leaf15_derivation() {
        let crystal_clock_ratio = 88;
        let tsc_frequency_hz = 2100000000u32;

        {
            let mut cpuids = CPUIDS.lock();

            cpuids.push(hypervisor::CpuIdEntry {
                function: 0,
                index: 0,
                eax: 0x16, // highest available leaf is 0x16
                ..Default::default()
            });

            cpuids.push(hypervisor::CpuIdEntry {
                function: 0x15,
                index: 0,
                eax: 2, // eax usually contains 2, and ebx/eax is the crystal clock ratio
                ebx: crystal_clock_ratio * 2,
                ..Default::default()
            });

            cpuids.push(hypervisor::CpuIdEntry {
                function: 0x16,
                index: 0,
                eax: tsc_frequency_hz / 1_000_000_u32, // MHz frequency
                ..Default::default()
            });
        }

        // We compare the frequencies divided by the crystal_clock_ratio because that's the
        // resolution that the tsc frequency is stored at in CPUID.15H.ECX.
        assert_eq!(
            tsc_freq_hz().unwrap() / crystal_clock_ratio,
            tsc_frequency_hz / crystal_clock_ratio
        );

        CPUIDS.lock().clear();
    }
}
<commit_msg>tsc: Refactor test imports<commit_after>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// TODO(b/213149158): Remove after uses are added.
#![allow(dead_code)]

cfg_if::cfg_if! {
    if #[cfg(test)] {
        use std::arch::x86_64::CpuidResult;
        use std::sync::Arc;
        use sync::Mutex;

        // Note: to use this mock without cross test pollution, tests must be run serially. Since
        // there is exactly one test using it at the moment, serial running is not required.
        lazy_static::lazy_static! {
            static ref CPUIDS: Arc<Mutex<Vec<hypervisor::CpuIdEntry>>> =
                Arc::new(Mutex::new(Vec::new()));
        }

        // This function is safe, but we mark it as unsafe so the signature matches the external
        // __cpuid_count function so we don't get warnings.
        unsafe fn __cpuid_count(function: u32, index: u32) -> CpuidResult {
            let cpuids = CPUIDS.lock();
            let entry = cpuids
                .iter()
                .find(|c| c.function == function && c.index == index)
                .map_or(hypervisor::CpuIdEntry::default(), |c| *c);

            CpuidResult {
                eax: entry.eax,
                ebx: entry.ebx,
                ecx: entry.ecx,
                edx: entry.edx,
            }
        }
    } else {
        use std::arch::x86_64::__cpuid_count;
    }
}

/// Gets the TSC frequency for cpuid leaf 0x15 from the existing leaves 0x15 and 0x16
pub fn tsc_frequency_cpuid() -> Option<hypervisor::CpuIdEntry> {
    // Safe because we pass 0 and 0 for this call and the host supports the `cpuid` instruction.
    let result = unsafe { __cpuid_count(0, 0) };
    if result.eax < 0x15 {
        return None;
    }

    let mut tsc_freq = hypervisor::CpuIdEntry {
        // 0x15 is the TSC frequency leaf.
        function: 0x15,
        index: 0,
        flags: 0,
        eax: 0,
        ebx: 0,
        ecx: 0,
        edx: 0,
    };
    // Safe because we pass 0 and 0 for this call and the host supports the `cpuid` instruction.
    unsafe {
        let result = __cpuid_count(tsc_freq.function, tsc_freq.index);
        tsc_freq.eax = result.eax;
        tsc_freq.ebx = result.ebx;
        tsc_freq.ecx = result.ecx;
        tsc_freq.edx = result.edx;
    }

    if tsc_freq.ecx != 0 {
        Some(tsc_freq)
    } else {
        // The core crystal frequency is missing. Old kernels (<5.3) don't try to derive it from the
        // CPU base clock speed. Here, we essentially implement
        // https://lore.kernel.org/patchwork/patch/1064690/ so that old kernels can calibrate TSC.
        // Safe because the host supports `cpuid` instruction.
        let cpu_clock = unsafe {
            // 0x16 is the base clock frequency leaf.
            __cpuid_count(0x16, 0)
        };
        if cpu_clock.eax > 0 {
            // Here, we assume the CPU base clock is the core crystal clock, as is done in the patch
            // that exists in 5.3+ kernels. We further assume that the core crystal clock is exactly
            // the TSC frequency. As such, we expose the base clock scaled by the _inverse_ of the
            // "tsc freq" / "core crystal clock freq" ratio. That way when the kernel extracts
            // the frequency & multiplies by the ratio, it obtains the TSC frequency.
            //
            // base_mhz = cpu_clock.eax
            // tsc_to_base_ratio = tsc_freq.eax / tsc_freq.ebx
            // crystal_hz = base_mhz * tsc_base_to_clock_ratio * 10^6
            tsc_freq.ecx = (cpu_clock.eax as f64 * tsc_freq.eax as f64 * 1_000_000_f64
                / tsc_freq.ebx as f64)
                .round() as u32;
            Some(tsc_freq)
        } else {
            None
        }
    }
}

/// Given the tsc frequency in Hz and the bus frequency in Hz, return a fake version of
/// cpuid leaf 0x15.
pub fn fake_tsc_frequency_cpuid(tsc_hz: u64, bus_hz: u32) -> hypervisor::CpuIdEntry {
    // We use 1000 for the crystal clock ratio denominator so we can preserve precision in case
    // tsc_hz is not neatly divisible by bus_hz
    let crystal_clock_ratio_denominator: u32 = 1000;
    let crystal_clock_ratio_numerator: u32 =
        (tsc_hz * crystal_clock_ratio_denominator as u64 / bus_hz as u64) as u32;

    hypervisor::CpuIdEntry {
        function: 0x15,
        index: 0,
        flags: 0,
        eax: crystal_clock_ratio_denominator,
        ebx: crystal_clock_ratio_numerator,
        ecx: bus_hz,
        edx: 0,
    }
}

/// Returns the Bus frequency in Hz, based on reading Intel-specific cpuids, or None
/// if the frequency can't be determined from cpuids.
pub fn bus_freq_hz() -> Option<u32> {
    tsc_frequency_cpuid().map(|cpuid| cpuid.ecx)
}

/// Returns the TSC frequency in Hz, based on reading Intel-specific cpuids, or None
/// if the frequency can't be determined from cpuids.
pub fn tsc_freq_hz() -> Option<u32> {
    tsc_frequency_cpuid()
        .map(|cpuid| (cpuid.ecx as u64 * cpuid.ebx as u64 / cpuid.eax as u64) as u32)
}

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

    #[test]
    // It seems that most Intel CPUs don't have any TSC frequency information in CPUID.15H.ECX. The
    // linux kernel only treats the TSC frequency as a "known" frequency if it comes from
    // CPUID.15H.ECX, and we want our TSC frequency to be "known" to prevent clock watchdogs from
    // invalidating the TSC clocksource. So we derive CPUID.15H.ECX from the values in CPUID.16H.
    // This test verifies that that derivation is working correctly.
    fn test_leaf15_derivation() {
        let crystal_clock_ratio = 88;
        let tsc_frequency_hz = 2100000000u32;

        {
            let mut cpuids = CPUIDS.lock();

            cpuids.push(hypervisor::CpuIdEntry {
                function: 0,
                index: 0,
                eax: 0x16, // highest available leaf is 0x16
                ..Default::default()
            });

            cpuids.push(hypervisor::CpuIdEntry {
                function: 0x15,
                index: 0,
                eax: 2, // eax usually contains 2, and ebx/eax is the crystal clock ratio
                ebx: crystal_clock_ratio * 2,
                ..Default::default()
            });

            cpuids.push(hypervisor::CpuIdEntry {
                function: 0x16,
                index: 0,
                eax: tsc_frequency_hz / 1_000_000_u32, // MHz frequency
                ..Default::default()
            });
        }

        // We compare the frequencies divided by the crystal_clock_ratio because that's the
        // resolution that the tsc frequency is stored at in CPUID.15H.ECX.
        assert_eq!(
            tsc_freq_hz().unwrap() / crystal_clock_ratio,
            tsc_frequency_hz / crystal_clock_ratio
        );

        CPUIDS.lock().clear();
    }
}
<|endoftext|>