<commit_before>//! Combinators and utilities for working with `Future`s, `Stream`s, `Sink`s,
//! and the `AsyncRead` and `AsyncWrite` traits.

#![feature(async_await, pin, arbitrary_self_types, futures_api)]
#![cfg_attr(feature = "std", feature(await_macro))]
#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))]

#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs, missing_debug_implementations)]
#![deny(bare_trait_objects)]

#![doc(html_root_url = "https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.9/futures_util")]

#[macro_use]
mod macros;

#[cfg(feature = "std")]
#[macro_use]
pub mod async_await;

#[cfg(feature = "std")]
#[doc(hidden)]
pub mod rand_reexport { // used by select!
    pub use rand::*;
}

#[doc(hidden)]
pub mod core_reexport {
    pub use core::*;
}

macro_rules! delegate_sink {
    ($field:ident) => {
        fn poll_ready(
            mut self: Pin<&mut Self>,
            lw: &$crate::core_reexport::task::LocalWaker,
        ) -> $crate::core_reexport::task::Poll<Result<(), Self::SinkError>> {
            self.$field().poll_ready(lw)
        }

        fn start_send(
            mut self: Pin<&mut Self>,
            item: Self::SinkItem
        ) -> Result<(), Self::SinkError> {
            self.$field().start_send(item)
        }

        fn poll_flush(
            mut self: Pin<&mut Self>,
            lw: &$crate::core_reexport::task::LocalWaker
        ) -> $crate::core_reexport::task::Poll<Result<(), Self::SinkError>> {
            self.$field().poll_flush(lw)
        }

        fn poll_close(
            mut self: Pin<&mut Self>,
            lw: &$crate::core_reexport::task::LocalWaker
        ) -> $crate::core_reexport::task::Poll<Result<(), Self::SinkError>> {
            self.$field().poll_close(lw)
        }
    }
}

pub mod future;
#[doc(hidden)] pub use crate::future::FutureExt;

pub mod try_future;
#[doc(hidden)] pub use crate::try_future::TryFutureExt;

pub mod stream;
#[doc(hidden)] pub use crate::stream::StreamExt;

pub mod try_stream;
#[doc(hidden)] pub use crate::try_stream::TryStreamExt;

pub mod sink;
#[doc(hidden)] pub use crate::sink::SinkExt;

pub mod task;

#[cfg(feature = "compat")]
pub mod compat;

#[cfg(feature = "std")]
pub mod io;
#[cfg(feature = "std")]
#[doc(hidden)] pub use crate::io::{AsyncReadExt, AsyncWriteExt};

#[cfg(feature = "std")]
#[cfg(any(test, feature = "bench"))]
pub mod lock;
#[cfg(feature = "std")]
#[cfg(not(any(test, feature = "bench")))]
mod lock;
<commit_msg>Temporariy add unsized_locals feature to fix nightly build<commit_after>//! Combinators and utilities for working with `Future`s, `Stream`s, `Sink`s,
//! and the `AsyncRead` and `AsyncWrite` traits.

#![feature(async_await, pin, arbitrary_self_types, futures_api, unsized_locals)]
#![cfg_attr(feature = "std", feature(await_macro))]
#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))]

#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs, missing_debug_implementations)]
#![deny(bare_trait_objects)]

#![doc(html_root_url = "https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.9/futures_util")]

#[macro_use]
mod macros;

#[cfg(feature = "std")]
#[macro_use]
pub mod async_await;

#[cfg(feature = "std")]
#[doc(hidden)]
pub mod rand_reexport { // used by select!
    pub use rand::*;
}

#[doc(hidden)]
pub mod core_reexport {
    pub use core::*;
}

macro_rules! delegate_sink {
    ($field:ident) => {
        fn poll_ready(
            mut self: Pin<&mut Self>,
            lw: &$crate::core_reexport::task::LocalWaker,
        ) -> $crate::core_reexport::task::Poll<Result<(), Self::SinkError>> {
            self.$field().poll_ready(lw)
        }

        fn start_send(
            mut self: Pin<&mut Self>,
            item: Self::SinkItem
        ) -> Result<(), Self::SinkError> {
            self.$field().start_send(item)
        }

        fn poll_flush(
            mut self: Pin<&mut Self>,
            lw: &$crate::core_reexport::task::LocalWaker
        ) -> $crate::core_reexport::task::Poll<Result<(), Self::SinkError>> {
            self.$field().poll_flush(lw)
        }

        fn poll_close(
            mut self: Pin<&mut Self>,
            lw: &$crate::core_reexport::task::LocalWaker
        ) -> $crate::core_reexport::task::Poll<Result<(), Self::SinkError>> {
            self.$field().poll_close(lw)
        }
    }
}

pub mod future;
#[doc(hidden)] pub use crate::future::FutureExt;

pub mod try_future;
#[doc(hidden)] pub use crate::try_future::TryFutureExt;

pub mod stream;
#[doc(hidden)] pub use crate::stream::StreamExt;

pub mod try_stream;
#[doc(hidden)] pub use crate::try_stream::TryStreamExt;

pub mod sink;
#[doc(hidden)] pub use crate::sink::SinkExt;

pub mod task;

#[cfg(feature = "compat")]
pub mod compat;

#[cfg(feature = "std")]
pub mod io;
#[cfg(feature = "std")]
#[doc(hidden)] pub use crate::io::{AsyncReadExt, AsyncWriteExt};

#[cfg(feature = "std")]
#[cfg(any(test, feature = "bench"))]
pub mod lock;
#[cfg(feature = "std")]
#[cfg(not(any(test, feature = "bench")))]
mod lock;
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use cudart::Memory;
use std::path::Path;
use image;

#[allow(dead_code)]
pub struct Image<T> {
    info: T,
    width: usize,
    height: usize,
    pub data: Vec<u8>
}

const CHANNELS:usize = 3;

impl<T> Image<T> {
    pub fn from_file(file: &mut File,
                     width: usize,
                     height: usize,
                     info: T) -> Result<Image<T>, &'static str> {
        let mut buf = vec![0u8; width * height * CHANNELS];
        try!(match file.read(&mut buf) {
            Ok(n) if(n == width * height * CHANNELS) => Ok(()),
            _ => Err("EOF")
        });

        Ok(Image::<T> {
            info: info,
            width: width,
            height: height,
            data: buf.to_vec()
        })
    }

    pub fn from_device(memory: Memory<f32>,
                       info: T,
                       width: usize,
                       height: usize) -> Result<Image<T>, &'static str> {
        let mut buf_f32 = vec![0f32; width * height * CHANNELS];
        try!(memory.read(&mut buf_f32));
        let buf_u8 = buf_f32.into_iter().map(|x: f32| (x * 255.0) as u8).collect::<Vec<_>>();

        Ok(Image::<T> {
            info: info,
            width: width,
            height: height,
            data: buf_u8
        })
    }

    pub fn save(self, path: &str) -> Result<(), &'static str> {
        match image::save_buffer(&Path::new(&path),
                                 &self.data_whc(),
                                 self.width as u32,
                                 self.height as u32,
                                 image::RGB(8)) {
            Ok(()) => Ok(()),
            Err(_) => Err("Failed to save the result image file.")
        }
    }

    pub fn to_device(&self) -> Result<Memory<f32>, &'static str> {
        let buf = self.data.clone().into_iter().map(|x: u8| (x as f32) / 255.0).collect::<Vec<_>>();
        let mem = try!(Memory::new(self.size()));
        try!(mem.write(&buf));
        Ok(mem)
    }

    pub fn size(&self) -> usize {
        self.width * self.height * CHANNELS
    }

    pub fn data_whc(&self) -> Vec<u8> {
        let mut res = vec![0u8; self.size()];
        for i in 0..res.len() {
            res[i] = self.data[(i % 3) * (self.width * self.height) + (i / 3)];
        }
        res
    }
}
<commit_msg>opened image info<commit_after>use std::fs::File;
use std::io::Read;
use cudart::Memory;
use std::path::Path;
use image;

#[allow(dead_code)]
pub struct Image<T> {
    pub info: T,
    width: usize,
    height: usize,
    pub data: Vec<u8>
}

const CHANNELS:usize = 3;

impl<T> Image<T> {
    pub fn from_file(file: &mut File,
                     width: usize,
                     height: usize,
                     info: T) -> Result<Image<T>, &'static str> {
        let mut buf = vec![0u8; width * height * CHANNELS];
        try!(match file.read(&mut buf) {
            Ok(n) if(n == width * height * CHANNELS) => Ok(()),
            _ => Err("EOF")
        });

        Ok(Image::<T> {
            info: info,
            width: width,
            height: height,
            data: buf.to_vec()
        })
    }

    pub fn from_device(memory: Memory<f32>,
                       info: T,
                       width: usize,
                       height: usize) -> Result<Image<T>, &'static str> {
        let mut buf_f32 = vec![0f32; width * height * CHANNELS];
        try!(memory.read(&mut buf_f32));
        let buf_u8 = buf_f32.into_iter().map(|x: f32| (x * 255.0) as u8).collect::<Vec<_>>();

        Ok(Image::<T> {
            info: info,
            width: width,
            height: height,
            data: buf_u8
        })
    }

    pub fn save(self, path: &str) -> Result<(), &'static str> {
        match image::save_buffer(&Path::new(&path),
                                 &self.data_whc(),
                                 self.width as u32,
                                 self.height as u32,
                                 image::RGB(8)) {
            Ok(()) => Ok(()),
            Err(_) => Err("Failed to save the result image file.")
        }
    }

    pub fn to_device(&self) -> Result<Memory<f32>, &'static str> {
        let buf = self.data.clone().into_iter().map(|x: u8| (x as f32) / 255.0).collect::<Vec<_>>();
        let mem = try!(Memory::new(self.size()));
        try!(mem.write(&buf));
        Ok(mem)
    }

    pub fn size(&self) -> usize {
        self.width * self.height * CHANNELS
    }

    pub fn data_whc(&self) -> Vec<u8> {
        let mut res = vec![0u8; self.size()];
        for i in 0..res.len() {
            res[i] = self.data[(i % 3) * (self.width * self.height) + (i / 3)];
        }
        res
    }
}
<|endoftext|>


