<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

use futures::{self, Future, Stream, Sink};
use futures::stream::Wait;
use futures::sync::mpsc;
use tokio_core::reactor::Core;
use tokio_timer::{TimeoutStream, Timer};

use std::net::SocketAddr;
use std::thread;
use std::time::{self, Duration};

use crypto::{gen_keypair, PublicKey, Signature};
use messages::{MessageWriter, RawMessage, Connect, Message};
use events::{NetworkEvent, NetworkRequest};
use events::network::{NetworkPart, NetworkConfiguration};
use node::{NodeChannel, EventsPoolCapacity};

#[derive(Debug)]
pub struct TestHandler {
    listen_address: SocketAddr,
    network_events_rx: Wait<TimeoutStream<mpsc::Receiver<NetworkEvent>>>,
    network_requests_tx: mpsc::Sender<NetworkRequest>,
}

impl TestHandler {
    pub fn new(
        listen_address: SocketAddr,
        network_requests_tx: mpsc::Sender<NetworkRequest>,
        network_events_rx: mpsc::Receiver<NetworkEvent>,
    ) -> TestHandler {
        let timer = Timer::default();
        let receiver = timer.timeout_stream(network_events_rx, Duration::from_secs(30));
        TestHandler {
            listen_address,
            network_requests_tx,
            network_events_rx: receiver.wait(),
        }
    }

    pub fn wait_for_event(&mut self) -> Result<NetworkEvent, ()> {
        let event = self.network_events_rx.next().unwrap()?;
        Ok(event)
    }

    pub fn connect_with(&self, addr: SocketAddr) {
        let connect = connect_message(self.listen_address);
        self.network_requests_tx
            .clone()
            .send(NetworkRequest::SendMessage(addr, connect.raw().clone()))
            .wait()
            .unwrap();
    }

    pub fn disconnect_with(&self, addr: SocketAddr) {
        self.network_requests_tx
            .clone()
            .send(NetworkRequest::DisconnectWithPeer(addr))
            .wait()
            .unwrap();
    }

    pub fn send_to(&self, addr: SocketAddr, raw: RawMessage) {
        self.network_requests_tx
            .clone()
            .send(NetworkRequest::SendMessage(addr, raw))
            .wait()
            .unwrap();
    }

    pub fn wait_for_connect(&mut self) -> Connect {
        match self.wait_for_event() {
            Ok(NetworkEvent::PeerConnected(_addr, connect)) => connect,
            Ok(other) => panic!("Unexpected connect received, {:?}", other),
            Err(e) => panic!("An error occured, {:?}", e),
        }
    }

    pub fn wait_for_disconnect(&mut self) -> SocketAddr {
        match self.wait_for_event() {
            Ok(NetworkEvent::PeerDisconnected(addr)) => addr,
            Ok(other) => panic!("Unexpected disconnect received, {:?}", other),
            Err(e) => panic!("An error occured, {:?}", e),
        }
    }

    pub fn wait_for_message(&mut self) -> RawMessage {
        match self.wait_for_event() {
            Ok(NetworkEvent::MessageReceived(_addr, msg)) => msg,
            Ok(other) => panic!("Unexpected message received, {:?}", other),
            Err(e) => panic!("An error occured, {:?}", e),
        }
    }
}

impl Drop for TestHandler {
    fn drop(&mut self) {
        if !::std::thread::panicking() {
            self.network_requests_tx
                .clone()
                .send(NetworkRequest::Shutdown)
                .wait()
                .unwrap();
        }
    }
}

#[derive(Debug)]
pub struct TestEvents {
    pub listen_address: SocketAddr,
    pub network_config: NetworkConfiguration,
    pub events_config: EventsPoolCapacity,
}

struct TestHandlerPart {
    handler: TestHandler,
    core: Core,
}

impl TestEvents {
    pub fn with_addr(listen_address: SocketAddr) -> TestEvents {
        TestEvents {
            listen_address,
            network_config: NetworkConfiguration::default(),
            events_config: EventsPoolCapacity::default(),
        }
    }

    pub fn spawn<F>(self, test_fn: F) -> thread::JoinHandle<()>
    where
        F: Fn(&mut TestHandler) + 'static + Send,
    {
        thread::spawn(move || {
            let (handler_part, network_part) = self.into_reactor();
            let network_thread = thread::spawn(move || network_part.run().unwrap());

            let mut handler = handler_part.handler;

            let mut core = handler_part.core;
            let test_fut = futures::lazy(move || -> Result<(), ()> {
                test_fn(&mut handler);
                Ok(())
            });
            core.run(test_fut).unwrap();
            network_thread.join().unwrap();
        })
    }

    fn into_reactor(self) -> (TestHandlerPart, NetworkPart) {
        let channel = NodeChannel::new(self.events_config);
        let core = Core::new().unwrap();
        let network_config = self.network_config;
        let (network_tx, network_rx) = channel.network_events;
        let network_requests_tx = channel.network_requests.0.clone();

        let network_part = NetworkPart {
            listen_address: self.listen_address,
            network_config,
            network_requests: channel.network_requests,
            network_tx: network_tx.clone(),
        };

        let handler_part = TestHandlerPart {
            core,
            handler: TestHandler::new(self.listen_address, network_requests_tx, network_rx),
        };
        (handler_part, network_part)
    }
}

pub fn connect_message(addr: SocketAddr) -> Connect {
    let time = time::UNIX_EPOCH;
    Connect::new_with_signature(&PublicKey::zero(), addr, time, &Signature::zero())
}

pub fn raw_message(id: u16, len: usize) -> RawMessage {
    let writer = MessageWriter::new(
        ::messages::PROTOCOL_MAJOR_VERSION,
        ::messages::TEST_NETWORK_ID,
        0,
        id,
        len,
    );
    RawMessage::new(writer.sign(&gen_keypair().1))
}

#[test]
fn test_network_handshake() {
    let addrs: [SocketAddr; 2] =
        ["127.0.0.1:17230".parse().unwrap(), "127.0.0.1:17231".parse().unwrap()];

    let e1 = TestEvents::with_addr(addrs[0]);
    let e2 = TestEvents::with_addr(addrs[1]);

    let c1 = connect_message(addrs[0]);
    let c2 = connect_message(addrs[1]);

    let t1 = e1.spawn(move |e: &mut TestHandler| {
        e.connect_with(addrs[1]);
        assert_eq!(e.wait_for_connect(), c2);
    });
    let t2 = e2.spawn(move |e: &mut TestHandler| {
        assert_eq!(e.wait_for_connect(), c1);
        e.connect_with(addrs[0]);
        e.disconnect_with(addrs[0]);
        assert_eq!(e.wait_for_disconnect(), addrs[0]);
    });

    t1.join().unwrap();
    t2.join().unwrap();
}

#[test]
fn test_network_big_message() {
    let addrs: [SocketAddr; 2] =
        ["127.0.0.1:17200".parse().unwrap(), "127.0.0.1:17201".parse().unwrap()];

    let msg1 = raw_message(15, 100000);
    let msg2 = raw_message(16, 400);

    let e1 = TestEvents::with_addr(addrs[0]);
    let e2 = TestEvents::with_addr(addrs[1]);

    let m1 = msg1.clone();
    let m2 = msg2.clone();
    let t1 = e1.spawn(move |e: &mut TestHandler| {
        e.connect_with(addrs[1]);
        e.wait_for_connect();

        e.send_to(addrs[1], m1.clone());
        e.send_to(addrs[1], m2.clone());
        e.send_to(addrs[1], m1.clone());

        assert_eq!(e.wait_for_message(), m2);
        assert_eq!(e.wait_for_message(), m1);
        assert_eq!(e.wait_for_message(), m2);

        e.disconnect_with(addrs[1]);
        assert_eq!(e.wait_for_disconnect(), addrs[1]);
    });

    let m1 = msg1.clone();
    let m2 = msg2.clone();
    let t2 = e2.spawn(move |e: &mut TestHandler| {
        e.connect_with(addrs[0]);
        e.wait_for_connect();

        e.send_to(addrs[0], m2.clone());
        e.send_to(addrs[0], m1.clone());
        e.send_to(addrs[0], m2.clone());

        assert_eq!(e.wait_for_message(), m1);
        assert_eq!(e.wait_for_message(), m2);
        assert_eq!(e.wait_for_message(), m1);

        e.disconnect_with(addrs[0]);
        assert_eq!(e.wait_for_disconnect(), addrs[0]);
    });

    t2.join().unwrap();
    t1.join().unwrap();
}

#[test]
fn test_network_reconnect() {
    let addrs: [SocketAddr; 2] =
        ["127.0.0.1:19100".parse().unwrap(), "127.0.0.1:19101".parse().unwrap()];

    let c1 = connect_message(addrs[0]);
    let c2 = connect_message(addrs[1]);
    let t1 = TestEvents::with_addr(addrs[0]).spawn(move |e: &mut TestHandler| {
        // Handle first attempt
        e.connect_with(addrs[1]);
        assert_eq!(e.wait_for_connect(), c2);
        assert_eq!(e.wait_for_disconnect(), addrs[1]);
        // Handle second attempt
        assert_eq!(e.wait_for_connect(), c2);
        e.connect_with(addrs[1]);
        e.disconnect_with(addrs[1]);
        assert_eq!(e.wait_for_disconnect(), addrs[1]);
    });
    // First connect attempt.
    let c1_cloned = c1.clone();
    TestEvents::with_addr(addrs[1])
        .spawn(move |e: &mut TestHandler| {
            assert_eq!(e.wait_for_connect(), c1_cloned);
            e.connect_with(addrs[0]);
            e.disconnect_with(addrs[0]);
            assert_eq!(e.wait_for_disconnect(), addrs[0]);
        })
        .join()
        .unwrap();
    // Second connect attempt.
    let c1_cloned = c1.clone();
    TestEvents::with_addr(addrs[1])
        .spawn(move |e: &mut TestHandler| {
            e.connect_with(addrs[0]);
            assert_eq!(e.wait_for_connect(), c1_cloned);
            assert_eq!(e.wait_for_disconnect(), addrs[0]);
        })
        .join()
        .unwrap();
    // Wait for first server
    t1.join().unwrap();
}
<commit_msg>Fix handshake test<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

use futures::{self, Future, Stream, Sink};
use futures::stream::Wait;
use futures::sync::mpsc;
use tokio_core::reactor::Core;
use tokio_timer::{TimeoutStream, Timer};

use std::net::SocketAddr;
use std::thread;
use std::time::{self, Duration};

use crypto::{gen_keypair, PublicKey, Signature};
use messages::{MessageWriter, RawMessage, Connect, Message};
use events::{NetworkEvent, NetworkRequest};
use events::network::{NetworkPart, NetworkConfiguration};
use node::{NodeChannel, EventsPoolCapacity};

#[derive(Debug)]
pub struct TestHandler {
    listen_address: SocketAddr,
    network_events_rx: Wait<TimeoutStream<mpsc::Receiver<NetworkEvent>>>,
    network_requests_tx: mpsc::Sender<NetworkRequest>,
}

impl TestHandler {
    pub fn new(
        listen_address: SocketAddr,
        network_requests_tx: mpsc::Sender<NetworkRequest>,
        network_events_rx: mpsc::Receiver<NetworkEvent>,
    ) -> TestHandler {
        let timer = Timer::default();
        let receiver = timer.timeout_stream(network_events_rx, Duration::from_secs(30));
        TestHandler {
            listen_address,
            network_requests_tx,
            network_events_rx: receiver.wait(),
        }
    }

    pub fn wait_for_event(&mut self) -> Result<NetworkEvent, ()> {
        let event = self.network_events_rx.next().unwrap()?;
        Ok(event)
    }