<commit_before>extern crate chrono;

use std::ops::{Deref, DerefMut};
use self::chrono::offset::utc::UTC;
use self::chrono::{DateTime, NaiveDateTime};

pub trait Mbc {
    fn read(&self, address: u16) -> u8;
    fn write(&mut self, address: u16, v: u8);
    fn ram(&mut self) -> &mut [u8];
    fn rtc(&mut self) -> Option<&mut i64>;
}

struct Mbc0 {
    data: Vec<u8>,
    ram: [u8; RAM_BANK_SIZE],
}

impl Mbc0 {
    pub fn new(data: Vec<u8>) -> Mbc0 {
        Mbc0 {
            data: data,
            ram: [0; RAM_BANK_SIZE],
        }
    }
}

impl Mbc for Mbc0 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.data[address as usize],
            0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000],
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, _: u16, _: u8) {
        // Theoretically not supposed to write to the Mbc0 ROM, but some games do
        // it anyway.
    }

    fn ram(&mut self) -> &mut [u8] {
        &mut self.ram
    }

    fn rtc(&mut self) -> Option<&mut i64> {
        None
    }
}

#[allow(dead_code)]
#[derive(PartialEq, Eq)]
enum MemoryMode {
    C4_32,
    C16_8,
}

enum MbcMode {
    Mbc3,
    Mbc1,
}

#[allow(dead_code)]
struct Mbc13 {
    selected_bank: usize,
    data: Vec<u8>,
    offset: usize,
    ram: [u8; RAM_BANK_SIZE * 4],

    ram_rtc: RamRtc,
    ram_enabled: bool,

    rtc: i64,
    rtc_register: u8,
    rtc_latch_status: RtcLatchStatus,

    rom_banks: usize,
    mode: MbcMode,
}

const BANK_SIZE: usize = 0x4000;
const RAM_BANK_SIZE: usize = 0x2000;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum RtcLatchStatus {
    Initial,
    Enabling,
    Enabled,
}

enum RamRtc {
    RamBank(usize),
    RtcRegister(u8),
}

impl Mbc13 {
    pub fn new(data: Vec<u8>, mode: MbcMode) -> Mbc13 {
        if data.len() % BANK_SIZE != 0 {
            panic!(format!("Invalid rom size (must be an integer multiple of {})", BANK_SIZE));
        }

        Mbc13 {
            selected_bank: 1,
            rom_banks: data.len() / BANK_SIZE,
            data: data,
            offset: 0,
            ram: [0; BANK_SIZE * 2],

            ram_rtc: RamRtc::RamBank(0),
            ram_enabled: false,
            rtc: 0,

            rtc_register: 0,
            rtc_latch_status: RtcLatchStatus::Initial,

            mode: mode,
        }
    }

    fn write_ram(&mut self, offset: usize, address: u16, v: u8) {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + offset;
        self.ram[address] = v;
    }

    fn write_ram_mbc1(&mut self, address: u16, v: u8) {
        match self.ram_rtc {
            RamRtc::RamBank(offset) => self.write_ram(offset, address, v),
            // MBC1 does not support RTC
            RamRtc::RtcRegister(_) => unreachable!(),
        }
    }

    fn write_ram_rtc_mbc3(&mut self, address: u16, v: u8) {
        match self.ram_rtc {
            RamRtc::RamBank(offset) => self.write_ram(offset, address, v),
            RamRtc::RtcRegister(reg) => self.write_rtc(reg, v),
        }
    }

    fn read_ram(&self, offset: usize, address: u16) -> u8 {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + offset;
        self.ram[address]
    }

    fn read_rtc(&self, reg: u8) -> u8 {
        let rtc = DateTime::<UTC>::from_utc(NaiveDateTime::from_timestamp(self.rtc, 0), UTC);

        let diff = UTC::now().signed_duration_since(rtc);
        (match reg {
            0x08 => diff.num_seconds() % 60,
            0x09 => diff.num_minutes() % 60,
            0x0A => diff.num_hours() % 24,
            0x0B => diff.num_days() % 0xFF,
            0x0C => diff.num_days() >> 8 & 0x01
                + (if diff.num_days() > 511 { 0b10000000 } else { 0 }),
            _ => unreachable!(),
        } as u8)
    }

    fn write_rtc(&mut self, _: u8, _: u8) {
        // TODO
    }

    fn read_ram_mbc1(&self, address: u16) -> u8 {
        match self.ram_rtc {
            RamRtc::RamBank(offset) => self.read_ram(offset, address),
            // MBC1 does not support RTC
            RamRtc::RtcRegister(_) => unreachable!(),
        }
    }

    fn read_ram_rtc_mbc3(&self, address: u16) -> u8 {
        match self.ram_rtc {
            RamRtc::RamBank(offset) => self.read_ram(offset, address),
            RamRtc::RtcRegister(reg) => self.read_rtc(reg),
        }
    }

    fn switch_bank_mbc3(&mut self, v: u8) {
        // Any write to this area will enable the bank of memory contained in v
        // if 0 is selected we will select 1 because 0 is already available
        // statically in 0 0000 - 3FFF
        // Moreover, if the requested bank is out of range, the DMG wraps around
        // and picks a valid bank regardless of the value.
        let bank = v as usize % self.rom_banks;
        if bank > 0 {
            self.offset = (bank - 1) * BANK_SIZE;
        } else {
            self.offset = 0x0000;
        }
    }

    fn switch_bank_mbc1(&mut self, v: u8) {
        // There's a bug in MBC1 that makes it so that for v = 0x00, 0x20, 0x40, 0x60
        // the bank selected is actually the following one (v+1)
        let v_bug = match v & 0b11111 {
            0x00 | 0x20 | 0x40 | 0x60 => v + 1,
            _ => v,
        };

        // The rom bank selected will wrap around if the value is out of range.
        let bank = v_bug as usize % self.rom_banks;

        self.offset = (bank - 1) * BANK_SIZE;
    }

    fn switch_ram_bank_mbc1(&mut self, v: u8) {
        // Writing to this area will cause the controller to switch
        // banks of in-cartridge RAM.
        // Only the lowest two bits are relevant for this register.
        self.ram_rtc = RamRtc::RamBank(RAM_BANK_SIZE * (v & 0b11) as usize);
    }

    fn switch_ram_bank_mbc3(&mut self, v: u8) {
        if v < 0x04 {
            self.ram_rtc = RamRtc::RamBank(RAM_BANK_SIZE * (v & 0b11) as usize);
        } else if v >= 0x08 && v <= 0x0C {
            self.ram_rtc = RamRtc::RtcRegister(v);
        } else {
            // TODO: not sure what happens here ???
            unimplemented!();
        }
    }

    fn latch_clock_data(&mut self, v: u8) {
        if v == 0x00 {
            self.rtc_latch_status = RtcLatchStatus::Enabling;
        } else if v == 0x01 && self.rtc_latch_status == RtcLatchStatus::Enabling {
            self.rtc_latch_status = RtcLatchStatus::Enabled;
            // TODO write registers
        }
    }
}

impl Mbc for Mbc13 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x3FFF => self.data[address as usize],
            0x4000 ... 0x7FFF => self.data[address as usize + self.offset],
            0xA000 ... 0xBFFF => {
                match self.mode {
                    MbcMode::Mbc1 => self.read_ram_mbc1(address),
                    MbcMode::Mbc3 => self.read_ram_rtc_mbc3(address),
                }
            }
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        match address {
            0x0000 ... 0x1FFF => {
                match v & 0x0A {
                    0x00 => self.ram_enabled = false,
                    0x0A => self.ram_enabled = true,
                    _    => {
                        // Not too sure about this, but some games write
                        // to this area other values which don't seem to
                        // do anything. TODO: test on real hardware
                    }
                }
            },
            0x2000 ... 0x3FFF => {
                match self.mode {
                    MbcMode::Mbc1 => self.switch_bank_mbc1(v),
                    MbcMode::Mbc3 => self.switch_bank_mbc3(v),
                }
            },
            0x4000 ... 0x5FFF => {
                match self.mode {
                    MbcMode::Mbc1 => self.switch_ram_bank_mbc1(v),
                    MbcMode::Mbc3 => self.switch_ram_bank_mbc3(v),
                }
            },
            0x6000 ... 0x7FFF => {
                match self.mode {
                    MbcMode::Mbc1 => unimplemented!(),
                    MbcMode::Mbc3 => self.latch_clock_data(v),
                }
            },
            0xA000 ... 0xBFFF => {
                match self.mode {
                    MbcMode::Mbc1 => self.write_ram_mbc1(address, v),
                    MbcMode::Mbc3 => self.write_ram_rtc_mbc3(address, v),
                }
            },
            _ => unimplemented!(),
        }
    }

    fn ram(&mut self) -> &mut [u8] {
        &mut self.ram
    }

    fn rtc(&mut self) -> Option<&mut i64> {
        Some(&mut self.rtc)
    }
}

pub struct MemoryController {
    controller: Box<Mbc>,
}

impl MemoryController {
    pub fn from_bytes(bytes: Vec<u8>) -> MemoryController {
        let controller = match bytes[0x147] {
            0x00 =>
                Box::new(Mbc0::new(bytes)) as Box<Mbc>,
            0x01 | 0x02 | 0x03 =>
                Box::new(Mbc13::new(bytes, MbcMode::Mbc1)) as Box<Mbc>,
            0x0F | 0x10 | 0x11 | 0x12 | 0x13 =>
                Box::new(Mbc13::new(bytes, MbcMode::Mbc3)) as Box<Mbc>,
            _ => {
                println!("Unrecognized type {:02X}", bytes[0x147]);
                panic!();
            }
        };

        MemoryController {
            controller: controller,
        }
    }

    pub fn read(&self, address: u16) -> u8 {
        self.controller.read(address)
    }

    pub fn write(&mut self, address: u16, v: u8) {
        self.controller.write(address, v);
    }
}

impl Deref for MemoryController {
    type Target = Mbc;
    fn deref(&self) -> &Self::Target {
        &*self.controller
    }
}

impl DerefMut for MemoryController {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut *self.controller
    }
}
<commit_msg>Don't crash on invalid mbc3 bank setting.<commit_after>extern crate chrono;

use std::ops::{Deref, DerefMut};
use self::chrono::offset::utc::UTC;
use self::chrono::{DateTime, NaiveDateTime};

pub trait Mbc {
    fn read(&self, address: u16) -> u8;
    fn write(&mut self, address: u16, v: u8);
    fn ram(&mut self) -> &mut [u8];
    fn rtc(&mut self) -> Option<&mut i64>;
}

struct Mbc0 {
    data: Vec<u8>,
    ram: [u8; RAM_BANK_SIZE],
}

impl Mbc0 {
    pub fn new(data: Vec<u8>) -> Mbc0 {
        Mbc0 {
            data: data,
            ram: [0; RAM_BANK_SIZE],
        }
    }
}

impl Mbc for Mbc0 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.data[address as usize],
            0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000],
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, _: u16, _: u8) {
        // Theoretically not supposed to write to the Mbc0 ROM, but some games do
        // it anyway.
    }

    fn ram(&mut self) -> &mut [u8] {
        &mut self.ram
    }

    fn rtc(&mut self) -> Option<&mut i64> {
        None
    }
}

#[allow(dead_code)]
#[derive(PartialEq, Eq)]
enum MemoryMode {
    C4_32,
    C16_8,
}

enum MbcMode {
    Mbc3,
    Mbc1,
}

#[allow(dead_code)]
struct Mbc13 {
    selected_bank: usize,
    data: Vec<u8>,
    offset: usize,
    ram: [u8; RAM_BANK_SIZE * 4],

    ram_rtc: RamRtc,
    ram_enabled: bool,

    rtc: i64,
    rtc_register: u8,
    rtc_latch_status: RtcLatchStatus,

    rom_banks: usize,
    mode: MbcMode,
}

const BANK_SIZE: usize = 0x4000;
const RAM_BANK_SIZE: usize = 0x2000;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum RtcLatchStatus {
    Initial,
    Enabling,
    Enabled,
}

enum RamRtc {
    RamBank(usize),
    RtcRegister(u8),
}

impl Mbc13 {
    pub fn new(data: Vec<u8>, mode: MbcMode) -> Mbc13 {
        if data.len() % BANK_SIZE != 0 {
            panic!(format!("Invalid rom size (must be an integer multiple of {})", BANK_SIZE));
        }

        Mbc13 {
            selected_bank: 1,
            rom_banks: data.len() / BANK_SIZE,
            data: data,
            offset: 0,
            ram: [0; BANK_SIZE * 2],

            ram_rtc: RamRtc::RamBank(0),
            ram_enabled: false,
            rtc: 0,

            rtc_register: 0,
            rtc_latch_status: RtcLatchStatus::Initial,

            mode: mode,
        }
    }

    fn write_ram(&mut self, offset: usize, address: u16, v: u8) {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + offset;
        self.ram[address] = v;
    }

    fn write_ram_mbc1(&mut self, address: u16, v: u8) {
        match self.ram_rtc {
            RamRtc::RamBank(offset) => self.write_ram(offset, address, v),
            // MBC1 does not support RTC
            RamRtc::RtcRegister(_) => unreachable!(),
        }
    }

    fn write_ram_rtc_mbc3(&mut self, address: u16, v: u8) {
        match self.ram_rtc {
            RamRtc::RamBank(offset) => self.write_ram(offset, address, v),
            RamRtc::RtcRegister(reg) => self.write_rtc(reg, v),
        }
    }

    fn read_ram(&self, offset: usize, address: u16) -> u8 {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + offset;
        self.ram[address]
    }

    fn read_rtc(&self, reg: u8) -> u8 {
        let rtc = DateTime::<UTC>::from_utc(NaiveDateTime::from_timestamp(self.rtc, 0), UTC);

        let diff = UTC::now().signed_duration_since(rtc);
        (match reg {
            0x08 => diff.num_seconds() % 60,
            0x09 => diff.num_minutes() % 60,
            0x0A => diff.num_hours() % 24,
            0x0B => diff.num_days() % 0xFF,
            0x0C => diff.num_days() >> 8 & 0x01
                + (if diff.num_days() > 511 { 0b10000000 } else { 0 }),
            _ => unreachable!(),
        } as u8)
    }

    fn write_rtc(&mut self, _: u8, _: u8) {
        // TODO
    }

    fn read_ram_mbc1(&self, address: u16) -> u8 {
        match self.ram_rtc {
            RamRtc::RamBank(offset) => self.read_ram(offset, address),
            // MBC1 does not support RTC
            RamRtc::RtcRegister(_) => unreachable!(),
        }
    }

    fn read_ram_rtc_mbc3(&self, address: u16) -> u8 {
        match self.ram_rtc {
            RamRtc::RamBank(offset) => self.read_ram(offset, address),
            RamRtc::RtcRegister(reg) => self.read_rtc(reg),
        }
    }

    fn switch_bank_mbc3(&mut self, v: u8) {
        // Any write to this area will enable the bank of memory contained in v
        // if 0 is selected we will select 1 because 0 is already available
        // statically in 0 0000 - 3FFF
        // Moreover, if the requested bank is out of range, the DMG wraps around
        // and picks a valid bank regardless of the value.
        let bank = v as usize % self.rom_banks;
        if bank > 0 {
            self.offset = (bank - 1) * BANK_SIZE;
        } else {
            self.offset = 0x0000;
        }
    }

    fn switch_bank_mbc1(&mut self, v: u8) {
        // There's a bug in MBC1 that makes it so that for v = 0x00, 0x20, 0x40, 0x60
        // the bank selected is actually the following one (v+1)
        let v_bug = match v & 0b11111 {
            0x00 | 0x20 | 0x40 | 0x60 => v + 1,
            _ => v,
        };

        // The rom bank selected will wrap around if the value is out of range.
        let bank = v_bug as usize % self.rom_banks;

        self.offset = (bank - 1) * BANK_SIZE;
    }

    fn switch_ram_bank_mbc1(&mut self, v: u8) {
        // Writing to this area will cause the controller to switch
        // banks of in-cartridge RAM.
        // Only the lowest two bits are relevant for this register.
        self.ram_rtc = RamRtc::RamBank(RAM_BANK_SIZE * (v & 0b11) as usize);
    }

    fn switch_ram_bank_mbc3(&mut self, v: u8) {
        if v < 0x04 {
            self.ram_rtc = RamRtc::RamBank(RAM_BANK_SIZE * (v & 0b11) as usize);
        } else if v >= 0x08 && v <= 0x0C {
            self.ram_rtc = RamRtc::RtcRegister(v);
        } else {
            // TODO: Looking at the town map in Pokemon Red/Blue triggers this,
            // not sure what is supposed to happen but doing nothing seems good
            // enough for now.
        }
    }

    fn latch_clock_data(&mut self, v: u8) {
        if v == 0x00 {
            self.rtc_latch_status = RtcLatchStatus::Enabling;
        } else if v == 0x01 && self.rtc_latch_status == RtcLatchStatus::Enabling {
            self.rtc_latch_status = RtcLatchStatus::Enabled;
            // TODO write registers
        }
    }
}

impl Mbc for Mbc13 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x3FFF => self.data[address as usize],
            0x4000 ... 0x7FFF => self.data[address as usize + self.offset],
            0xA000 ... 0xBFFF => {
                match self.mode {
                    MbcMode::Mbc1 => self.read_ram_mbc1(address),
                    MbcMode::Mbc3 => self.read_ram_rtc_mbc3(address),
                }
            }
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        match address {
            0x0000 ... 0x1FFF => {
                match v & 0x0A {
                    0x00 => self.ram_enabled = false,
                    0x0A => self.ram_enabled = true,
                    _    => {
                        // Not too sure about this, but some games write
                        // to this area other values which don't seem to
                        // do anything. TODO: test on real hardware
                    }
                }
            },
            0x2000 ... 0x3FFF => {
                match self.mode {
                    MbcMode::Mbc1 => self.switch_bank_mbc1(v),
                    MbcMode::Mbc3 => self.switch_bank_mbc3(v),
                }
            },
            0x4000 ... 0x5FFF => {
                match self.mode {
                    MbcMode::Mbc1 => self.switch_ram_bank_mbc1(v),
                    MbcMode::Mbc3 => self.switch_ram_bank_mbc3(v),
                }
            },
            0x6000 ... 0x7FFF => {
                match self.mode {
                    MbcMode::Mbc1 => unimplemented!(),
                    MbcMode::Mbc3 => self.latch_clock_data(v),
                }
            },
            0xA000 ... 0xBFFF => {
                match self.mode {
                    MbcMode::Mbc1 => self.write_ram_mbc1(address, v),
                    MbcMode::Mbc3 => self.write_ram_rtc_mbc3(address, v),
                }
            },
            _ => unimplemented!(),
        }
    }

    fn ram(&mut self) -> &mut [u8] {
        &mut self.ram
    }

    fn rtc(&mut self) -> Option<&mut i64> {
        Some(&mut self.rtc)
    }
}

pub struct MemoryController {
    controller: Box<Mbc>,
}

impl MemoryController {
    pub fn from_bytes(bytes: Vec<u8>) -> MemoryController {
        let controller = match bytes[0x147] {
            0x00 =>
                Box::new(Mbc0::new(bytes)) as Box<Mbc>,
            0x01 | 0x02 | 0x03 =>
                Box::new(Mbc13::new(bytes, MbcMode::Mbc1)) as Box<Mbc>,
            0x0F | 0x10 | 0x11 | 0x12 | 0x13 =>
                Box::new(Mbc13::new(bytes, MbcMode::Mbc3)) as Box<Mbc>,
            _ => {
                println!("Unrecognized type {:02X}", bytes[0x147]);
                panic!();
            }
        };

        MemoryController {
            controller: controller,
        }
    }

    pub fn read(&self, address: u16) -> u8 {
        self.controller.read(address)
    }

    pub fn write(&mut self, address: u16, v: u8) {
        self.controller.write(address, v);
    }
}