    pub fn connect_with(&self, addr: SocketAddr) {
        let connect = connect_message(self.listen_address);
        self.network_requests_tx
            .clone()
            .send(NetworkRequest::SendMessage(addr, connect.raw().clone()))
            .wait()
            .unwrap();
    }

    pub fn disconnect_with(&self, addr: SocketAddr) {
        self.network_requests_tx
            .clone()
            .send(NetworkRequest::DisconnectWithPeer(addr))
            .wait()
            .unwrap();
    }

    pub fn send_to(&self, addr: SocketAddr, raw: RawMessage) {
        self.network_requests_tx
            .clone()
            .send(NetworkRequest::SendMessage(addr, raw))
            .wait()
            .unwrap();
    }

    pub fn wait_for_connect(&mut self) -> Connect {
        match self.wait_for_event() {
            Ok(NetworkEvent::PeerConnected(_addr, connect)) => connect,
            Ok(other) => panic!("Unexpected connect received, {:?}", other),
            Err(e) => panic!("An error occured, {:?}", e),
        }
    }

    pub fn wait_for_disconnect(&mut self) -> SocketAddr {
        match self.wait_for_event() {
            Ok(NetworkEvent::PeerDisconnected(addr)) => addr,
            Ok(other) => panic!("Unexpected disconnect received, {:?}", other),
            Err(e) => panic!("An error occured, {:?}", e),
        }
    }

    pub fn wait_for_message(&mut self) -> RawMessage {
        match self.wait_for_event() {
            Ok(NetworkEvent::MessageReceived(_addr, msg)) => msg,
            Ok(other) => panic!("Unexpected message received, {:?}", other),
            Err(e) => panic!("An error occured, {:?}", e),
        }
    }
}

impl Drop for TestHandler {
    fn drop(&mut self) {
        if !::std::thread::panicking() {
            self.network_requests_tx
                .clone()
                .send(NetworkRequest::Shutdown)
                .wait()
                .unwrap();
        }
    }
}

#[derive(Debug)]
pub struct TestEvents {
    pub listen_address: SocketAddr,
    pub network_config: NetworkConfiguration,
    pub events_config: EventsPoolCapacity,
}

struct TestHandlerPart {
    handler: TestHandler,
    core: Core,
}

impl TestEvents {
    pub fn with_addr(listen_address: SocketAddr) -> TestEvents {
        TestEvents {
            listen_address,
            network_config: NetworkConfiguration::default(),
            events_config: EventsPoolCapacity::default(),
        }
    }

    pub fn spawn<F>(self, test_fn: F) -> thread::JoinHandle<()>
    where
        F: Fn(&mut TestHandler) + 'static + Send,
    {
        thread::spawn(move || {
            let (handler_part, network_part) = self.into_reactor();
            let network_thread = thread::spawn(move || network_part.run().unwrap());

            let mut handler = handler_part.handler;

            let mut core = handler_part.core;
            let test_fut = futures::lazy(move || -> Result<(), ()> {
                test_fn(&mut handler);
                Ok(())
            });
            core.run(test_fut).unwrap();
            network_thread.join().unwrap();
        })
    }

    fn into_reactor(self) -> (TestHandlerPart, NetworkPart) {
        let channel = NodeChannel::new(self.events_config);
        let core = Core::new().unwrap();
        let network_config = self.network_config;
        let (network_tx, network_rx) = channel.network_events;
        let network_requests_tx = channel.network_requests.0.clone();

        let network_part = NetworkPart {
            listen_address: self.listen_address,
            network_config,
            network_requests: channel.network_requests,
            network_tx: network_tx.clone(),
        };

        let handler_part = TestHandlerPart {
            core,
            handler: TestHandler::new(self.listen_address, network_requests_tx, network_rx),
        };
        (handler_part, network_part)
    }
}

pub fn connect_message(addr: SocketAddr) -> Connect {
    let time = time::UNIX_EPOCH;
    Connect::new_with_signature(&PublicKey::zero(), addr, time, &Signature::zero())
}

pub fn raw_message(id: u16, len: usize) -> RawMessage {
    let writer = MessageWriter::new(
        ::messages::PROTOCOL_MAJOR_VERSION,
        ::messages::TEST_NETWORK_ID,
        0,
        id,
        len,
    );
    RawMessage::new(writer.sign(&gen_keypair().1))
}

#[test]
fn test_network_handshake() {
    let addrs: [SocketAddr; 2] =
        ["127.0.0.1:17230".parse().unwrap(), "127.0.0.1:17231".parse().unwrap()];

    let e1 = TestEvents::with_addr(addrs[0]);
    let e2 = TestEvents::with_addr(addrs[1]);

    let c1 = connect_message(addrs[0]);
    let c2 = connect_message(addrs[1]);

    let t1 = e1.spawn(move |e: &mut TestHandler| {
        e.connect_with(addrs[1]);
        assert_eq!(e.wait_for_connect(), c2);
        assert_eq!(e.wait_for_disconnect(), addrs[1]);
    });
    let t2 = e2.spawn(move |e: &mut TestHandler| {
        assert_eq!(e.wait_for_connect(), c1);
        e.connect_with(addrs[0]);
        e.disconnect_with(addrs[0]);
        assert_eq!(e.wait_for_disconnect(), addrs[0]);
    });

    t1.join().unwrap();
    t2.join().unwrap();
}

#[test]
fn test_network_big_message() {
    let addrs: [SocketAddr; 2] =
        ["127.0.0.1:17200".parse().unwrap(), "127.0.0.1:17201".parse().unwrap()];

    let msg1 = raw_message(15, 100000);
    let msg2 = raw_message(16, 400);

    let e1 = TestEvents::with_addr(addrs[0]);
    let e2 = TestEvents::with_addr(addrs[1]);

    let m1 = msg1.clone();
    let m2 = msg2.clone();
    let t1 = e1.spawn(move |e: &mut TestHandler| {
        e.connect_with(addrs[1]);
        e.wait_for_connect();

        e.send_to(addrs[1], m1.clone());
        e.send_to(addrs[1], m2.clone());
        e.send_to(addrs[1], m1.clone());

        assert_eq!(e.wait_for_message(), m2);
        assert_eq!(e.wait_for_message(), m1);
        assert_eq!(e.wait_for_message(), m2);

        e.disconnect_with(addrs[1]);
        assert_eq!(e.wait_for_disconnect(), addrs[1]);
    });

    let m1 = msg1.clone();
    let m2 = msg2.clone();
    let t2 = e2.spawn(move |e: &mut TestHandler| {
        e.connect_with(addrs[0]);
        e.wait_for_connect();

        e.send_to(addrs[0], m2.clone());
        e.send_to(addrs[0], m1.clone());
        e.send_to(addrs[0], m2.clone());

        assert_eq!(e.wait_for_message(), m1);
        assert_eq!(e.wait_for_message(), m2);
        assert_eq!(e.wait_for_message(), m1);

        e.disconnect_with(addrs[0]);
        assert_eq!(e.wait_for_disconnect(), addrs[0]);
    });

    t2.join().unwrap();
    t1.join().unwrap();
}

#[test]
fn test_network_reconnect() {
    let addrs: [SocketAddr; 2] =
        ["127.0.0.1:19100".parse().unwrap(), "127.0.0.1:19101".parse().unwrap()];

    let c1 = connect_message(addrs[0]);
    let c2 = connect_message(addrs[1]);
    let t1 = TestEvents::with_addr(addrs[0]).spawn(move |e: &mut TestHandler| {
        // Handle first attempt
        e.connect_with(addrs[1]);
        assert_eq!(e.wait_for_connect(), c2);
        assert_eq!(e.wait_for_disconnect(), addrs[1]);
        // Handle second attempt
        assert_eq!(e.wait_for_connect(), c2);
        e.connect_with(addrs[1]);
        e.disconnect_with(addrs[1]);
        assert_eq!(e.wait_for_disconnect(), addrs[1]);
    });
    // First connect attempt.
    let c1_cloned = c1.clone();
    TestEvents::with_addr(addrs[1])
        .spawn(move |e: &mut TestHandler| {
            assert_eq!(e.wait_for_connect(), c1_cloned);
            e.connect_with(addrs[0]);
            e.disconnect_with(addrs[0]);
            assert_eq!(e.wait_for_disconnect(), addrs[0]);
        })
        .join()
        .unwrap();
    // Second connect attempt.
    let c1_cloned = c1.clone();
    TestEvents::with_addr(addrs[1])
        .spawn(move |e: &mut TestHandler| {
            e.connect_with(addrs[0]);
            assert_eq!(e.wait_for_connect(), c1_cloned);
            assert_eq!(e.wait_for_disconnect(), addrs[0]);
        })
        .join()
        .unwrap();
    // Wait for first server
    t1.join().unwrap();
}
<|endoftext|>


<commit_before>use std::iter;
use super::{StackOfStrings, Stack};

const INITIAL_STACK_CAPACITY: usize = 1;

pub struct ResizingArrayStackOfStrings {
    s: Vec<Option<String>>,
    n: usize
}

impl ResizingArrayStackOfStrings {
    pub fn with_capacity(capacity: usize) -> ResizingArrayStackOfStrings {
        let storage = iter::repeat(None).take(capacity).collect();

        ResizingArrayStackOfStrings {
            s: storage,
            n: 0
        }
    }

    fn resize(&mut self, capacity: usize) {
        let mut new_storage: Vec<Option<String>> = iter::repeat(None).take(capacity).collect();
        for i in 0 .. self.n {
            new_storage[i] = self.s[i].take();
        }
        self.s = new_storage;
    }
}

impl StackOfStrings for ResizingArrayStackOfStrings {
    fn new() -> ResizingArrayStackOfStrings {
        ResizingArrayStackOfStrings::with_capacity(INITIAL_STACK_CAPACITY)
    }

    fn is_empty(&self) -> bool {
        self.n == 0
    }

    fn push(&mut self, item: String) {
        let len = self.s.len();
        if self.n == len {
            self.resize(2 * len);
        }
        self.s[self.n] = Some(item);
        self.n += 1;
    }

    fn pop(&mut self) -> String {
        self.n -= 1;
        let cell = self.s[self.n].take();
        let len = self.s.len();
        if self.n > 0 && self.n == len / 4 {
            self.resize(len / 2);
        }
        cell.unwrap()
    }
}

pub struct ResizingArrayStack<T> {
    s: Vec<Option<T>>,
    n: usize
}

impl<T> ResizingArrayStack<T> {
    pub fn with_capacity(capacity: usize) -> ResizingArrayStack<T> {
        let mut storage = Vec::with_capacity(capacity);
        for _ in 0 .. capacity {
            storage.push(None);
        }

        ResizingArrayStack {
            s: storage,
            n: 0
        }
    }

    fn resize(&mut self, capacity: usize) {
        let mut new_storage = Vec::with_capacity(capacity);
        for i in 0 .. capacity {
            if i < self.n {
                new_storage.push(self.s[i].take())
            } else {
                new_storage.push(None);
            }
        }
        self.s = new_storage;
    }
}

impl<T> Stack<T> for ResizingArrayStack<T> {
    fn new() -> ResizingArrayStack<T> {
        ResizingArrayStack::with_capacity(INITIAL_STACK_CAPACITY)
    }

    fn is_empty(&self) -> bool {
        self.n == 0
    }

    fn push(&mut self, item: T) {
        let len = self.s.len();
        if self.n == len {
            self.resize(2 * len);
        }
        self.s[self.n] = Some(item);
        self.n += 1;
    }

    fn pop(&mut self) -> T {
        self.n -= 1;
        let cell = self.s[self.n].take();
        let len = self.s.len();
        if self.n > 0 && self.n == len / 4 {
            self.resize(len / 2);
        }
        cell.unwrap()
    }
}

#[test]
fn test_resizing_array_stack_of_strings() {
    let mut stack: ResizingArrayStackOfStrings = StackOfStrings::new();

    let mut result = "to be not that or be".split(' ');

    for s in "to be or not to - be - - that - - - is".split(' ') {
        if s == "-" {
            assert_eq!(&stack.pop(), result.next().unwrap())
        } else {
            stack.push(s.into())
        }
    }
}

#[test]
fn test_resizing_array_stack() {
    let mut stack: ResizingArrayStack<i32> = Stack::new();

    let result = [1, 3, 4, 3, 5, 3];
    let mut rit = result.iter();

    for s in vec![1, 3, 5, 4, 1, 0, 3, 0, 0, 3, 0, 0, 0, 4] {
        if s == 0 {
            assert_eq!(&stack.pop(), rit.next().unwrap())
        } else {
            stack.push(s)
        }
    }

}
<commit_msg>stacks_and_queues: impl Iterator for ResizingArrayStack<commit_after>use std::iter;
use std::iter::Iterator;
use std::marker::PhantomData;
use super::{StackOfStrings, Stack};

const INITIAL_STACK_CAPACITY: usize = 1;

pub struct ResizingArrayStackOfStrings {
    s: Vec<Option<String>>,
    n: usize
}

impl ResizingArrayStackOfStrings {
    pub fn with_capacity(capacity: usize) -> ResizingArrayStackOfStrings {
        let storage = iter::repeat(None).take(capacity).collect();

        ResizingArrayStackOfStrings {
            s: storage,
            n: 0
        }
    }

    fn resize(&mut self, capacity: usize) {
        let mut new_storage: Vec<Option<String>> = iter::repeat(None).take(capacity).collect();
        for i in 0 .. self.n {
            new_storage[i] = self.s[i].take();
        }
        self.s = new_storage;
    }
}

impl StackOfStrings for ResizingArrayStackOfStrings {
    fn new() -> ResizingArrayStackOfStrings {
        ResizingArrayStackOfStrings::with_capacity(INITIAL_STACK_CAPACITY)
    }

    fn is_empty(&self) -> bool {
        self.n == 0
    }

    fn push(&mut self, item: String) {
        let len = self.s.len();
        if self.n == len {
            self.resize(2 * len);
        }
        self.s[self.n] = Some(item);
        self.n += 1;
    }

    fn pop(&mut self) -> String {
        self.n -= 1;
        let cell = self.s[self.n].take();
        let len = self.s.len();
        if self.n > 0 && self.n == len / 4 {
            self.resize(len / 2);
        }
        cell.unwrap()
    }
}

pub struct ResizingArrayStack<T> {
    s: Vec<Option<T>>,
    n: usize
}

impl<T> ResizingArrayStack<T> {
    pub fn with_capacity(capacity: usize) -> ResizingArrayStack<T> {
        let mut storage = Vec::with_capacity(capacity);
        for _ in 0 .. capacity {
            storage.push(None);
        }

        ResizingArrayStack {
            s: storage,
            n: 0
        }
    }

    fn resize(&mut self, capacity: usize) {
        let mut new_storage = Vec::with_capacity(capacity);
        for i in 0 .. capacity {
            if i < self.n {
                new_storage.push(self.s[i].take())
            } else {
                new_storage.push(None);
            }
        }
        self.s = new_storage;
    }
}

impl<T> Stack<T> for ResizingArrayStack<T> {
    fn new() -> ResizingArrayStack<T> {
        ResizingArrayStack::with_capacity(INITIAL_STACK_CAPACITY)
    }

    fn is_empty(&self) -> bool {
        self.n == 0
    }

    fn push(&mut self, item: T) {
        let len = self.s.len();
        if self.n == len {
            self.resize(2 * len);
        }
        self.s[self.n] = Some(item);
        self.n += 1;
    }

    fn pop(&mut self) -> T {
        self.n -= 1;
        let cell = self.s[self.n].take();
        let len = self.s.len();
        if self.n > 0 && self.n == len / 4 {
            self.resize(len / 2);
        }
        cell.unwrap()
    }
}

pub struct Iter<'a, T: 'a> {
    ptr: *const Option<T>,
    end: *const Option<T>,
    _marker: PhantomData<&'a T>
}

unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {}
unsafe impl<'a, T: Sync> Send for Iter<'a, T> {}

// FIXME: maybe error with zero-sized type
impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        unsafe {
            if self.ptr < self.end {
                None
            } else {
                self.ptr = self.ptr.offset(-1);
                (*self.ptr).as_ref()
            }
        }
    }
}

impl<'a, T> ResizingArrayStack<T> {
    pub fn iter(&'a self) -> Iter<'a, T> {
        Iter {
            // first empty
            ptr: &self.s[self.n],
            end: &self.s[0],
            _marker: PhantomData
        }
    }
}

#[test]
fn test_resizing_array_stack_of_strings() {
    let mut stack: ResizingArrayStackOfStrings = StackOfStrings::new();

    let mut result = "to be not that or be".split(' ');

    for s in "to be or not to - be - - that - - - is".split(' ') {
        if s == "-" {
            assert_eq!(&stack.pop(), result.next().unwrap())
        } else {
            stack.push(s.into())
        }
    }
}

#[test]
fn test_resizing_array_stack() {
    let mut stack: ResizingArrayStack<i32> = Stack::new();

    let result = [1, 3, 4, 3, 5, 3];
    let mut rit = result.iter();

    for s in vec![1, 3, 5, 4, 1, 0, 3, 0, 0, 3, 0, 0, 0, 4] {
        if s == 0 {
            assert_eq!(&stack.pop(), rit.next().unwrap())
        } else {
            stack.push(s)
        }
    }

}

#[test]
fn test_resizing_array_stack_iter() {
    let mut stack: ResizingArrayStack<i32> = Stack::new();

    let result = [3, 3, 1];
    let mut rit = result.iter();

    for s in vec![1, 3, 5, 0, 1, 0, 3] {
        if s == 0 {
            stack.pop();
        } else {
            stack.push(s);
        }
    }

    for v in stack.iter() {
        println!("v => {:?}", v);
        assert_eq!(v, rit.next().unwrap())
    }
}

#[test]
fn test_resizing_array_stack_iter_string() {
    let mut stack: ResizingArrayStack<String> = Stack::new();

    let mut result = "is that or be to".split(' ');

    for s in "to be or not to - be - - that is".split(' ') {
        if s == "-" {
            stack.pop();
        } else {
            stack.push(s.into());
        }
    }

    for v in stack.iter() {
        assert_eq!(v, result.next().unwrap())
    }
}
<|endoftext|>


<commit_before>use core::mem;
use goblin::elf::sym;

use crate::paging::{ActivePageTable, PageTableType, VirtualAddress};

/// Get a stack trace
//TODO: Check for stack being mapped before dereferencing
#[inline(never)]
pub unsafe fn stack_trace() {
    let mut fp: usize;
    llvm_asm!("" : "={fp}"(fp) : : : "volatile");

    println!("TRACE: {:>016x}", fp);
    //Maximum 64 frames
    let active_table = ActivePageTable::new(PageTableType::User);
    for _frame in 0..64 {
        if let Some(pc_fp) = fp.checked_add(mem::size_of::<usize>()) {
            if active_table.translate(VirtualAddress::new(fp)).is_some() && active_table.translate(VirtualAddress::new(pc_fp)).is_some() {
                let pc = *(pc_fp as *const usize);
                if pc == 0 {
                    println!(" {:>016x}: EMPTY RETURN", fp);
                    break;
                }
                println!("  {:>016x}: {:>016x}", fp, pc);
                fp = *(fp as *const usize);
//                symbol_trace(pc);
            } else {
                println!("  {:>016x}: GUARD PAGE", fp);
                break;
            }
        } else {
            println!("  {:>016x}: fp OVERFLOW", fp);
        }
    }
}
///
/// Get a symbol
//TODO: Do not create Elf object for every symbol lookup
#[inline(never)]
pub unsafe fn symbol_trace(addr: usize) {
    use core::slice;
    use core::sync::atomic::Ordering;

    use crate::elf::Elf;
    use crate::start::{KERNEL_BASE, KERNEL_SIZE};

    let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + crate::KERNEL_OFFSET) as *const u8;
    let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));

    println!("symbol_trace: 0, kernel_ptr = 0x{:x}", kernel_ptr as usize);

    match Elf::from(kernel_slice) {
        Ok(elf) => {
            println!("symbol_trace: 1");
            let mut strtab_opt = None;
            for section in elf.sections() {
                if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB {
                    strtab_opt = Some(section);
                    break;
                }
            }

            println!("symbol_trace: 2");

            if let Some(symbols) = elf.symbols() {
                println!("symbol_trace: 3");
                for sym in symbols {
                    if sym::st_type(sym.st_info) == sym::STT_FUNC
                        && addr >= sym.st_value as usize
                            && addr < (sym.st_value + sym.st_size) as usize
                            {
                                println!("    {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize);

                                if let Some(strtab) = strtab_opt {
                                    let start = strtab.sh_offset as usize + sym.st_name as usize;
                                    let mut end = start;
                                    while end < elf.data.len() {
                                        let b = elf.data[end];
                                        end += 1;
                                        if b == 0 {
                                            break;
                                        }
                                    }

                                    if end > start {
                                        let sym_name = &elf.data[start .. end];

                                        print!("    ");

                                        if sym_name.starts_with(b"_ZN") {
                                            // Skip _ZN
                                            let mut i = 3;
                                            let mut first = true;
                                            while i < sym_name.len() {
                                                // E is the end character
                                                if sym_name[i] == b'E' {
                                                    break;
                                                }

                                                // Parse length string
                                                let mut len = 0;
                                                while i < sym_name.len() {
                                                    let b = sym_name[i];
                                                    if b >= b'0' && b <= b'9' {
                                                        i += 1;
                                                        len *= 10;
                                                        len += (b - b'0') as usize;
                                                    } else {
                                                        break;
                                                    }
                                                }

                                                // Print namespace seperator, if required
                                                if first {
                                                    first = false;
                                                } else {
                                                    print!("::");
                                                }

                                                // Print name string
                                                let end = i + len;
                                                while i < sym_name.len() && i < end {
                                                    print!("{}", sym_name[i] as char);
                                                    i += 1;
                                                }
                                            }
                                        } else {
                                            for &b in sym_name.iter() {
                                                print!("{}", b as char);
                                            }
                                        }

                                        println!("");
                                    }
                                }
                            }
                }
            }
        },
        Err(_e) => {
            println!("WTF ?");
        }
    }
}
<commit_msg>Fix unwrapping stack when there are kernel addresses (and there always are)<commit_after>use core::mem;
use goblin::elf::sym;

use crate::paging::{ActivePageTable, PageTableType, VirtualAddress};