impl Deref for MemoryController {
    type Target = Mbc;
    fn deref(&self) -> &Self::Target {
        &*self.controller
    }
}

impl DerefMut for MemoryController {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut *self.controller
    }
}
<|endoftext|>


<commit_before>//! Download a web page using the `curl` crate
//! Use RUST_LOG=info cargo run to see INFO messages

extern crate clap;
extern crate curl;
extern crate env_logger;
extern crate log;

#[macro_use]
extern crate error_chain;

use clap::{Arg, App};
use log::{info, error};
use std::fs::File;
use std::io::prelude::*;

// Declare errors
error_chain! {
    foreign_links {
        Curl(curl::Error);
        StdIo(std::io::Error);
    }
    errors {
        HttpError(code: u32) {
            description("HTTP error code")
            display("HTTP error status in response: {}", code)
        }
    }
}

/// Download the content hosted on an URL
fn download_binary(url: &str) -> Result<Vec<u8>> {
    let mut buf = Vec::new();
    let mut handle = curl::easy::Easy::new();
    handle.url(url)?;
    {
        let mut transfer = handle.transfer();
        transfer.write_function(|data| {
            buf.extend_from_slice(data);
            Ok(data.len())
        })?;
        transfer.perform()?;
    }
    let http_code = handle.response_code()?;
    if http_code != 200 {
        bail!(ErrorKind::HttpError(http_code));
    }
    Ok(buf)
}

/// Download a URL, optionally to an output file
fn download_web(url: &str, output_file: Option<&str>) -> Result<()> {
    let data = download_binary(url)?;
    if let Some(out_file_path) = output_file {
        let mut file = File::create(out_file_path)?;
        file.write_all(&data)?;
        info!("{} bytes written to {}", data.len(), out_file_path);
    } else {
        let body = String::from_utf8(data).map_err(
            |_| "data is not valid UTF8!",
        )?;
        println!("{}", body);
    }
    Ok(())
}

fn main() {
    env_logger::init();

    let matches = App::new("DownloadWeb")
        .version("0.1.0")
        .author("Nicolas Iooss")
        .about("Download a web page")
        .arg(
            Arg::with_name("url")
                .required(true)
                .takes_value(true)
                .help("URL to the page"),
        )
        .arg(
            Arg::with_name("output")
                .short("o")
                .long("output")
                .takes_value(true)
                .help("Output to a file"),
        )
        .get_matches();

    if let Err(err) = download_web(matches.value_of("url").unwrap(), matches.value_of("output")) {
        match err {
            Error(ErrorKind::Curl(e), _) => error!("Error in Curl: {}", e),
            _ => error!("Error: {}", err),
        }
        std::process::exit(1);
    }
}
<commit_msg>rust/download_web: drop wildcard import<commit_after>//! Download a web page using the `curl` crate
//! Use RUST_LOG=info cargo run to see INFO messages

extern crate clap;
extern crate curl;
extern crate env_logger;
extern crate log;

#[macro_use]
extern crate error_chain;

use clap::{Arg, App};
use log::{info, error};
use std::fs::File;
use std::io::Write;

// Declare errors
error_chain! {
    foreign_links {
        Curl(curl::Error);
        StdIo(std::io::Error);
    }
    errors {
        HttpError(code: u32) {
            description("HTTP error code")
            display("HTTP error status in response: {}", code)
        }
    }
}

/// Download the content hosted on an URL
fn download_binary(url: &str) -> Result<Vec<u8>> {
    let mut buf = Vec::new();
    let mut handle = curl::easy::Easy::new();
    handle.url(url)?;
    {
        let mut transfer = handle.transfer();
        transfer.write_function(|data| {
            buf.extend_from_slice(data);
            Ok(data.len())
        })?;
        transfer.perform()?;
    }
    let http_code = handle.response_code()?;
    if http_code != 200 {
        bail!(ErrorKind::HttpError(http_code));
    }
    Ok(buf)
}

/// Download a URL, optionally to an output file
fn download_web(url: &str, output_file: Option<&str>) -> Result<()> {
    let data = download_binary(url)?;
    if let Some(out_file_path) = output_file {
        let mut file = File::create(out_file_path)?;
        file.write_all(&data)?;
        info!("{} bytes written to {}", data.len(), out_file_path);
    } else {
        let body = String::from_utf8(data).map_err(
            |_| "data is not valid UTF8!",
        )?;
        println!("{}", body);
    }
    Ok(())
}

fn main() {
    env_logger::init();

    let matches = App::new("DownloadWeb")
        .version("0.1.0")
        .author("Nicolas Iooss")
        .about("Download a web page")
        .arg(
            Arg::with_name("url")
                .required(true)
                .takes_value(true)
                .help("URL to the page"),
        )
        .arg(
            Arg::with_name("output")
                .short("o")
                .long("output")
                .takes_value(true)
                .help("Output to a file"),
        )
        .get_matches();

    if let Err(err) = download_web(matches.value_of("url").unwrap(), matches.value_of("output")) {
        match err {
            Error(ErrorKind::Curl(e), _) => error!("Error in Curl: {}", e),
            _ => error!("Error: {}", err),
        }
        std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>use super::{Numeric, Columnar, Tabular};
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

#[cfg(features = "rand")]
use rand::Rand;

#[cfg(test)]
mod test;

pub trait Vector<N>: Sized
where N: Numeric {

    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

#[cfg(features = "rand")]
impl<N> Rand for Vector3<N>
where N: Numeric
    , N: Rand {

    fn rand<R: Rng>(rng: &mut R) -> Self {
        Vector3 { x: N::rand(rng)
                , y: N::rand(rng)
                , z: N::rand(rng)
                }
    }
}

impl<N> Columnar for Vector3<N>
where N: Numeric
    , N: Copy {

    type Column = Vector3<N>;

    #[inline] fn ncols(&self) -> usize { 1 }
    #[inline] fn column(&self, i: usize) -> Self::Column {
        if i == 0 { *self }
        else { panic!("Index out of bounds!") }
    }
    #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
        if i == 0 { self }
        else { panic!("Index out of bounds!") }
    }

}

impl<N> Tabular for Vector3<N>
where N: Numeric
    , N: Copy {

    type Row = N;
    #[inline] fn nrows(&self) -> usize { 3 }
    #[inline] fn row(&self, i: usize) -> Self::Row {
        match i { 0 => self.x
                , 1 => self.y
                , 2 => self.z
                , _ => panic!("Index out of bounds!")
                }
    }
    #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
        match i { 0 => &mut self.x
                , 1 => &mut self.y
                , 2 => &mut self.z
                , _ => panic!("Index out of bounds!")
                }
    }

}

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector3<N>> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

#[cfg(features = "rand")]
impl<N> Rand for Vector2<N>
where N: Numeric
    , N: Rand {

    fn rand<R: Rng>(rng: &mut R) -> Self {
        Vector2 { x: N::rand(rng)
                , y: N::rand(rng)
                }
    }
}

impl<N> Columnar for Vector2<N>
where N: Numeric
    , N: Copy {

    type Column = Vector2<N>;

    #[inline] fn ncols(&self) -> usize { 1 }
    #[inline] fn column(&self, i: usize) -> Self::Column {
        if i == 0 { *self }
        else { panic!("Index out of bounds!") }
    }
    #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
        if i == 0 { self }
        else { panic!("Index out of bounds!") }
    }

}

impl<N> Tabular for Vector2<N>
where N: Numeric
    , N: Copy {

    type Row = N;
    #[inline] fn nrows(&self) -> usize { 3 }
    #[inline] fn row(&self, i: usize) -> Self::Row {
        match i { 0 => self.x
                , 1 => self.y
                , _ => panic!("Index out of bounds!")
                }
    }
    #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
        match i { 0 => &mut self.x
                , 1 => &mut self.y
                , _ => panic!("Index out of bounds!")
                }
    }

}

// macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector2<N>> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

pub struct VectorN<'a, N: Numeric + 'a>(&'a [N]);
<commit_msg>Vectors can now be converted from arrays<commit_after>use super::{Numeric, Columnar, Tabular};
use std::ops::{Add, Sub, Mul, Div, Rem};
use std::convert;

#[cfg(features = "parallel")]
use super::parallel::*;

#[cfg(features = "rand")]
use rand::Rand;

#[cfg(test)]
mod test;

pub trait Vector<N>: Sized
where N: Numeric {

    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

#[cfg(features = "rand")]
impl<N> Rand for Vector3<N>
where N: Numeric
    , N: Rand {

    fn rand<R: Rng>(rng: &mut R) -> Self {
        Vector3 { x: N::rand(rng)
                , y: N::rand(rng)
                , z: N::rand(rng)
                }
    }
}

impl<N> Columnar for Vector3<N>
where N: Numeric
    , N: Copy {

    type Column = Vector3<N>;

    #[inline] fn ncols(&self) -> usize { 1 }
    #[inline] fn column(&self, i: usize) -> Self::Column {
        if i == 0 { *self }
        else { panic!("Index out of bounds!") }
    }
    #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
        if i == 0 { self }
        else { panic!("Index out of bounds!") }
    }

}

impl<N> Tabular for Vector3<N>
where N: Numeric
    , N: Copy {

    type Row = N;
    #[inline] fn nrows(&self) -> usize { 3 }
    #[inline] fn row(&self, i: usize) -> Self::Row {
        match i { 0 => self.x
                , 1 => self.y
                , 2 => self.z
                , _ => panic!("Index out of bounds!")
                }
    }
    #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
        match i { 0 => &mut self.x
                , 1 => &mut self.y
                , 2 => &mut self.z
                , _ => panic!("Index out of bounds!")
                }
    }

}

impl<N> convert::From<[N; 3]> for Vector3<N>
where N: Numeric
    , N: Copy {
        fn from(a: [N; 3]) -> Self {
            Vector3 { x: a[0], y: a[1], z: a[2] }
        }
}

impl<'a, N> convert::From<&'a [N; 3]> for Vector3<N>
where N: Numeric
    , N: Copy {
        fn from(a: &[N; 3]) -> Self {
            Vector3 { x: a[0], y: a[1], z: a[2] }
        }
}

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector3<N>> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