/// Get a stack trace
//TODO: Check for stack being mapped before dereferencing
#[inline(never)]
pub unsafe fn stack_trace() {
    let mut fp: usize;
    llvm_asm!("" : "={fp}"(fp) : : : "volatile");

    println!("TRACE: {:>016x}", fp);
    //Maximum 64 frames
    let active_ktable = ActivePageTable::new(PageTableType::Kernel);
    let active_utable = ActivePageTable::new(PageTableType::User);
    let in_kernel_or_user_table = |ptr| {
        active_ktable.translate(VirtualAddress::new(ptr)).is_some() ||
        active_utable.translate(VirtualAddress::new(ptr)).is_some()
    };
    for _frame in 0..64 {
        if let Some(pc_fp) = fp.checked_add(mem::size_of::<usize>()) {
            if in_kernel_or_user_table(fp) && in_kernel_or_user_table(pc_fp) {
                let pc = *(pc_fp as *const usize);
                if pc == 0 {
                    println!(" {:>016x}: EMPTY RETURN", fp);
                    break;
                }
                println!("  FP {:>016x}: PC {:>016x}", fp, pc);
                fp = *(fp as *const usize);
                //TODO symbol_trace(pc);
            } else {
                println!("  {:>016x}: GUARD PAGE", fp);
                break;
            }
        } else {
            println!("  {:>016x}: fp OVERFLOW", fp);
        }
    }
}
///
/// Get a symbol
//TODO: Do not create Elf object for every symbol lookup
#[inline(never)]
pub unsafe fn symbol_trace(addr: usize) {
    use core::slice;
    use core::sync::atomic::Ordering;

    use crate::elf::Elf;
    use crate::start::{KERNEL_BASE, KERNEL_SIZE};

    let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + crate::KERNEL_OFFSET) as *const u8;
    let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));

    println!("symbol_trace: 0, kernel_ptr = 0x{:x}", kernel_ptr as usize);

    match Elf::from(kernel_slice) {
        Ok(elf) => {
            println!("symbol_trace: 1");
            let mut strtab_opt = None;
            for section in elf.sections() {
                if section.sh_type == ::goblin::elf::section_header::SHT_STRTAB {
                    strtab_opt = Some(section);
                    break;
                }
            }

            println!("symbol_trace: 2");

            if let Some(symbols) = elf.symbols() {
                println!("symbol_trace: 3");
                for sym in symbols {
                    if sym::st_type(sym.st_info) == sym::STT_FUNC
                        && addr >= sym.st_value as usize
                            && addr < (sym.st_value + sym.st_size) as usize
                            {
                                println!("    {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize);

                                if let Some(strtab) = strtab_opt {
                                    let start = strtab.sh_offset as usize + sym.st_name as usize;
                                    let mut end = start;
                                    while end < elf.data.len() {
                                        let b = elf.data[end];
                                        end += 1;
                                        if b == 0 {
                                            break;
                                        }
                                    }

                                    if end > start {
                                        let sym_name = &elf.data[start .. end];

                                        print!("    ");

                                        if sym_name.starts_with(b"_ZN") {
                                            // Skip _ZN
                                            let mut i = 3;
                                            let mut first = true;
                                            while i < sym_name.len() {
                                                // E is the end character
                                                if sym_name[i] == b'E' {
                                                    break;
                                                }

                                                // Parse length string
                                                let mut len = 0;
                                                while i < sym_name.len() {
                                                    let b = sym_name[i];
                                                    if b >= b'0' && b <= b'9' {
                                                        i += 1;
                                                        len *= 10;
                                                        len += (b - b'0') as usize;
                                                    } else {
                                                        break;
                                                    }
                                                }

                                                // Print namespace seperator, if required
                                                if first {
                                                    first = false;
                                                } else {
                                                    print!("::");
                                                }

                                                // Print name string
                                                let end = i + len;
                                                while i < sym_name.len() && i < end {
                                                    print!("{}", sym_name[i] as char);
                                                    i += 1;
                                                }
                                            }
                                        } else {
                                            for &b in sym_name.iter() {
                                                print!("{}", b as char);
                                            }
                                        }

                                        println!("");
                                    }
                                }
                            }
                }
            }
        },
        Err(_e) => {
            println!("WTF ?");
        }
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for using the `x86` and `x86_64` segmentation hardware.
//!
//! For more information, refer to the _Intel® 64 and IA-32 Architectures
//! Software Developer’s Manual_, Vol. 3A, section 3.2, "Using Segments".
//! Some of the documentation present in this module was taken from the Intel
//! manual.
use core::{fmt, mem};

/// Represents an x86 privilege level.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
#[repr(u16)]
pub enum PrivilegeLevel { /// Ring 0 is the most privileged ring
                          KernelMode = 0
                        , Ring1 = 1
                        , Ring2 = 2
                        , /// Ring 3 is the least privileged ring
                          UserMode = 3

}

bitflags! {
    /// A segment selector is a 16-bit identifier for a segment.
    ///
    /// It does not point directly to the segment, but instead points to the
    /// segment descriptor that defines the segment.
    ///
    /// A segment selector contains the following items:
    ///     - *Requested Privilege Level (RPL)*: bits 0 and 1.
    ///       Specifies the privelege level of the selector.
    ///     - *Table Indicator*: bit 2. Specifies which descriptor table to use.
    ///     - *Index*: bits 3 through 15. Selects one of 8192 descriptors in the
    ///       GDT or LDT. The processor multiplies the index value by 8 (the number
    ///       of bytes in a segment descriptor) and adds the result to the base
    ///       address of the GDT or LDT (from the GDTR or LDTR register,
    ///       respectively).
    pub flags Selector: u16 { const RPL_RING_0 = 0b00
                            , const RPL_RING_1 = 0b01
                            , const RPL_RING_2 = 0b10
                            , const RPL_RING_3 = 0b11

                            , /// Requested Prrivelege Level (RPL)
                              const RPL = RPL_RING_0.bits
                               | RPL_RING_1.bits
                               | RPL_RING_2.bits
                               | RPL_RING_3.bits

                            , /// If the Table Indicator (TI) is 0, use the GDT
                              const TI_GDT = 0 << 3

                            , /// If the TI is 1, use the LDT
                              const TI_LDT = 1 << 3
                            }
}

impl Selector {
    /// Create a new `Selector`
    ///
    /// # Arguments:
    ///   - `index`: the index in the GDT or LDT
    pub const fn new(index: u16) -> Self {
        Selector { bits: index << 3 }
    }

    /// Create a new `Selector` from raw bits
    pub const fn from_raw(bits: u16) -> Self {
        Selector { bits: bits }
    }

    /// Extracts the index from a segment selector
    #[inline] pub fn index(&self) -> u16 {
        self.bits >> 3
    }

    /// Sets this segment selector to be a GDT segment.
    ///
    /// If the segment is already a GDT segment, this will quietly do nothing.
    #[inline] pub fn set_global(&mut self) -> &mut Self {
        self.remove(TI_LDT);
        self
    }

    /// Sets this segment selector to be an LDT segment.
    ///
    /// If the segment is already an LDT segment, this will quietly do nothing.
    #[inline] pub fn set_local(&mut self) -> &mut Self {
        self.insert(TI_GDT);
        self
    }

    /// Sets the Requested Priveliege Level (RPL)
    ///
    /// The RPL must be in the range between 0 and 3.
    #[inline] pub fn set_rpl(&mut self, rpl: PrivilegeLevel) -> &mut Self {
        self.bits &= rpl as u16;
        self
    }

    /// Checks the segment's privelige.
    #[inline] pub fn get_rpl(&self) -> PrivilegeLevel {
        unsafe { mem::transmute(*self & RPL) }
    }

    /// Load this selector into the stack segment register.
    pub unsafe fn load_ss(&self) {
        asm!(  "mov ss, $0"
            :: "r"(self.bits)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the data segment register.
    pub unsafe fn load_ds(&self) {
        asm!(  "mov ds, $0"
            :: "r"(self.bits)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the es segment register.
    pub unsafe fn load_es(&self) {
        asm!(  "mov es, $0"
            :: "r"(self.bits)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the fs segment register.
    pub unsafe fn load_fs(&self) {
        asm!(  "mov fs, $0"
            :: "r"(self.bits)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the gs segment register.
    pub unsafe fn load_gs(&self) {
        asm!(  "mov gs, $0"
            :: "r"(self.bits)
            :  "memory"
            :  "intel");
    }
}

impl fmt::Display for Selector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: this could be much less ugly.
        let ring = if self.contains(RPL_RING_3) { "3" }
                   else if self.contains(RPL_RING_2) { "2" }
                   else if self.contains(RPL_RING_1) { "1" }
                   else if self.contains(RPL_RING_0) { "0" }
                   else { unreachable!() };
        let table = if self.contains(TI_GDT) { "GDT" }
                    else { "LDT" };
        write!(f, "Index {} in {} at Ring {}", self.index(), table, ring)
    }
}

#[cfg(target_arch = "x86_64")]
#[path = "descr64.rs"] pub mod descriptor;

pub use self::descriptor::Descriptor;
<commit_msg>[x86_all] Segment selectors can be loaded to and from cs<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for using the `x86` and `x86_64` segmentation hardware.
//!
//! For more information, refer to the _Intel® 64 and IA-32 Architectures
//! Software Developer’s Manual_, Vol. 3A, section 3.2, "Using Segments".
//! Some of the documentation present in this module was taken from the Intel
//! manual.
use core::{fmt, mem};

/// Represents an x86 privilege level.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
#[repr(u16)]
pub enum PrivilegeLevel { /// Ring 0 is the most privileged ring
                          KernelMode = 0
                        , Ring1 = 1
                        , Ring2 = 2
                        , /// Ring 3 is the least privileged ring
                          UserMode = 3

}

bitflags! {
    /// A segment selector is a 16-bit identifier for a segment.
    ///
    /// It does not point directly to the segment, but instead points to the
    /// segment descriptor that defines the segment.
    ///
    /// A segment selector contains the following items:
    ///     - *Requested Privilege Level (RPL)*: bits 0 and 1.
    ///       Specifies the privelege level of the selector.
    ///     - *Table Indicator*: bit 2. Specifies which descriptor table to use.
    ///     - *Index*: bits 3 through 15. Selects one of 8192 descriptors in the
    ///       GDT or LDT. The processor multiplies the index value by 8 (the number
    ///       of bytes in a segment descriptor) and adds the result to the base
    ///       address of the GDT or LDT (from the GDTR or LDTR register,
    ///       respectively).
    pub flags Selector: u16 { const RPL_RING_0 = 0b00
                            , const RPL_RING_1 = 0b01
                            , const RPL_RING_2 = 0b10
                            , const RPL_RING_3 = 0b11

                            , /// Requested Prrivelege Level (RPL)
                              const RPL = RPL_RING_0.bits
                               | RPL_RING_1.bits
                               | RPL_RING_2.bits
                               | RPL_RING_3.bits

                            , /// If the Table Indicator (TI) is 0, use the GDT
                              const TI_GDT = 0 << 3

                            , /// If the TI is 1, use the LDT
                              const TI_LDT = 1 << 3
                            }
}

impl Selector {
    /// Create a new `Selector`
    ///
    /// # Arguments:
    ///   - `index`: the index in the GDT or LDT
    pub const fn new(index: u16) -> Self {
        Selector { bits: index << 3 }
    }

    /// Create a new `Selector` from raw bits
    pub const fn from_raw(bits: u16) -> Self {
        Selector { bits: bits }
    }

    /// Returns the current value of the code segment register.
    pub fn from_cs() -> Self {
        let cs: u16;
        unsafe {
            asm!( "mov $0, cs"
                : "=r"(cs)
                ::: "intel" )
        };
        Selector::from_bits_truncate(cs)
    }

    /// Extracts the index from a segment selector
    #[inline] pub fn index(&self) -> u16 {
        self.bits >> 3
    }

    /// Sets this segment selector to be a GDT segment.
    ///
    /// If the segment is already a GDT segment, this will quietly do nothing.
    #[inline] pub fn set_global(&mut self) -> &mut Self {
        self.remove(TI_LDT);
        self
    }

    /// Sets this segment selector to be an LDT segment.
    ///
    /// If the segment is already an LDT segment, this will quietly do nothing.
    #[inline] pub fn set_local(&mut self) -> &mut Self {
        self.insert(TI_GDT);
        self
    }

    /// Sets the Requested Priveliege Level (RPL)
    ///
    /// The RPL must be in the range between 0 and 3.
    #[inline] pub fn set_rpl(&mut self, rpl: PrivilegeLevel) -> &mut Self {
        self.bits &= rpl as u16;
        self
    }

    /// Checks the segment's privelige.
    #[inline] pub fn get_rpl(&self) -> PrivilegeLevel {
        unsafe { mem::transmute(*self & RPL) }
    }

    /// Load this selector into the stack segment register (`ss`).
    pub unsafe fn load_ss(&self) {
        asm!(  "mov ss, $0"
            :: "r"(*self)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the data segment register (`ds`).
    pub unsafe fn load_ds(&self) {
        asm!(  "mov ds, $0"
            :: "r"(*self)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the `es` segment register.
    pub unsafe fn load_es(&self) {
        asm!(  "mov es, $0"
            :: "r"(*self)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the `fs` segment register.
    pub unsafe fn load_fs(&self) {
        asm!(  "mov fs, $0"
            :: "r"(*self)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the `gs` segment register.
    pub unsafe fn load_gs(&self) {
        asm!(  "mov gs, $0"
            :: "r"(*self)
            :  "memory"
            :  "intel");
    }

    /// Load this selector into the code segment register.
    ///
    /// N.B. that as we cannot `mov` directly to `cs`, we have to do this
    /// differently. We push the selector and return value onto the stack,
    /// and use `lret` to reload `cs`.
    #[cfg(target_arch = "x86_64")]
    pub unsafe fn load_cs(&self) {
        asm!(  "push $0
                lea rax, [rip + 1]
                push rax
                iret
                1:"
            :: "r"(self.bits as u64)
            :  "{rax}", "memory"
            :  "intel");
    }

}

impl fmt::Display for Selector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: this could be much less ugly.
        let ring = if self.contains(RPL_RING_3) { "3" }
                   else if self.contains(RPL_RING_2) { "2" }
                   else if self.contains(RPL_RING_1) { "1" }
                   else if self.contains(RPL_RING_0) { "0" }
                   else { unreachable!() };
        let table = if self.contains(TI_GDT) { "GDT" }
                    else { "LDT" };
        write!(f, "Index {} in {} at Ring {}", self.index(), table, ring)
    }
}

#[cfg(target_arch = "x86_64")]
#[path = "descr64.rs"] pub mod descriptor;

pub use self::descriptor::Descriptor;
<|endoftext|>


<commit_before>pub type boolean_t = ::c_int;

pub const CLOCK_UPTIME_RAW: ::clockid_t = 8;

s! {
    pub struct malloc_zone_t {
        __private: [::uintptr_t; 18], // FIXME: needs arm64 auth pointers support
    }
}

cfg_if! {
    if #[cfg(libc_align)] {
        mod align;
        pub use self::align::*;
    }
}
<commit_msg>Fix style issue<commit_after>pub type boolean_t = ::c_int;

s! {
    pub struct malloc_zone_t {
        __private: [::uintptr_t; 18], // FIXME: needs arm64 auth pointers support
    }
}

pub const CLOCK_UPTIME_RAW: ::clockid_t = 8;

cfg_if! {
    if #[cfg(libc_align)] {
        mod align;
        pub use self::align::*;
    }
}
<|endoftext|>


<commit_before>use hir::{HasSource, InFile};
use ide_db::assists::{AssistId, AssistKind};
use syntax::{
    ast::{self, edit::IndentLevel},
    AstNode, TextSize,
};

use crate::assist_context::{AssistContext, Assists};

// Assist: generate_enum_variant
//
// Adds a variant to an enum.
//
// ```
// enum Countries {
//     Ghana,
// }
//
// fn main() {
//     let country = Countries::Lesotho$0;
// }
// ```
// ->
// ```
// enum Countries {
//     Ghana,
//     Lesotho,
// }
//
// fn main() {
//     let country = Countries::Lesotho;
// }
// ```
pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
    let path = path_expr.path()?;

    if ctx.sema.resolve_path(&path).is_some() {
        // No need to generate anything if the path resolves
        return None;
    }

    let name_ref = path.segment()?.name_ref()?;
    if name_ref.text().starts_with(char::is_lowercase) {
        // Don't suggest generating variant if the name starts with a lowercase letter
        return None;
    }

    if let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e)))) =
        ctx.sema.resolve_path(&path.qualifier()?)
    {
        let target = path.syntax().text_range();
        return add_variant_to_accumulator(acc, ctx, target, e, &name_ref);
    }

    None
}

fn add_variant_to_accumulator(
    acc: &mut Assists,
    ctx: &AssistContext<'_>,
    target: syntax::TextRange,
    adt: hir::Enum,
    name_ref: &ast::NameRef,
) -> Option<()> {
    let db = ctx.db();
    let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?;
    let enum_indent = IndentLevel::from_node(&enum_node.syntax());

    let variant_list = enum_node.variant_list()?;
    let offset = variant_list.syntax().text_range().end() - TextSize::of('}');
    let empty_enum = variant_list.variants().next().is_none();

    acc.add(
        AssistId("generate_enum_variant", AssistKind::Generate),
        "Generate variant",
        target,
        |builder| {
            builder.edit_file(file_id.original_file(db));
            let text = format!(
                "{maybe_newline}{indent_1}{name},\n{enum_indent}",
                maybe_newline = if empty_enum { "\n" } else { "" },
                indent_1 = IndentLevel(1),
                name = name_ref,
                enum_indent = enum_indent
            );
            builder.insert(offset, text)
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn generate_basic_enum_variant_in_empty_enum() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::Bar$0
}
",
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Bar
}
",
        )
    }

    #[test]
    fn generate_basic_enum_variant_in_non_empty_enum() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Baz$0
}
",
            r"
enum Foo {
    Bar,
    Baz,
}
fn main() {
    Foo::Baz
}
",
        )
    }

    #[test]
    fn generate_basic_enum_variant_in_different_file() {
        check_assist(
            generate_enum_variant,
            r"
//- /main.rs
mod foo;
use foo::Foo;

fn main() {
    Foo::Baz$0
}

//- /foo.rs
enum Foo {
    Bar,
}
",
            r"
enum Foo {
    Bar,
    Baz,
}
",
        )
    }

    #[test]
    fn not_applicable_for_existing_variant() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Bar$0
}
",
        )
    }

    #[test]
    fn not_applicable_for_lowercase() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::new$0
}
",
        )
    }

    #[test]
    fn indentation_level_is_correct() {
        check_assist(
            generate_enum_variant,
            r"
mod m {
    enum Foo {
        Bar,
    }
}
fn main() {
    m::Foo::Baz$0
}
",
            r"
mod m {
    enum Foo {
        Bar,
        Baz,
    }
}
fn main() {
    m::Foo::Baz
}
",
        )
    }
}
<commit_msg>convert generate_enum_variant to use add_variant<commit_after>use hir::{HasSource, InFile};
use ide_db::assists::{AssistId, AssistKind};
use syntax::{
    ast::{self, make},
    AstNode,
};

use crate::assist_context::{AssistContext, Assists};

// Assist: generate_enum_variant
//
// Adds a variant to an enum.
//
// ```
// enum Countries {
//     Ghana,
// }
//
// fn main() {
//     let country = Countries::Lesotho$0;
// }
// ```
// ->
// ```
// enum Countries {
//     Ghana,
//     Lesotho,
// }
//
// fn main() {
//     let country = Countries::Lesotho;
// }
// ```
pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
    let path = path_expr.path()?;

    if ctx.sema.resolve_path(&path).is_some() {
        // No need to generate anything if the path resolves
        return None;
    }

    let name_ref = path.segment()?.name_ref()?;
    if name_ref.text().starts_with(char::is_lowercase) {
        // Don't suggest generating variant if the name starts with a lowercase letter
        return None;
    }

    if let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e)))) =
        ctx.sema.resolve_path(&path.qualifier()?)
    {
        let target = path.syntax().text_range();
        return add_variant_to_accumulator(acc, ctx, target, e, &name_ref);
    }

    None
}

fn add_variant_to_accumulator(
    acc: &mut Assists,
    ctx: &AssistContext<'_>,
    target: syntax::TextRange,
    adt: hir::Enum,
    name_ref: &ast::NameRef,
) -> Option<()> {
    let db = ctx.db();
    let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?;

    let variant = make::variant(make::name(&name_ref.text()), None);
    acc.add(
        AssistId("generate_enum_variant", AssistKind::Generate),
        "Generate variant",
        target,
        |builder| {
            builder.edit_file(file_id.original_file(db));
            let node = builder.make_mut(enum_node);
            node.variant_list().map(|it| it.add_variant(variant.clone_for_update()));
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn generate_basic_enum_variant_in_empty_enum() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::Bar$0
}
",
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Bar
}
",
        )
    }

    #[test]
    fn generate_basic_enum_variant_in_non_empty_enum() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Baz$0
}
",
            r"
enum Foo {
    Bar,
    Baz,
}
fn main() {
    Foo::Baz
}
",
        )
    }

    #[test]
    fn generate_basic_enum_variant_in_different_file() {
        check_assist(
            generate_enum_variant,
            r"
//- /main.rs
mod foo;
use foo::Foo;

fn main() {
    Foo::Baz$0
}

//- /foo.rs
enum Foo {
    Bar,
}
",
            r"
enum Foo {
    Bar,
    Baz,
}
",
        )
    }

    #[test]
    fn not_applicable_for_existing_variant() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Bar$0
}
",
        )
    }

    #[test]
    fn not_applicable_for_lowercase() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::new$0
}
",
        )
    }

    #[test]
    fn indentation_level_is_correct() {
        check_assist(
            generate_enum_variant,
            r"
mod m {
    enum Foo {
        Bar,
    }
}
fn main() {
    m::Foo::Baz$0
}
",
            r"
mod m {
    enum Foo {
        Bar,
        Baz,
    }
}
fn main() {
    m::Foo::Baz
}
",
        )
    }
}
<|endoftext|>


<commit_before>extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;

use self::uuid::Uuid;

use std::io::prelude::*;

use std::fs::File;
use std::net::TcpStream;
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};

use player::Player;
use chat::{read_text,write_text, text_as_bytes};
use opcode;

#[derive(Debug,Clone)]
pub struct ClientBase {
    pub key: Vec<u8>,
    pub id: Uuid,
}

#[derive(Debug,Clone)]
pub struct Client {
    pub base: ClientBase,
    pub stream: Option<Arc<Mutex<TcpStream>>>,
    pub cache: HashMap<Uuid,Player>, //TODO: arc-mutex me
}

impl Client {
    #[allow(dead_code)]
    pub fn default (key: [u8;20], uuid: Uuid) -> Client {
        Client { base: ClientBase { key:From::from(&key[..]),
                                    id:uuid, },
                 stream: None,
                 cache: HashMap::new() }
    }

    #[allow(unused_must_use)]
    pub fn new () -> Client {
        let id = uuid::Uuid::new_v4();
        let m = hmacsha1::hmac_sha1(uuid::Uuid::new_v4().as_bytes(),
                                    id.as_bytes());

        Client::default(m,id)
    }
    #[allow(unused_must_use)]
    pub fn save (client: &Client, path: &str) -> bool {
        let f = File::create(path);
        if let Ok(mut f) = f {
            f.write_all(&client.base.key);
            f.write_all(client.base.id.as_bytes()).is_ok()
        }
        else { false }
    }

    pub fn id (&self) -> &Uuid {
        &self.base.id
    }

    pub fn key (&self) -> &[u8] {
        &self.base.key[..]
    }

    #[allow(dead_code)]
    pub fn key_as_ref (&self) -> &Vec<u8> {
        &self.base.key
    }

    pub fn load_file (path: &str) -> Option<Client> {
        let f = File::open(path);
        if let Ok(mut f) = f {
            return Client::load(&mut f)
        }

        None
    }