#[cfg(features = "rand")]
impl<N> Rand for Vector2<N>
where N: Numeric
    , N: Rand {

    fn rand<R: Rng>(rng: &mut R) -> Self {
        Vector2 { x: N::rand(rng)
                , y: N::rand(rng)
                }
    }
}

impl<N> Columnar for Vector2<N>
where N: Numeric
    , N: Copy {

    type Column = Vector2<N>;

    #[inline] fn ncols(&self) -> usize { 1 }
    #[inline] fn column(&self, i: usize) -> Self::Column {
        if i == 0 { *self }
        else { panic!("Index out of bounds!") }
    }
    #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
        if i == 0 { self }
        else { panic!("Index out of bounds!") }
    }

}

impl<N> Tabular for Vector2<N>
where N: Numeric
    , N: Copy {

    type Row = N;
    #[inline] fn nrows(&self) -> usize { 3 }
    #[inline] fn row(&self, i: usize) -> Self::Row {
        match i { 0 => self.x
                , 1 => self.y
                , _ => panic!("Index out of bounds!")
                }
    }
    #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
        match i { 0 => &mut self.x
                , 1 => &mut self.y
                , _ => panic!("Index out of bounds!")
                }
    }

}

impl<N> convert::From<[N; 2]> for Vector2<N>
where N: Numeric
    , N: Copy {
        fn from(a: [N; 2]) -> Self {
            Vector2 { x: a[0], y: a[1] }
        }
}

impl<'a, N> convert::From<&'a [N; 2]> for Vector2<N>
where N: Numeric
    , N: Copy {
        fn from(a: &[N; 2]) -> Self {
            Vector2 { x: a[0], y: a[1] }
        }
}

// macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector2<N>> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

pub struct VectorN<'a, N: Numeric + 'a>(&'a [N]);
<|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 https://mozilla.org/MPL/2.0/. */

use crate::geom::flow_relative::{Rect, Sides};
use crate::geom::{PhysicalPoint, PhysicalRect};
#[cfg(debug_assertions)]
use crate::layout_debug;
use crate::positioned::HoistedFragmentId;
use gfx::text::glyph::GlyphStore;
use gfx_traits::print_tree::PrintTree;
#[cfg(not(debug_assertions))]
use serde::ser::{Serialize, Serializer};
use servo_arc::Arc as ServoArc;
use std::sync::Arc;
use style::computed_values::overflow_x::T as ComputedOverflow;
use style::dom::OpaqueNode;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style::Zero;
use webrender_api::{FontInstanceKey, ImageKey};

#[derive(Serialize)]
pub(crate) enum Fragment {
    Box(BoxFragment),
    Anonymous(AnonymousFragment),
    AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment),
    Text(TextFragment),
    Image(ImageFragment),
}

#[derive(Serialize)]
pub(crate) struct AbsoluteOrFixedPositionedFragment(pub HoistedFragmentId);

#[derive(Serialize)]
pub(crate) struct BoxFragment {
    pub tag: OpaqueNode,
    pub debug_id: DebugId,
    #[serde(skip_serializing)]
    pub style: ServoArc<ComputedValues>,
    pub children: Vec<Fragment>,

    /// From the containing block’s start corner…?
    /// This might be broken when the containing block is in a different writing mode:
    /// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
    pub content_rect: Rect<Length>,

    pub padding: Sides<Length>,
    pub border: Sides<Length>,
    pub margin: Sides<Length>,

    pub block_margins_collapsed_with_children: CollapsedBlockMargins,

    /// The scrollable overflow of this box fragment.
    pub scrollable_overflow_from_children: PhysicalRect<Length>,

    /// XXX Add thsi
    pub hoisted_fragment_id: Option<HoistedFragmentId>,
}

#[derive(Serialize)]
pub(crate) struct CollapsedBlockMargins {
    pub collapsed_through: bool,
    pub start: CollapsedMargin,
    pub end: CollapsedMargin,
}

#[derive(Clone, Copy, Serialize)]
pub(crate) struct CollapsedMargin {
    max_positive: Length,
    min_negative: Length,
}

/// Can contain child fragments with relative coordinates, but does not contribute to painting itself.
#[derive(Serialize)]
pub(crate) struct AnonymousFragment {
    pub debug_id: DebugId,
    pub rect: Rect<Length>,
    pub children: Vec<Fragment>,
    pub mode: WritingMode,

    /// The scrollable overflow of this anonymous fragment's children.
    pub scrollable_overflow: PhysicalRect<Length>,
}

#[derive(Serialize)]
pub(crate) struct TextFragment {
    pub debug_id: DebugId,
    pub tag: OpaqueNode,
    #[serde(skip_serializing)]
    pub parent_style: ServoArc<ComputedValues>,
    pub rect: Rect<Length>,
    pub ascent: Length,
    #[serde(skip_serializing)]
    pub font_key: FontInstanceKey,
    pub glyphs: Vec<Arc<GlyphStore>>,
}

#[derive(Serialize)]
pub(crate) struct ImageFragment {
    pub debug_id: DebugId,
    #[serde(skip_serializing)]
    pub style: ServoArc<ComputedValues>,
    pub rect: Rect<Length>,
    #[serde(skip_serializing)]
    pub image_key: ImageKey,
}

impl Fragment {
    pub fn offset_inline(&mut self, offset: &Length) {
        let position = match self {
            Fragment::Box(f) => &mut f.content_rect.start_corner,
            Fragment::AbsoluteOrFixedPositioned(_) => return,
            Fragment::Anonymous(f) => &mut f.rect.start_corner,
            Fragment::Text(f) => &mut f.rect.start_corner,
            Fragment::Image(f) => &mut f.rect.start_corner,
        };

        position.inline += *offset;
    }

    pub fn print(&self, tree: &mut PrintTree) {
        match self {
            Fragment::Box(fragment) => fragment.print(tree),
            Fragment::AbsoluteOrFixedPositioned(fragment) => fragment.print(tree),
            Fragment::Anonymous(fragment) => fragment.print(tree),
            Fragment::Text(fragment) => fragment.print(tree),
            Fragment::Image(fragment) => fragment.print(tree),
        }
    }

    pub fn scrollable_overflow(&self) -> PhysicalRect<Length> {
        // FIXME(mrobinson, bug 25564): We should be using the containing block
        // here to properly convert scrollable overflow to physical geometry.
        let containing_block = PhysicalRect::zero();
        match self {
            Fragment::Box(fragment) => fragment.scrollable_overflow_for_parent(&containing_block),
            Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(),
            Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(),
            Fragment::Text(fragment) => fragment
                .rect
                .to_physical(fragment.parent_style.writing_mode, &containing_block),
            Fragment::Image(fragment) => fragment
                .rect
                .to_physical(fragment.style.writing_mode, &containing_block),
        }
    }

    pub fn is_hoisted(&self) -> bool {
        match self {
            Fragment::Box(fragment) if fragment.hoisted_fragment_id.is_some() => true,
            _ => false,
        }
    }

    pub fn hoisted_fragment_id(&self) -> Option<&HoistedFragmentId> {
        match self {
            Fragment::Box(fragment) => fragment.hoisted_fragment_id.as_ref(),
            _ => None,
        }
    }
}

impl AbsoluteOrFixedPositionedFragment {
    pub fn print(&self, tree: &mut PrintTree) {
        tree.add_item(format!("AbsoluteOrFixedPositionedFragment({:?})", self.0));
    }
}

impl AnonymousFragment {
    pub fn no_op(mode: WritingMode) -> Self {
        Self {
            debug_id: DebugId::new(),
            children: vec![],
            rect: Rect::zero(),
            mode,
            scrollable_overflow: PhysicalRect::zero(),
        }
    }

    pub fn new(rect: Rect<Length>, children: Vec<Fragment>, mode: WritingMode) -> Self {
        let content_origin = rect.start_corner.to_physical(mode);
        let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
            acc.union(
                &child
                    .scrollable_overflow()
                    .translate(content_origin.to_vector()),
            )
        });
        AnonymousFragment {
            debug_id: DebugId::new(),
            rect,
            children,
            mode,
            scrollable_overflow,
        }
    }

    pub fn print(&self, tree: &mut PrintTree) {
        tree.new_level(format!(
            "Anonymous\
                \nrect={:?}\
                \nscrollable_overflow={:?}",
            self.rect, self.scrollable_overflow
        ));

        for child in &self.children {
            child.print(tree);
        }
        tree.end_level();
    }
}

impl BoxFragment {
    pub fn new(
        tag: OpaqueNode,
        style: ServoArc<ComputedValues>,
        children: Vec<Fragment>,
        content_rect: Rect<Length>,
        padding: Sides<Length>,
        border: Sides<Length>,
        margin: Sides<Length>,
        block_margins_collapsed_with_children: CollapsedBlockMargins,
        hoisted_fragment_id: Option<HoistedFragmentId>,
    ) -> BoxFragment {
        let scrollable_overflow_from_children =
            children.iter().fold(PhysicalRect::zero(), |acc, child| {
                acc.union(&child.scrollable_overflow())
            });
        BoxFragment {
            tag,
            debug_id: DebugId::new(),
            style,
            children,
            content_rect,
            padding,
            border,
            margin,
            block_margins_collapsed_with_children,
            scrollable_overflow_from_children,
            hoisted_fragment_id,
        }
    }

    pub fn scrollable_overflow(&self) -> PhysicalRect<Length> {
        // FIXME(mrobinson, bug 25564): We should be using the containing block
        // here to properly convert scrollable overflow to physical geometry.
        let physical_padding_rect = self
            .padding_rect()
            .to_physical(self.style.writing_mode, &PhysicalRect::zero());

        let content_origin = self
            .content_rect
            .start_corner
            .to_physical(self.style.writing_mode);
        physical_padding_rect.union(
            &self
                .scrollable_overflow_from_children
                .translate(content_origin.to_vector()),
        )
    }

    pub fn padding_rect(&self) -> Rect<Length> {
        self.content_rect.inflate(&self.padding)
    }