    pub fn load<S:Read> (s: &mut S) -> Option<Client> {
        let mut key = [0u8;20];
        let mut id = [0u8;16];
        if let Ok(_) = s.read_exact(&mut key) {
            if let Ok(_) = s.read_exact(&mut id) {
                if let Ok(id) = Uuid::from_bytes(&id) {
                    return Some(Client { base: ClientBase { id:id, key: From::from(&key[..]) },
                                         stream:None,
                                         cache:HashMap::new() })
                }
                else { println!("cannot uuid file") }
            }
        }

        None
    }

    #[allow(unused_must_use)]
    pub fn connect (&mut self, server: &str)  {
        if let Ok(s) = TcpStream::connect(server) {
            self.stream = Some(Arc::new(Mutex::new(s)));
        }
        else { println!("cannot connect to server {:?}",server) }
    }

    #[allow(unused_must_use)]
    pub fn login (&mut self) -> bool {
        let mut c = self.clone();
        if let Some(ref s) = self.stream {
            if let Ok(ref mut s) = s.lock() {
                let mut m = [0u8;16];
                if let Ok(_) = s.read_exact(&mut m) {
                    s.write_all(&[0]);
                    let hm = hmacsha1::hmac_sha1(&self.base.key, &m);

                    s.write_all(&hm);
                    s.write_all(self.base.id.as_bytes());

                    thread::spawn(move || {
                        c.handler()
                    });

                    return true
                }
            }
        }

        false
    }

    #[allow(unused_must_use)]
    pub fn register (&mut self) {
        if let Some(ref ms) = self.stream {
            if let Ok(ref mut s) = ms.lock() {
                s.write_all(&[1]);
                s.write_all(&self.base.key);
                s.write_all(self.base.id.as_bytes());
            }
        }
    }

    #[allow(unused_must_use)]
    pub fn chat (&mut self, text: &str) {
        if let Some(ref ms) = self.stream {
            if let Ok(ref mut s) = ms.lock() {
                write_text(s, text);
            }
        }
    }

    #[allow(unused_must_use)]
    pub fn nick (&mut self, nick: &str) {
        if let Some(ref ms) = self.stream {
            if let Ok(ref mut s) = ms.lock() {
                let (mut data, bytes) = text_as_bytes(nick);
                data[0] = 3; // specify nick route

                s.write_all(&data);
                s.write_all(bytes);
            }
        }
    }

    fn handler (&mut self) {
        let mut cmd = [0u8;1];
        let mut s; // NOTE: this should be read from only!

        if let Some(ref ms) = self.stream {
            if let Ok(s_) = ms.lock() {
                s = s_.try_clone().unwrap();
            }
            else { panic!("client stream mutex poisoned") }
        }
        else { panic!("no client stream available") }

        loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    opcode::CHAT => { // chat
                        if let Some(text) = read_text(&mut s) {
                            let mut id = [0u8;16];
                            if let Ok(_) = s.read_exact(&mut id) {
                                if let Ok(uuid) = Uuid::from_bytes(&id) {
                                    println!("{:?} says: {:?}",
                                             self.cache.get(&uuid),
                                             text.trim());
                                }
                            }
                        }
                    },
                    opcode::PLAYER => { //player
                        if let (Some(uuid),Some(player)) = Player::from_stream(&mut s, true) {
                            println!("player:{:?} {:?}", uuid, player);
                            self.cache.insert(uuid, player);
                        }
                    },
                    _ => {
                        println!("unknown command {:?}",cmd)
                    },
                }
            }
        }
    }
}

<commit_msg>store messages for later retrieval<commit_after>extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;

use self::uuid::Uuid;

use std::io::prelude::*;

use std::fs::File;
use std::net::TcpStream;
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};

use player::Player;
use chat::{read_text,write_text, text_as_bytes};
use opcode;

#[derive(Debug,Clone)]
pub struct ClientBase {
    pub key: Vec<u8>,
    pub id: Uuid,
}

#[derive(Debug,Clone)]
pub struct Client {
    pub base: ClientBase,
    pub stream: Option<Arc<Mutex<TcpStream>>>,
    pub cache: HashMap<Uuid,Player>, //TODO: arc-mutex me
    pub msg: Arc<Mutex<Vec<(Uuid,String)>>>, //cached messages of inbound chat
}

impl Client {
    #[allow(dead_code)]
    pub fn default (key: [u8;20], uuid: Uuid) -> Client {
        Client { base: ClientBase { key:From::from(&key[..]),
                                    id:uuid, },
                 stream: None,
                 cache: HashMap::new(),
                 msg: Arc::new(Mutex::new(vec!())),
        }
    }

    #[allow(unused_must_use)]
    pub fn new () -> Client {
        let id = uuid::Uuid::new_v4();
        let m = hmacsha1::hmac_sha1(uuid::Uuid::new_v4().as_bytes(),
                                    id.as_bytes());

        Client::default(m,id)
    }
    #[allow(unused_must_use)]
    pub fn save (client: &Client, path: &str) -> bool {
        let f = File::create(path);
        if let Ok(mut f) = f {
            f.write_all(&client.base.key);
            f.write_all(client.base.id.as_bytes()).is_ok()
        }
        else { false }
    }

    pub fn id (&self) -> &Uuid {
        &self.base.id
    }

    pub fn key (&self) -> &[u8] {
        &self.base.key[..]
    }

    #[allow(dead_code)]
    pub fn key_as_ref (&self) -> &Vec<u8> {
        &self.base.key
    }

    pub fn load_file (path: &str) -> Option<Client> {
        let f = File::open(path);
        if let Ok(mut f) = f {
            return Client::load(&mut f)
        }

        None
    }

    pub fn load<S:Read> (s: &mut S) -> Option<Client> {
        let mut key = [0u8;20];
        let mut id = [0u8;16];
        if let Ok(_) = s.read_exact(&mut key) {
            if let Ok(_) = s.read_exact(&mut id) {
                if let Ok(id) = Uuid::from_bytes(&id) {
                    return Some(Client::default(key, id))
                }
                else { println!("cannot uuid file") }
            }
        }

        None
    }

    #[allow(unused_must_use)]
    pub fn connect (&mut self, server: &str)  {
        if let Ok(s) = TcpStream::connect(server) {
            self.stream = Some(Arc::new(Mutex::new(s)));
        }
        else { println!("cannot connect to server {:?}",server) }
    }

    #[allow(unused_must_use)]
    pub fn login (&mut self) -> bool {
        let mut c = self.clone();
        if let Some(ref s) = self.stream {
            if let Ok(ref mut s) = s.lock() {
                let mut m = [0u8;16];
                if let Ok(_) = s.read_exact(&mut m) {
                    s.write_all(&[0]);
                    let hm = hmacsha1::hmac_sha1(&self.base.key, &m);

                    s.write_all(&hm);
                    s.write_all(self.base.id.as_bytes());

                    thread::spawn(move || {
                        c.handler()
                    });

                    return true
                }
            }
        }

        false
    }

    #[allow(unused_must_use)]
    pub fn register (&mut self) {
        if let Some(ref ms) = self.stream {
            if let Ok(ref mut s) = ms.lock() {
                s.write_all(&[1]);
                s.write_all(&self.base.key);
                s.write_all(self.base.id.as_bytes());
            }
        }
    }

    #[allow(unused_must_use)]
    pub fn chat (&mut self, text: &str) {
        if let Some(ref ms) = self.stream {
            if let Ok(ref mut s) = ms.lock() {
                write_text(s, text);
            }
        }
    }

    #[allow(unused_must_use)]
    pub fn nick (&mut self, nick: &str) {
        if let Some(ref ms) = self.stream {
            if let Ok(ref mut s) = ms.lock() {
                let (mut data, bytes) = text_as_bytes(nick);
                data[0] = 3; // specify nick route

                s.write_all(&data);
                s.write_all(bytes);
            }
        }
    }

    fn handler (&mut self) {
        let mut cmd = [0u8;1];
        let mut s; // NOTE: this should be read from only!

        if let Some(ref ms) = self.stream {
            if let Ok(s_) = ms.lock() {
                s = s_.try_clone().unwrap();
            }
            else { panic!("client stream mutex poisoned") }
        }
        else { panic!("no client stream available") }

        loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    opcode::CHAT => { // chat
                        if let Some(text) = read_text(&mut s) {
                            let mut id = [0u8;16];
                            if let Ok(_) = s.read_exact(&mut id) {
                                if let Ok(uuid) = Uuid::from_bytes(&id) {
                                    if let Ok(ref mut msg) = self.msg.lock() {
                                        msg.push((uuid,text));
                                    }
                                }
                            }
                        }
                    },
                    opcode::PLAYER => { //player
                        if let (Some(uuid),Some(player)) = Player::from_stream(&mut s, true) {
                            println!("player:{:?} {:?}", uuid, player);
                            self.cache.insert(uuid, player);
                        }
                    },
                    _ => {
                        println!("unknown command {:?}",cmd)
                    },
                }
            }
        }
    }
}

<|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/. */

//! Borders, padding, and margins.

use std::num::Zero;
use geom::side_offsets::SideOffsets2D;
use gfx::geometry::Au;
use newcss::complete::CompleteStyle;
use newcss::units::{Em, Pt, Px};
use newcss::values::{CSSBorderWidth, CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSBorderWidthThick, CSSBorderWidthThin, CSSFontSize, CSSFontSizeLength};
use newcss::values::{CSSWidth, CSSWidthLength, CSSWidthPercentage, CSSWidthAuto};
use newcss::values::{CSSHeight, CSSHeightLength, CSSHeightPercentage, CSSHeightAuto};
use newcss::values::{CSSMargin, CSSMarginLength, CSSMarginPercentage, CSSMarginAuto};
use newcss::values::{CSSPadding, CSSPaddingLength, CSSPaddingPercentage};
/// Encapsulates the borders, padding, and margins, which we collectively call the "box model".
pub struct BoxModel {
    border: SideOffsets2D<Au>,
    padding: SideOffsets2D<Au>,
    margin: SideOffsets2D<Au>,
    /// The width of the content box.
    content_box_width: Au,
}

/// Useful helper data type when computing values for blocks and positioned elements.
pub enum MaybeAuto {
    Auto,
    Specified(Au),
}

impl MaybeAuto {
    pub fn from_margin(margin: CSSMargin, containing_width: Au, font_size: CSSFontSize) -> MaybeAuto {
        match margin {
            CSSMarginAuto => Auto,
            CSSMarginPercentage(percent) => Specified(containing_width.scale_by(percent/100.0)),
            CSSMarginLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSMarginLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSMarginLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Specified(Au::from_frac_px(em * v)),
                    CSSFontSizeLength(Pt(v)) => Specified(Au::from_pt(em * v)),
                    _ => fail!(~"expected non-relative font size"),
                }
            }
        }
    }

    pub fn from_width(width: CSSWidth, containing_width: Au, font_size: CSSFontSize) -> MaybeAuto {
        match width {
            CSSWidthAuto => Auto,
            CSSWidthPercentage(percent) => Specified(containing_width.scale_by(percent/100.0)),
            CSSWidthLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSWidthLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSWidthLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Specified(Au::from_frac_px(em * v)),
                    CSSFontSizeLength(Pt(v)) => Specified(Au::from_pt(em * v)),
                    _ => fail!(~"expected non-relative font size"),
                }
            }
        }
    }

    pub fn from_height(height: CSSHeight, cb_height: Au, font_size: CSSFontSize) -> MaybeAuto {
        match height {
            CSSHeightAuto => Auto,
            CSSHeightPercentage(percent) => Specified(cb_height.scale_by(percent/100.0)),
            CSSHeightLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSHeightLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSHeightLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Specified(Au::from_frac_px(em * v)),
                    CSSFontSizeLength(Pt(v)) => Specified(Au::from_pt(em * v)),
                    _ => fail!(~"expected non-relative font size"),
                }
            }

        }
    }

    pub fn specified_or_default(&self, default: Au) -> Au {
        match *self {
            Auto => default,
            Specified(value) => value,
        }
    }

    pub fn specified_or_zero(&self) -> Au {
        self.specified_or_default(Au(0))
    }
}