    pub fn border_rect(&self) -> Rect<Length> {
        self.padding_rect().inflate(&self.border)
    }

    pub fn print(&self, tree: &mut PrintTree) {
        tree.new_level(format!(
            "Box\
                \ncontent={:?}\
                \npadding rect={:?}\
                \nborder rect={:?}\
                \nscrollable_overflow={:?}\
                \noverflow={:?} / {:?}\
                \nstyle={:p}\
                \nhoisted_id={:?}",
            self.content_rect,
            self.padding_rect(),
            self.border_rect(),
            self.scrollable_overflow(),
            self.style.get_box().overflow_x,
            self.style.get_box().overflow_y,
            self.style,
            self.hoisted_fragment_id,
        ));

        for child in &self.children {
            child.print(tree);
        }
        tree.end_level();
    }

    pub fn scrollable_overflow_for_parent(
        &self,
        containing_block: &PhysicalRect<Length>,
    ) -> PhysicalRect<Length> {
        let mut overflow = self
            .border_rect()
            .to_physical(self.style.writing_mode, containing_block);

        if self.style.get_box().overflow_y != ComputedOverflow::Visible &&
            self.style.get_box().overflow_x != ComputedOverflow::Visible
        {
            return overflow;
        }

        // https://www.w3.org/TR/css-overflow-3/#scrollable
        // Only include the scrollable overflow of a child box if it has overflow: visible.
        let scrollable_overflow = self.scrollable_overflow();
        let bottom_right = PhysicalPoint::new(
            overflow.max_x().max(scrollable_overflow.max_x()),
            overflow.max_y().max(scrollable_overflow.max_y()),
        );

        if self.style.get_box().overflow_y == ComputedOverflow::Visible {
            overflow.origin.y = overflow.origin.y.min(scrollable_overflow.origin.y);
            overflow.size.height = bottom_right.y - overflow.origin.y;
        }

        if self.style.get_box().overflow_x == ComputedOverflow::Visible {
            overflow.origin.x = overflow.origin.x.min(scrollable_overflow.origin.x);
            overflow.size.width = bottom_right.x - overflow.origin.x;
        }

        overflow
    }
}

impl TextFragment {
    pub fn print(&self, tree: &mut PrintTree) {
        tree.add_item(format!(
            "Text num_glyphs={}",
            self.glyphs
                .iter()
                .map(|glyph_store| glyph_store.len().0)
                .sum::<isize>()
        ));
    }
}

impl ImageFragment {
    pub fn print(&self, tree: &mut PrintTree) {
        tree.add_item(format!(
            "Image\
                \nrect={:?}",
            self.rect
        ));
    }
}

impl CollapsedBlockMargins {
    pub fn from_margin(margin: &Sides<Length>) -> Self {
        Self {
            collapsed_through: false,
            start: CollapsedMargin::new(margin.block_start),
            end: CollapsedMargin::new(margin.block_end),
        }
    }

    pub fn zero() -> Self {
        Self {
            collapsed_through: false,
            start: CollapsedMargin::zero(),
            end: CollapsedMargin::zero(),
        }
    }
}

impl CollapsedMargin {
    pub fn zero() -> Self {
        Self {
            max_positive: Length::zero(),
            min_negative: Length::zero(),
        }
    }

    pub fn new(margin: Length) -> Self {
        Self {
            max_positive: margin.max(Length::zero()),
            min_negative: margin.min(Length::zero()),
        }
    }

    pub fn adjoin(&self, other: &Self) -> Self {
        Self {
            max_positive: self.max_positive.max(other.max_positive),
            min_negative: self.min_negative.min(other.min_negative),
        }
    }

    pub fn adjoin_assign(&mut self, other: &Self) {
        *self = self.adjoin(other);
    }

    pub fn solve(&self) -> Length {
        self.max_positive + self.min_negative
    }
}

#[cfg(not(debug_assertions))]
#[derive(Clone)]
pub struct DebugId;

#[cfg(debug_assertions)]
#[derive(Clone, Serialize)]
#[serde(transparent)]
pub struct DebugId(u16);

#[cfg(not(debug_assertions))]
impl DebugId {
    pub fn new() -> DebugId {
        DebugId
    }
}

#[cfg(debug_assertions)]
impl DebugId {
    pub fn new() -> DebugId {
        DebugId(layout_debug::generate_unique_debug_id())
    }
}

#[cfg(not(debug_assertions))]
impl Serialize for DebugId {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&format!("{:p}", &self))
    }
}
<commit_msg>Auto merge of #25988 - mrobinson:fix-doc, r=SimonSapin<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 https://mozilla.org/MPL/2.0/. */

use crate::geom::flow_relative::{Rect, Sides};
use crate::geom::{PhysicalPoint, PhysicalRect};
#[cfg(debug_assertions)]
use crate::layout_debug;
use crate::positioned::HoistedFragmentId;
use gfx::text::glyph::GlyphStore;
use gfx_traits::print_tree::PrintTree;
#[cfg(not(debug_assertions))]
use serde::ser::{Serialize, Serializer};
use servo_arc::Arc as ServoArc;
use std::sync::Arc;
use style::computed_values::overflow_x::T as ComputedOverflow;
use style::dom::OpaqueNode;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style::Zero;
use webrender_api::{FontInstanceKey, ImageKey};

#[derive(Serialize)]
pub(crate) enum Fragment {
    Box(BoxFragment),
    Anonymous(AnonymousFragment),
    AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment),
    Text(TextFragment),
    Image(ImageFragment),
}

#[derive(Serialize)]
pub(crate) struct AbsoluteOrFixedPositionedFragment(pub HoistedFragmentId);

#[derive(Serialize)]
pub(crate) struct BoxFragment {
    pub tag: OpaqueNode,
    pub debug_id: DebugId,
    #[serde(skip_serializing)]
    pub style: ServoArc<ComputedValues>,
    pub children: Vec<Fragment>,

    /// From the containing block’s start corner…?
    /// This might be broken when the containing block is in a different writing mode:
    /// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
    pub content_rect: Rect<Length>,

    pub padding: Sides<Length>,
    pub border: Sides<Length>,
    pub margin: Sides<Length>,

    pub block_margins_collapsed_with_children: CollapsedBlockMargins,

    /// The scrollable overflow of this box fragment.
    pub scrollable_overflow_from_children: PhysicalRect<Length>,

    /// If this fragment was laid out from a hoisted box, this id corresponds to the id stored in
    /// the AbsoluteOrFixedPositionedFragment left as a placeholder in the tree position of the
    /// box.
    pub hoisted_fragment_id: Option<HoistedFragmentId>,
}

#[derive(Serialize)]
pub(crate) struct CollapsedBlockMargins {
    pub collapsed_through: bool,
    pub start: CollapsedMargin,
    pub end: CollapsedMargin,
}

#[derive(Clone, Copy, Serialize)]
pub(crate) struct CollapsedMargin {
    max_positive: Length,
    min_negative: Length,
}

/// Can contain child fragments with relative coordinates, but does not contribute to painting itself.
#[derive(Serialize)]
pub(crate) struct AnonymousFragment {
    pub debug_id: DebugId,
    pub rect: Rect<Length>,
    pub children: Vec<Fragment>,
    pub mode: WritingMode,

    /// The scrollable overflow of this anonymous fragment's children.
    pub scrollable_overflow: PhysicalRect<Length>,
}

#[derive(Serialize)]
pub(crate) struct TextFragment {
    pub debug_id: DebugId,
    pub tag: OpaqueNode,
    #[serde(skip_serializing)]
    pub parent_style: ServoArc<ComputedValues>,
    pub rect: Rect<Length>,
    pub ascent: Length,
    #[serde(skip_serializing)]
    pub font_key: FontInstanceKey,
    pub glyphs: Vec<Arc<GlyphStore>>,
}

#[derive(Serialize)]
pub(crate) struct ImageFragment {
    pub debug_id: DebugId,
    #[serde(skip_serializing)]
    pub style: ServoArc<ComputedValues>,
    pub rect: Rect<Length>,
    #[serde(skip_serializing)]
    pub image_key: ImageKey,
}

impl Fragment {
    pub fn offset_inline(&mut self, offset: &Length) {
        let position = match self {
            Fragment::Box(f) => &mut f.content_rect.start_corner,
            Fragment::AbsoluteOrFixedPositioned(_) => return,
            Fragment::Anonymous(f) => &mut f.rect.start_corner,
            Fragment::Text(f) => &mut f.rect.start_corner,
            Fragment::Image(f) => &mut f.rect.start_corner,
        };

        position.inline += *offset;
    }

    pub fn print(&self, tree: &mut PrintTree) {
        match self {
            Fragment::Box(fragment) => fragment.print(tree),
            Fragment::AbsoluteOrFixedPositioned(fragment) => fragment.print(tree),
            Fragment::Anonymous(fragment) => fragment.print(tree),
            Fragment::Text(fragment) => fragment.print(tree),
            Fragment::Image(fragment) => fragment.print(tree),
        }
    }

    pub fn scrollable_overflow(&self) -> PhysicalRect<Length> {
        // FIXME(mrobinson, bug 25564): We should be using the containing block
        // here to properly convert scrollable overflow to physical geometry.
        let containing_block = PhysicalRect::zero();
        match self {
            Fragment::Box(fragment) => fragment.scrollable_overflow_for_parent(&containing_block),
            Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(),
            Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(),
            Fragment::Text(fragment) => fragment
                .rect
                .to_physical(fragment.parent_style.writing_mode, &containing_block),
            Fragment::Image(fragment) => fragment
                .rect
                .to_physical(fragment.style.writing_mode, &containing_block),
        }
    }

    pub fn is_hoisted(&self) -> bool {
        match self {
            Fragment::Box(fragment) if fragment.hoisted_fragment_id.is_some() => true,
            _ => false,
        }
    }

    pub fn hoisted_fragment_id(&self) -> Option<&HoistedFragmentId> {
        match self {
            Fragment::Box(fragment) => fragment.hoisted_fragment_id.as_ref(),
            _ => None,
        }
    }
}