impl Zero for BoxModel {
    fn zero() -> BoxModel {
        BoxModel {
            border: Zero::zero(),
            padding: Zero::zero(),
            margin: Zero::zero(),
            content_box_width: Zero::zero(),
        }
    }

    fn is_zero(&self) -> bool {
        self.padding.is_zero() && self.border.is_zero() && self.margin.is_zero()
    }
}

impl BoxModel {
    /// Populates the box model parameters from the given computed style.
    pub fn compute_borders(&mut self, style: CompleteStyle) {
        // Compute the borders.
        self.border.top = self.compute_border_width(style.border_top_width(), style.font_size());
        self.border.right = self.compute_border_width(style.border_right_width(), style.font_size());
        self.border.bottom = self.compute_border_width(style.border_bottom_width(), style.font_size());
        self.border.left = self.compute_border_width(style.border_left_width(), style.font_size());
    }

    pub fn compute_padding(&mut self, style: CompleteStyle, containing_width: Au) {
        self.padding.top = self.compute_padding_length(style.padding_top(), containing_width, style.font_size());
        self.padding.right = self.compute_padding_length(style.padding_right(), containing_width, style.font_size());
        self.padding.bottom = self.compute_padding_length(style.padding_bottom(), containing_width, style.font_size());
        self.padding.left = self.compute_padding_length(style.padding_left(), containing_width, style.font_size());
    }

    pub fn noncontent_width(&self) -> Au {
        let left = self.margin.left + self.border.left + self.padding.left;
        let right = self.margin.right + self.border.right + self.padding.right;
        left + right
    }

    pub fn offset(&self) -> Au {
        self.margin.left + self.border.left + self.padding.left
    }

    /// Helper function to compute the border width in app units from the CSS border width.
    pub fn compute_border_width(&self, width: CSSBorderWidth, font_size: CSSFontSize) -> Au {
        match width {
            CSSBorderWidthLength(Px(v)) => Au::from_frac_px(v),
            CSSBorderWidthLength(Pt(v)) => Au::from_pt(v),
            CSSBorderWidthLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
                    CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
                    _ => fail!(~"expected non-relative font size"),
                }
            },
            CSSBorderWidthThin => Au::from_px(1),
            CSSBorderWidthMedium => Au::from_px(5),
            CSSBorderWidthThick => Au::from_px(10),
        }
    }

    pub fn compute_padding_length(&self, padding: CSSPadding, content_box_width: Au, font_size: CSSFontSize) -> Au {
        match padding {
            CSSPaddingLength(Px(v)) => Au::from_frac_px(v),
            CSSPaddingLength(Pt(v)) => Au::from_pt(v),
            CSSPaddingLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
                    CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
                    _ => fail!(~"expected non-relative font size"),
                }
            },
            CSSPaddingPercentage(p) => content_box_width.scale_by(p/100.0)
        }
    }
}
<commit_msg>Factor out CSS length to Au conversion<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/. */

//! Borders, padding, and margins.

use std::num::Zero;
use geom::side_offsets::SideOffsets2D;
use gfx::geometry::Au;
use newcss::complete::CompleteStyle;
use newcss::units::{Length, Em, Pt, Px};
use newcss::values::{CSSBorderWidth, CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSBorderWidthThick, CSSBorderWidthThin, CSSFontSize, CSSFontSizeLength};
use newcss::values::{CSSWidth, CSSWidthLength, CSSWidthPercentage, CSSWidthAuto};
use newcss::values::{CSSHeight, CSSHeightLength, CSSHeightPercentage, CSSHeightAuto};
use newcss::values::{CSSMargin, CSSMarginLength, CSSMarginPercentage, CSSMarginAuto};
use newcss::values::{CSSPadding, CSSPaddingLength, CSSPaddingPercentage};
/// Encapsulates the borders, padding, and margins, which we collectively call the "box model".
pub struct BoxModel {
    border: SideOffsets2D<Au>,
    padding: SideOffsets2D<Au>,
    margin: SideOffsets2D<Au>,
    /// The width of the content box.
    content_box_width: Au,
}

fn from_length(length: Length, font_size: CSSFontSize) -> Au {
    match length {
        Px(v) => Au::from_frac_px(v),
        Pt(v) => Au::from_pt(v),
        Em(em) => {
            match font_size {
                CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
                CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
                _ => fail!("expected non-relative font size")
            }
        }
    }
}

/// Useful helper data type when computing values for blocks and positioned elements.
pub enum MaybeAuto {
    Auto,
    Specified(Au),
}

impl MaybeAuto {
    pub fn from_margin(margin: CSSMargin, containing_width: Au, font_size: CSSFontSize) -> MaybeAuto {
        match margin {
            CSSMarginAuto => Auto,
            CSSMarginPercentage(percent) => Specified(containing_width.scale_by(percent/100.0)),
            CSSMarginLength(length) => Specified(from_length(length, font_size))
        }
    }

    pub fn from_width(width: CSSWidth, containing_width: Au, font_size: CSSFontSize) -> MaybeAuto {
        match width {
            CSSWidthAuto => Auto,
            CSSWidthPercentage(percent) => Specified(containing_width.scale_by(percent/100.0)),
            CSSWidthLength(length) => Specified(from_length(length, font_size))
        }
    }

    pub fn from_height(height: CSSHeight, cb_height: Au, font_size: CSSFontSize) -> MaybeAuto {
        match height {
            CSSHeightAuto => Auto,
            CSSHeightPercentage(percent) => Specified(cb_height.scale_by(percent/100.0)),
            CSSHeightLength(length) => Specified(from_length(length, font_size))
        }
    }

    pub fn specified_or_default(&self, default: Au) -> Au {
        match *self {
            Auto => default,
            Specified(value) => value,
        }
    }

    pub fn specified_or_zero(&self) -> Au {
        self.specified_or_default(Au(0))
    }
}

impl Zero for BoxModel {
    fn zero() -> BoxModel {
        BoxModel {
            border: Zero::zero(),
            padding: Zero::zero(),
            margin: Zero::zero(),
            content_box_width: Zero::zero(),
        }
    }

    fn is_zero(&self) -> bool {
        self.padding.is_zero() && self.border.is_zero() && self.margin.is_zero()
    }
}

impl BoxModel {
    /// Populates the box model parameters from the given computed style.
    pub fn compute_borders(&mut self, style: CompleteStyle) {
        // Compute the borders.
        self.border.top = self.compute_border_width(style.border_top_width(), style.font_size());
        self.border.right = self.compute_border_width(style.border_right_width(), style.font_size());
        self.border.bottom = self.compute_border_width(style.border_bottom_width(), style.font_size());
        self.border.left = self.compute_border_width(style.border_left_width(), style.font_size());
    }

    pub fn compute_padding(&mut self, style: CompleteStyle, containing_width: Au) {
        self.padding.top = self.compute_padding_length(style.padding_top(), containing_width, style.font_size());
        self.padding.right = self.compute_padding_length(style.padding_right(), containing_width, style.font_size());
        self.padding.bottom = self.compute_padding_length(style.padding_bottom(), containing_width, style.font_size());
        self.padding.left = self.compute_padding_length(style.padding_left(), containing_width, style.font_size());
    }

    pub fn noncontent_width(&self) -> Au {
        let left = self.margin.left + self.border.left + self.padding.left;
        let right = self.margin.right + self.border.right + self.padding.right;
        left + right
    }

    pub fn offset(&self) -> Au {
        self.margin.left + self.border.left + self.padding.left
    }

    /// Helper function to compute the border width in app units from the CSS border width.
    pub fn compute_border_width(&self, width: CSSBorderWidth, font_size: CSSFontSize) -> Au {
        match width {
            CSSBorderWidthLength(length) => from_length(length, font_size),
            CSSBorderWidthThin => Au::from_px(1),
            CSSBorderWidthMedium => Au::from_px(5),
            CSSBorderWidthThick => Au::from_px(10),
        }
    }

    pub fn compute_padding_length(&self, padding: CSSPadding, content_box_width: Au, font_size: CSSFontSize) -> Au {
        match padding {
            CSSPaddingLength(length) => from_length(length, font_size),
            CSSPaddingPercentage(p) => content_box_width.scale_by(p/100.0)
        }
    }
}
<|endoftext|>


<commit_before>#[test]
fn test_format_int() {
    // Formatting integers should select the right implementation based off
    // the type of the argument. Also, hex/octal/binary should be defined
    // for integers, but they shouldn't emit the negative sign.
    assert!(format!("{}", 1isize) == "1");
    assert!(format!("{}", 1i8) == "1");
    assert!(format!("{}", 1i16) == "1");
    assert!(format!("{}", 1i32) == "1");
    assert!(format!("{}", 1i64) == "1");
    assert!(format!("{}", -1isize) == "-1");
    assert!(format!("{}", -1i8) == "-1");
    assert!(format!("{}", -1i16) == "-1");
    assert!(format!("{}", -1i32) == "-1");
    assert!(format!("{}", -1i64) == "-1");
    assert!(format!("{:?}", 1isize) == "1");
    assert!(format!("{:?}", 1i8) == "1");
    assert!(format!("{:?}", 1i16) == "1");
    assert!(format!("{:?}", 1i32) == "1");
    assert!(format!("{:?}", 1i64) == "1");
    assert!(format!("{:b}", 1isize) == "1");
    assert!(format!("{:b}", 1i8) == "1");
    assert!(format!("{:b}", 1i16) == "1");
    assert!(format!("{:b}", 1i32) == "1");
    assert!(format!("{:b}", 1i64) == "1");
    assert!(format!("{:x}", 1isize) == "1");
    assert!(format!("{:x}", 1i8) == "1");
    assert!(format!("{:x}", 1i16) == "1");
    assert!(format!("{:x}", 1i32) == "1");
    assert!(format!("{:x}", 1i64) == "1");
    assert!(format!("{:X}", 1isize) == "1");
    assert!(format!("{:X}", 1i8) == "1");
    assert!(format!("{:X}", 1i16) == "1");
    assert!(format!("{:X}", 1i32) == "1");
    assert!(format!("{:X}", 1i64) == "1");
    assert!(format!("{:o}", 1isize) == "1");
    assert!(format!("{:o}", 1i8) == "1");
    assert!(format!("{:o}", 1i16) == "1");
    assert!(format!("{:o}", 1i32) == "1");
    assert!(format!("{:o}", 1i64) == "1");

    assert!(format!("{}", 1usize) == "1");
    assert!(format!("{}", 1u8) == "1");
    assert!(format!("{}", 1u16) == "1");
    assert!(format!("{}", 1u32) == "1");
    assert!(format!("{}", 1u64) == "1");
    assert!(format!("{:?}", 1usize) == "1");
    assert!(format!("{:?}", 1u8) == "1");
    assert!(format!("{:?}", 1u16) == "1");
    assert!(format!("{:?}", 1u32) == "1");
    assert!(format!("{:?}", 1u64) == "1");
    assert!(format!("{:b}", 1usize) == "1");
    assert!(format!("{:b}", 1u8) == "1");
    assert!(format!("{:b}", 1u16) == "1");
    assert!(format!("{:b}", 1u32) == "1");
    assert!(format!("{:b}", 1u64) == "1");
    assert!(format!("{:x}", 1usize) == "1");
    assert!(format!("{:x}", 1u8) == "1");
    assert!(format!("{:x}", 1u16) == "1");
    assert!(format!("{:x}", 1u32) == "1");
    assert!(format!("{:x}", 1u64) == "1");
    assert!(format!("{:X}", 1usize) == "1");
    assert!(format!("{:X}", 1u8) == "1");
    assert!(format!("{:X}", 1u16) == "1");
    assert!(format!("{:X}", 1u32) == "1");
    assert!(format!("{:X}", 1u64) == "1");
    assert!(format!("{:o}", 1usize) == "1");
    assert!(format!("{:o}", 1u8) == "1");
    assert!(format!("{:o}", 1u16) == "1");
    assert!(format!("{:o}", 1u32) == "1");
    assert!(format!("{:o}", 1u64) == "1");

    // Test a larger number
    assert!(format!("{:b}", 55) == "110111");
    assert!(format!("{:o}", 55) == "67");
    assert!(format!("{}", 55) == "55");
    assert!(format!("{:x}", 55) == "37");
    assert!(format!("{:X}", 55) == "37");
}

#[test]
fn test_format_int_zero() {
    assert!(format!("{}", 0) == "0");
    assert!(format!("{:?}", 0) == "0");
    assert!(format!("{:b}", 0) == "0");
    assert!(format!("{:o}", 0) == "0");
    assert!(format!("{:x}", 0) == "0");
    assert!(format!("{:X}", 0) == "0");

    assert!(format!("{}", 0u32) == "0");
    assert!(format!("{:?}", 0u32) == "0");
    assert!(format!("{:b}", 0u32) == "0");
    assert!(format!("{:o}", 0u32) == "0");
    assert!(format!("{:x}", 0u32) == "0");
    assert!(format!("{:X}", 0u32) == "0");
}

#[test]
fn test_format_int_flags() {
    assert!(format!("{:3}", 1) == "  1");
    assert!(format!("{:>3}", 1) == "  1");
    assert!(format!("{:>+3}", 1) == " +1");
    assert!(format!("{:<3}", 1) == "1  ");
    assert!(format!("{:#}", 1) == "1");
    assert!(format!("{:#x}", 10) == "0xa");
    assert!(format!("{:#X}", 10) == "0xA");
    assert!(format!("{:#5x}", 10) == "  0xa");
    assert!(format!("{:#o}", 10) == "0o12");
    assert!(format!("{:08x}", 10) == "0000000a");
    assert!(format!("{:8x}", 10) == "       a");
    assert!(format!("{:<8x}", 10) == "a       ");
    assert!(format!("{:>8x}", 10) == "       a");
    assert!(format!("{:#08x}", 10) == "0x00000a");
    assert!(format!("{:08}", -10) == "-0000010");
    assert!(format!("{:x}", !0u8) == "ff");
    assert!(format!("{:X}", !0u8) == "FF");
    assert!(format!("{:b}", !0u8) == "11111111");
    assert!(format!("{:o}", !0u8) == "377");
    assert!(format!("{:#x}", !0u8) == "0xff");
    assert!(format!("{:#X}", !0u8) == "0xFF");
    assert!(format!("{:#b}", !0u8) == "0b11111111");
    assert!(format!("{:#o}", !0u8) == "0o377");
}

#[test]
fn test_format_int_sign_padding() {
    assert!(format!("{:+5}", 1) == "   +1");
    assert!(format!("{:+5}", -1) == "   -1");
    assert!(format!("{:05}", 1) == "00001");
    assert!(format!("{:05}", -1) == "-0001");
    assert!(format!("{:+05}", 1) == "+0001");
    assert!(format!("{:+05}", -1) == "-0001");
}

#[test]
fn test_format_int_twos_complement() {
    use core::{i8, i16, i32, i64};
    assert!(format!("{}", i8::MIN) == "-128");
    assert!(format!("{}", i16::MIN) == "-32768");
    assert!(format!("{}", i32::MIN) == "-2147483648");
    assert!(format!("{}", i64::MIN) == "-9223372036854775808");
}

#[test]
fn test_format_debug_hex() {
    assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]");
    assert!(format!("{:02X?}", b"Foo\0") == "[46, 6F, 6F, 00]");
}
<commit_msg>Replace assert with assert_eq for better debugging<commit_after>#[test]
fn test_format_int() {
    // Formatting integers should select the right implementation based off
    // the type of the argument. Also, hex/octal/binary should be defined
    // for integers, but they shouldn't emit the negative sign.
    assert_eq!(format!("{}", 1isize), "1");
    assert_eq!(format!("{}", 1i8), "1");
    assert_eq!(format!("{}", 1i16), "1");
    assert_eq!(format!("{}", 1i32), "1");
    assert_eq!(format!("{}", 1i64), "1");
    assert_eq!(format!("{}", -1isize), "-1");
    assert_eq!(format!("{}", -1i8), "-1");
    assert_eq!(format!("{}", -1i16), "-1");
    assert_eq!(format!("{}", -1i32), "-1");
    assert_eq!(format!("{}", -1i64), "-1");
    assert_eq!(format!("{:?}", 1isize), "1");
    assert_eq!(format!("{:?}", 1i8), "1");
    assert_eq!(format!("{:?}", 1i16), "1");
    assert_eq!(format!("{:?}", 1i32), "1");
    assert_eq!(format!("{:?}", 1i64), "1");
    assert_eq!(format!("{:b}", 1isize), "1");
    assert_eq!(format!("{:b}", 1i8), "1");
    assert_eq!(format!("{:b}", 1i16), "1");
    assert_eq!(format!("{:b}", 1i32), "1");
    assert_eq!(format!("{:b}", 1i64), "1");
    assert_eq!(format!("{:x}", 1isize), "1");
    assert_eq!(format!("{:x}", 1i8), "1");
    assert_eq!(format!("{:x}", 1i16), "1");
    assert_eq!(format!("{:x}", 1i32), "1");
    assert_eq!(format!("{:x}", 1i64), "1");
    assert_eq!(format!("{:X}", 1isize), "1");
    assert_eq!(format!("{:X}", 1i8), "1");
    assert_eq!(format!("{:X}", 1i16), "1");
    assert_eq!(format!("{:X}", 1i32), "1");
    assert_eq!(format!("{:X}", 1i64), "1");
    assert_eq!(format!("{:o}", 1isize), "1");
    assert_eq!(format!("{:o}", 1i8), "1");
    assert_eq!(format!("{:o}", 1i16), "1");
    assert_eq!(format!("{:o}", 1i32), "1");
    assert_eq!(format!("{:o}", 1i64), "1");

    assert_eq!(format!("{}", 1usize), "1");
    assert_eq!(format!("{}", 1u8), "1");
    assert_eq!(format!("{}", 1u16), "1");
    assert_eq!(format!("{}", 1u32), "1");
    assert_eq!(format!("{}", 1u64), "1");
    assert_eq!(format!("{:?}", 1usize), "1");
    assert_eq!(format!("{:?}", 1u8), "1");
    assert_eq!(format!("{:?}", 1u16), "1");
    assert_eq!(format!("{:?}", 1u32), "1");
    assert_eq!(format!("{:?}", 1u64), "1");
    assert_eq!(format!("{:b}", 1usize), "1");
    assert_eq!(format!("{:b}", 1u8), "1");
    assert_eq!(format!("{:b}", 1u16), "1");
    assert_eq!(format!("{:b}", 1u32), "1");
    assert_eq!(format!("{:b}", 1u64), "1");
    assert_eq!(format!("{:x}", 1usize), "1");
    assert_eq!(format!("{:x}", 1u8), "1");
    assert_eq!(format!("{:x}", 1u16), "1");
    assert_eq!(format!("{:x}", 1u32), "1");
    assert_eq!(format!("{:x}", 1u64), "1");
    assert_eq!(format!("{:X}", 1usize), "1");
    assert_eq!(format!("{:X}", 1u8), "1");
    assert_eq!(format!("{:X}", 1u16), "1");
    assert_eq!(format!("{:X}", 1u32), "1");
    assert_eq!(format!("{:X}", 1u64), "1");
    assert_eq!(format!("{:o}", 1usize), "1");
    assert_eq!(format!("{:o}", 1u8), "1");
    assert_eq!(format!("{:o}", 1u16), "1");
    assert_eq!(format!("{:o}", 1u32), "1");
    assert_eq!(format!("{:o}", 1u64), "1");

    // Test a larger number
    assert_eq!(format!("{:b}", 55), "110111");
    assert_eq!(format!("{:o}", 55), "67");
    assert_eq!(format!("{}", 55), "55");
    assert_eq!(format!("{:x}", 55), "37");
    assert_eq!(format!("{:X}", 55), "37");
}

#[test]
fn test_format_int_zero() {
    assert_eq!(format!("{}", 0), "0");
    assert_eq!(format!("{:?}", 0), "0");
    assert_eq!(format!("{:b}", 0), "0");
    assert_eq!(format!("{:o}", 0), "0");
    assert_eq!(format!("{:x}", 0), "0");
    assert_eq!(format!("{:X}", 0), "0");

    assert_eq!(format!("{}", 0u32), "0");
    assert_eq!(format!("{:?}", 0u32), "0");
    assert_eq!(format!("{:b}", 0u32), "0");
    assert_eq!(format!("{:o}", 0u32), "0");
    assert_eq!(format!("{:x}", 0u32), "0");
    assert_eq!(format!("{:X}", 0u32), "0");
}

#[test]
fn test_format_int_flags() {
    assert_eq!(format!("{:3}", 1), "  1");
    assert_eq!(format!("{:>3}", 1), "  1");
    assert_eq!(format!("{:>+3}", 1), " +1");
    assert_eq!(format!("{:<3}", 1), "1  ");
    assert_eq!(format!("{:#}", 1), "1");
    assert_eq!(format!("{:#x}", 10), "0xa");
    assert_eq!(format!("{:#X}", 10), "0xA");
    assert_eq!(format!("{:#5x}", 10), "  0xa");
    assert_eq!(format!("{:#o}", 10), "0o12");
    assert_eq!(format!("{:08x}", 10), "0000000a");
    assert_eq!(format!("{:8x}", 10), "       a");
    assert_eq!(format!("{:<8x}", 10), "a       ");
    assert_eq!(format!("{:>8x}", 10), "       a");
    assert_eq!(format!("{:#08x}", 10), "0x00000a");
    assert_eq!(format!("{:08}", -10), "-0000010");
    assert_eq!(format!("{:x}", !0u8), "ff");
    assert_eq!(format!("{:X}", !0u8), "FF");
    assert_eq!(format!("{:b}", !0u8), "11111111");
    assert_eq!(format!("{:o}", !0u8), "377");
    assert_eq!(format!("{:#x}", !0u8), "0xff");
    assert_eq!(format!("{:#X}", !0u8), "0xFF");
    assert_eq!(format!("{:#b}", !0u8), "0b11111111");
    assert_eq!(format!("{:#o}", !0u8), "0o377");
}

#[test]
fn test_format_int_sign_padding() {
    assert_eq!(format!("{:+5}", 1), "   +1");
    assert_eq!(format!("{:+5}", -1), "   -1");
    assert_eq!(format!("{:05}", 1), "00001");
    assert_eq!(format!("{:05}", -1), "-0001");
    assert_eq!(format!("{:+05}", 1), "+0001");
    assert_eq!(format!("{:+05}", -1), "-0001");
}

#[test]
fn test_format_int_twos_complement() {
    use core::{i16, i32, i64, i8};
    assert_eq!(format!("{}", i8::MIN), "-128");
    assert_eq!(format!("{}", i16::MIN), "-32768");
    assert_eq!(format!("{}", i32::MIN), "-2147483648");
    assert_eq!(format!("{}", i64::MIN), "-9223372036854775808");
}

#[test]
fn test_format_debug_hex() {
    assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]");
    assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]");
}
<|endoftext|>