impl AbsoluteOrFixedPositionedFragment {
    pub fn print(&self, tree: &mut PrintTree) {
        tree.add_item(format!("AbsoluteOrFixedPositionedFragment({:?})", self.0));
    }
}

impl AnonymousFragment {
    pub fn no_op(mode: WritingMode) -> Self {
        Self {
            debug_id: DebugId::new(),
            children: vec![],
            rect: Rect::zero(),
            mode,
            scrollable_overflow: PhysicalRect::zero(),
        }
    }

    pub fn new(rect: Rect<Length>, children: Vec<Fragment>, mode: WritingMode) -> Self {
        let content_origin = rect.start_corner.to_physical(mode);
        let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
            acc.union(
                &child
                    .scrollable_overflow()
                    .translate(content_origin.to_vector()),
            )
        });
        AnonymousFragment {
            debug_id: DebugId::new(),
            rect,
            children,
            mode,
            scrollable_overflow,
        }
    }

    pub fn print(&self, tree: &mut PrintTree) {
        tree.new_level(format!(
            "Anonymous\
                \nrect={:?}\
                \nscrollable_overflow={:?}",
            self.rect, self.scrollable_overflow
        ));

        for child in &self.children {
            child.print(tree);
        }
        tree.end_level();
    }
}

impl BoxFragment {
    pub fn new(
        tag: OpaqueNode,
        style: ServoArc<ComputedValues>,
        children: Vec<Fragment>,
        content_rect: Rect<Length>,
        padding: Sides<Length>,
        border: Sides<Length>,
        margin: Sides<Length>,
        block_margins_collapsed_with_children: CollapsedBlockMargins,
        hoisted_fragment_id: Option<HoistedFragmentId>,
    ) -> BoxFragment {
        let scrollable_overflow_from_children =
            children.iter().fold(PhysicalRect::zero(), |acc, child| {
                acc.union(&child.scrollable_overflow())
            });
        BoxFragment {
            tag,
            debug_id: DebugId::new(),
            style,
            children,
            content_rect,
            padding,
            border,
            margin,
            block_margins_collapsed_with_children,
            scrollable_overflow_from_children,
            hoisted_fragment_id,
        }
    }

    pub fn scrollable_overflow(&self) -> PhysicalRect<Length> {
        // FIXME(mrobinson, bug 25564): We should be using the containing block
        // here to properly convert scrollable overflow to physical geometry.
        let physical_padding_rect = self
            .padding_rect()
            .to_physical(self.style.writing_mode, &PhysicalRect::zero());

        let content_origin = self
            .content_rect
            .start_corner
            .to_physical(self.style.writing_mode);
        physical_padding_rect.union(
            &self
                .scrollable_overflow_from_children
                .translate(content_origin.to_vector()),
        )
    }

    pub fn padding_rect(&self) -> Rect<Length> {
        self.content_rect.inflate(&self.padding)
    }

    pub fn border_rect(&self) -> Rect<Length> {
        self.padding_rect().inflate(&self.border)
    }

    pub fn print(&self, tree: &mut PrintTree) {
        tree.new_level(format!(
            "Box\
                \ncontent={:?}\
                \npadding rect={:?}\
                \nborder rect={:?}\
                \nscrollable_overflow={:?}\
                \noverflow={:?} / {:?}\
                \nstyle={:p}\
                \nhoisted_id={:?}",
            self.content_rect,
            self.padding_rect(),
            self.border_rect(),
            self.scrollable_overflow(),
            self.style.get_box().overflow_x,
            self.style.get_box().overflow_y,
            self.style,
            self.hoisted_fragment_id,
        ));

        for child in &self.children {
            child.print(tree);
        }
        tree.end_level();
    }

    pub fn scrollable_overflow_for_parent(
        &self,
        containing_block: &PhysicalRect<Length>,
    ) -> PhysicalRect<Length> {
        let mut overflow = self
            .border_rect()
            .to_physical(self.style.writing_mode, containing_block);

        if self.style.get_box().overflow_y != ComputedOverflow::Visible &&
            self.style.get_box().overflow_x != ComputedOverflow::Visible
        {
            return overflow;
        }

        // https://www.w3.org/TR/css-overflow-3/#scrollable
        // Only include the scrollable overflow of a child box if it has overflow: visible.
        let scrollable_overflow = self.scrollable_overflow();
        let bottom_right = PhysicalPoint::new(
            overflow.max_x().max(scrollable_overflow.max_x()),
            overflow.max_y().max(scrollable_overflow.max_y()),
        );

        if self.style.get_box().overflow_y == ComputedOverflow::Visible {
            overflow.origin.y = overflow.origin.y.min(scrollable_overflow.origin.y);
            overflow.size.height = bottom_right.y - overflow.origin.y;
        }

        if self.style.get_box().overflow_x == ComputedOverflow::Visible {
            overflow.origin.x = overflow.origin.x.min(scrollable_overflow.origin.x);
            overflow.size.width = bottom_right.x - overflow.origin.x;
        }

        overflow
    }
}

impl TextFragment {
    pub fn print(&self, tree: &mut PrintTree) {
        tree.add_item(format!(
            "Text num_glyphs={}",
            self.glyphs
                .iter()
                .map(|glyph_store| glyph_store.len().0)
                .sum::<isize>()
        ));
    }
}

impl ImageFragment {
    pub fn print(&self, tree: &mut PrintTree) {
        tree.add_item(format!(
            "Image\
                \nrect={:?}",
            self.rect
        ));
    }
}

impl CollapsedBlockMargins {
    pub fn from_margin(margin: &Sides<Length>) -> Self {
        Self {
            collapsed_through: false,
            start: CollapsedMargin::new(margin.block_start),
            end: CollapsedMargin::new(margin.block_end),
        }
    }

    pub fn zero() -> Self {
        Self {
            collapsed_through: false,
            start: CollapsedMargin::zero(),
            end: CollapsedMargin::zero(),
        }
    }
}

impl CollapsedMargin {
    pub fn zero() -> Self {
        Self {
            max_positive: Length::zero(),
            min_negative: Length::zero(),
        }
    }

    pub fn new(margin: Length) -> Self {
        Self {
            max_positive: margin.max(Length::zero()),
            min_negative: margin.min(Length::zero()),
        }
    }

    pub fn adjoin(&self, other: &Self) -> Self {
        Self {
            max_positive: self.max_positive.max(other.max_positive),
            min_negative: self.min_negative.min(other.min_negative),
        }
    }

    pub fn adjoin_assign(&mut self, other: &Self) {
        *self = self.adjoin(other);
    }

    pub fn solve(&self) -> Length {
        self.max_positive + self.min_negative
    }
}

#[cfg(not(debug_assertions))]
#[derive(Clone)]
pub struct DebugId;

#[cfg(debug_assertions)]
#[derive(Clone, Serialize)]
#[serde(transparent)]
pub struct DebugId(u16);

#[cfg(not(debug_assertions))]
impl DebugId {
    pub fn new() -> DebugId {
        DebugId
    }
}

#[cfg(debug_assertions)]
impl DebugId {
    pub fn new() -> DebugId {
        DebugId(layout_debug::generate_unique_debug_id())
    }
}

#[cfg(not(debug_assertions))]
impl Serialize for DebugId {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(&format!("{:p}", &self))
    }
}
<|endoftext|>


<commit_before>use core::fmt;
use spin::Mutex;
use volatile::Volatile;
use lazy_static::lazy_static;

lazy_static! {
    /// A global `Writer` instance that can be used for printing to the VGA text buffer.
    ///
    /// Used by the `print!` and `println!` macros.
    pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer {
        column_position: 0,
        color_code: ColorCode::new(Color::Yellow, Color::Black),
        buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
    });
}

/// The standard color palette in VGA text mode.
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Magenta = 5,
    Brown = 6,
    LightGray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    Pink = 13,
    Yellow = 14,
    White = 15,
}

/// A combination of a foreground and a background color.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct ColorCode(u8);

impl ColorCode {
    /// Create a new `ColorCode` with the given foreground and background colors.
    fn new(foreground: Color, background: Color) -> ColorCode {
        ColorCode((background as u8) << 4 | (foreground as u8))
    }
}

/// A screen character in the VGA text buffer, consisting of an ASCII character and a `ColorCode`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
    ascii_character: u8,
    color_code: ColorCode,
}

/// The height of the text buffer (normally 25 lines).
const BUFFER_HEIGHT: usize = 25;
/// The width of the text buffer (normally 80 columns).
const BUFFER_WIDTH: usize = 80;

/// A structure representing the VGA text buffer.
struct Buffer {
    chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}

/// A writer type that allows writing ASCII bytes and strings to an underlying `Buffer`.
///
/// Wraps lines at `BUFFER_WIDTH`. Supports newline characters and implements the
/// `core::fmt::Write` trait.
pub struct Writer {
    column_position: usize,
    color_code: ColorCode,
    buffer: &'static mut Buffer,
}

impl Writer {
    /// Writes an ASCII byte to the buffer.
    ///
    /// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character.
    pub fn write_byte(&mut self, byte: u8) {
        match byte {
            b'\n' => self.new_line(),
            byte => {
                if self.column_position >= BUFFER_WIDTH {
                    self.new_line();
                }

                let row = BUFFER_HEIGHT - 1;
                let col = self.column_position;

                let color_code = self.color_code;
                self.buffer.chars[row][col].write(ScreenChar {
                    ascii_character: byte,
                    color_code,
                });
                self.column_position += 1;
            }
        }
    }

    /// Writes the given ASCII string to the buffer.
    ///
    /// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character. Does **not**
    /// support strings with non-ASCII characters, since they can't be printed in the VGA text
    /// mode.
    fn write_string(&mut self, s: &str) {
        for byte in s.bytes() {
            match byte {
                // printable ASCII byte or newline
                0x20...0x7e | b'\n' => self.write_byte(byte),
                // not part of printable ASCII range
                _ => self.write_byte(0xfe),
            }
        }
    }

    /// Shifts all lines one line up and clears the last row.
    fn new_line(&mut self) {
        for row in 1..BUFFER_HEIGHT {
            for col in 0..BUFFER_WIDTH {
                let character = self.buffer.chars[row][col].read();
                self.buffer.chars[row - 1][col].write(character);
            }
        }
        self.clear_row(BUFFER_HEIGHT - 1);
        self.column_position = 0;
    }

    /// Clears a row by overwriting it with blank characters.
    fn clear_row(&mut self, row: usize) {
        let blank = ScreenChar {
            ascii_character: b' ',
            color_code: self.color_code,
        };
        for col in 0..BUFFER_WIDTH {
            self.buffer.chars[row][col].write(blank);
        }
    }
}

impl fmt::Write for Writer {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.write_string(s);
        Ok(())
    }
}

/// Like the `print!` macro in the standard library, but prints to the VGA text buffer.
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ($crate::vga_buffer::print(format_args!($($arg)*)));
}

/// Like the `print!` macro in the standard library, but prints to the VGA text buffer.
#[macro_export]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
}

/// Prints the given formatted string to the VGA text buffer through the global `WRITER` instance.
pub fn print(args: fmt::Arguments) {
    use core::fmt::Write;
    use x86_64::instructions::interrupts;

    interrupts::without_interrupts(|| {
        WRITER.lock().write_fmt(args).unwrap();
    });
}

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

    fn construct_writer() -> Writer {
        use std::boxed::Box;

        let buffer = construct_buffer();
        Writer {
            column_position: 0,
            color_code: ColorCode::new(Color::Blue, Color::Magenta),
            buffer: Box::leak(Box::new(buffer)),
        }
    }

    fn construct_buffer() -> Buffer {
        use array_init::array_init;

        Buffer {
            chars: array_init(|_| array_init(|_| Volatile::new(empty_char()))),
        }
    }

    fn empty_char() -> ScreenChar {
        ScreenChar {
            ascii_character: b' ',
            color_code: ColorCode::new(Color::Green, Color::Brown),
        }
    }

    #[test]
    fn write_byte() {
        let mut writer = construct_writer();
        writer.write_byte(b'X');
        writer.write_byte(b'Y');

        for (i, row) in writer.buffer.chars.iter().enumerate() {
            for (j, screen_char) in row.iter().enumerate() {
                let screen_char = screen_char.read();
                if i == BUFFER_HEIGHT - 1 && j == 0 {
                    assert_eq!(screen_char.ascii_character, b'X');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else if i == BUFFER_HEIGHT - 1 && j == 1 {
                    assert_eq!(screen_char.ascii_character, b'Y');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else {
                    assert_eq!(screen_char, empty_char());
                }
            }
        }
    }

    #[test]
    fn write_formatted() {
        use core::fmt::Write;

        let mut writer = construct_writer();
        writeln!(&mut writer, "a").unwrap();
        writeln!(&mut writer, "b{}", "c").unwrap();

        for (i, row) in writer.buffer.chars.iter().enumerate() {
            for (j, screen_char) in row.iter().enumerate() {
                let screen_char = screen_char.read();
                if i == BUFFER_HEIGHT - 3 && j == 0 {
                    assert_eq!(screen_char.ascii_character, b'a');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else if i == BUFFER_HEIGHT - 2 && j == 0 {
                    assert_eq!(screen_char.ascii_character, b'b');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else if i == BUFFER_HEIGHT - 2 && j == 1 {
                    assert_eq!(screen_char.ascii_character, b'c');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else if i >= BUFFER_HEIGHT - 2 {
                    assert_eq!(screen_char.ascii_character, b' ');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else {
                    assert_eq!(screen_char, empty_char());
                }
            }
        }
    }
}
<commit_msg>Rename vga_buffer::print function to avoid name clash with macro<commit_after>use core::fmt;
use spin::Mutex;
use volatile::Volatile;
use lazy_static::lazy_static;

lazy_static! {
    /// A global `Writer` instance that can be used for printing to the VGA text buffer.
    ///
    /// Used by the `print!` and `println!` macros.
    pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer {
        column_position: 0,
        color_code: ColorCode::new(Color::Yellow, Color::Black),
        buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
    });
}

/// The standard color palette in VGA text mode.
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Magenta = 5,
    Brown = 6,
    LightGray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    Pink = 13,
    Yellow = 14,
    White = 15,
}

/// A combination of a foreground and a background color.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct ColorCode(u8);

impl ColorCode {
    /// Create a new `ColorCode` with the given foreground and background colors.
    fn new(foreground: Color, background: Color) -> ColorCode {
        ColorCode((background as u8) << 4 | (foreground as u8))
    }
}

/// A screen character in the VGA text buffer, consisting of an ASCII character and a `ColorCode`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
    ascii_character: u8,
    color_code: ColorCode,
}

/// The height of the text buffer (normally 25 lines).
const BUFFER_HEIGHT: usize = 25;
/// The width of the text buffer (normally 80 columns).
const BUFFER_WIDTH: usize = 80;

/// A structure representing the VGA text buffer.
struct Buffer {
    chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}

/// A writer type that allows writing ASCII bytes and strings to an underlying `Buffer`.
///
/// Wraps lines at `BUFFER_WIDTH`. Supports newline characters and implements the
/// `core::fmt::Write` trait.
pub struct Writer {
    column_position: usize,
    color_code: ColorCode,
    buffer: &'static mut Buffer,
}

impl Writer {
    /// Writes an ASCII byte to the buffer.
    ///
    /// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character.
    pub fn write_byte(&mut self, byte: u8) {
        match byte {
            b'\n' => self.new_line(),
            byte => {
                if self.column_position >= BUFFER_WIDTH {
                    self.new_line();
                }

                let row = BUFFER_HEIGHT - 1;
                let col = self.column_position;

                let color_code = self.color_code;
                self.buffer.chars[row][col].write(ScreenChar {
                    ascii_character: byte,
                    color_code,
                });
                self.column_position += 1;
            }
        }
    }

    /// Writes the given ASCII string to the buffer.
    ///
    /// Wraps lines at `BUFFER_WIDTH`. Supports the `\n` newline character. Does **not**
    /// support strings with non-ASCII characters, since they can't be printed in the VGA text
    /// mode.
    fn write_string(&mut self, s: &str) {
        for byte in s.bytes() {
            match byte {
                // printable ASCII byte or newline
                0x20...0x7e | b'\n' => self.write_byte(byte),
                // not part of printable ASCII range
                _ => self.write_byte(0xfe),
            }
        }
    }

    /// Shifts all lines one line up and clears the last row.
    fn new_line(&mut self) {
        for row in 1..BUFFER_HEIGHT {
            for col in 0..BUFFER_WIDTH {
                let character = self.buffer.chars[row][col].read();
                self.buffer.chars[row - 1][col].write(character);
            }
        }
        self.clear_row(BUFFER_HEIGHT - 1);
        self.column_position = 0;
    }

    /// Clears a row by overwriting it with blank characters.
    fn clear_row(&mut self, row: usize) {
        let blank = ScreenChar {
            ascii_character: b' ',
            color_code: self.color_code,
        };
        for col in 0..BUFFER_WIDTH {
            self.buffer.chars[row][col].write(blank);
        }
    }
}

impl fmt::Write for Writer {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.write_string(s);
        Ok(())
    }
}

/// Like the `print!` macro in the standard library, but prints to the VGA text buffer.
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ($crate::vga_buffer::_print(format_args!($($arg)*)));
}

/// Like the `print!` macro in the standard library, but prints to the VGA text buffer.
#[macro_export]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
}

/// Prints the given formatted string to the VGA text buffer through the global `WRITER` instance.
pub fn _print(args: fmt::Arguments) {
    use core::fmt::Write;
    use x86_64::instructions::interrupts;

    interrupts::without_interrupts(|| {
        WRITER.lock().write_fmt(args).unwrap();
    });
}

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

    fn construct_writer() -> Writer {
        use std::boxed::Box;

        let buffer = construct_buffer();
        Writer {
            column_position: 0,
            color_code: ColorCode::new(Color::Blue, Color::Magenta),
            buffer: Box::leak(Box::new(buffer)),
        }
    }

    fn construct_buffer() -> Buffer {
        use array_init::array_init;

        Buffer {
            chars: array_init(|_| array_init(|_| Volatile::new(empty_char()))),
        }
    }

    fn empty_char() -> ScreenChar {
        ScreenChar {
            ascii_character: b' ',
            color_code: ColorCode::new(Color::Green, Color::Brown),
        }
    }

    #[test]
    fn write_byte() {
        let mut writer = construct_writer();
        writer.write_byte(b'X');
        writer.write_byte(b'Y');

        for (i, row) in writer.buffer.chars.iter().enumerate() {
            for (j, screen_char) in row.iter().enumerate() {
                let screen_char = screen_char.read();
                if i == BUFFER_HEIGHT - 1 && j == 0 {
                    assert_eq!(screen_char.ascii_character, b'X');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else if i == BUFFER_HEIGHT - 1 && j == 1 {
                    assert_eq!(screen_char.ascii_character, b'Y');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else {
                    assert_eq!(screen_char, empty_char());
                }
            }
        }
    }

    #[test]
    fn write_formatted() {
        use core::fmt::Write;

        let mut writer = construct_writer();
        writeln!(&mut writer, "a").unwrap();
        writeln!(&mut writer, "b{}", "c").unwrap();

        for (i, row) in writer.buffer.chars.iter().enumerate() {
            for (j, screen_char) in row.iter().enumerate() {
                let screen_char = screen_char.read();
                if i == BUFFER_HEIGHT - 3 && j == 0 {
                    assert_eq!(screen_char.ascii_character, b'a');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else if i == BUFFER_HEIGHT - 2 && j == 0 {
                    assert_eq!(screen_char.ascii_character, b'b');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else if i == BUFFER_HEIGHT - 2 && j == 1 {
                    assert_eq!(screen_char.ascii_character, b'c');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else if i >= BUFFER_HEIGHT - 2 {
                    assert_eq!(screen_char.ascii_character, b' ');
                    assert_eq!(screen_char.color_code, writer.color_code);
                } else {
                    assert_eq!(screen_char, empty_char());
                }
            }
        }
    }
}
<|endoftext|>