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

use std::os::unix::io::RawFd;
use std::sync::Arc;

use byteorder::{ByteOrder, LittleEndian};
use sync::Mutex;

use crate::pci::pci_configuration::{
    PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
};
use crate::pci::pci_device::PciDevice;
use crate::BusDevice;

// A PciDevice that holds the root hub's configuration.
struct PciRootConfiguration {
    config: PciConfiguration,
}

impl PciDevice for PciRootConfiguration {
    fn debug_label(&self) -> String {
        "pci root device".to_owned()
    }
    fn keep_fds(&self) -> Vec<RawFd> {
        Vec::new()
    }
    fn config_registers(&self) -> &PciConfiguration {
        &self.config
    }

    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
        &mut self.config
    }

    fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {}

    fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
}

/// Emulates the PCI Root bridge.
pub struct PciRoot {
    /// Bus configuration for the root device.
    root_configuration: PciRootConfiguration,
    /// Devices attached to this bridge.
    devices: Vec<Arc<Mutex<dyn BusDevice>>>,
}

impl PciRoot {
    /// Create an empty PCI root bus.
    pub fn new() -> Self {
        PciRoot {
            root_configuration: PciRootConfiguration {
                config: PciConfiguration::new(
                    0,
                    0,
                    PciClassCode::BridgeDevice,
                    &PciBridgeSubclass::HostBridge,
                    None,
                    PciHeaderType::Bridge,
                    0,
                    0,
                ),
            },
            devices: Vec::new(),
        }
    }

    /// Add a `device` to this root PCI bus.
    pub fn add_device(&mut self, device: Arc<Mutex<dyn BusDevice>>) {
        self.devices.push(device);
    }

    pub fn config_space_read(
        &self,
        bus: usize,
        device: usize,
        _function: usize,
        register: usize,
    ) -> u32 {
        // Only support one bus.
        if bus != 0 {
            return 0xffff_ffff;
        }

        match device {
            0 => {
                // If bus and device are both zero, then read from the root config.
                self.root_configuration.config_register_read(register)
            }
            dev_num => self
                .devices
                .get(dev_num - 1)
                .map_or(0xffff_ffff, |d| d.lock().config_register_read(register)),
        }
    }

    pub fn config_space_write(
        &mut self,
        bus: usize,
        device: usize,
        _function: usize,
        register: usize,
        offset: u64,
        data: &[u8],
    ) {
        if offset as usize + data.len() > 4 {
            return;
        }

        // Only support one bus.
        if bus != 0 {
            return;
        }

        match device {
            0 => {
                // If bus and device are both zero, then read from the root config.
                self.root_configuration
                    .config_register_write(register, offset, data);
            }
            dev_num => {
                // dev_num is 1-indexed here.
                if let Some(d) = self.devices.get(dev_num - 1) {
                    d.lock().config_register_write(register, offset, data);
                }
            }
        }
    }
}

/// Emulates PCI configuration access mechanism #1 (I/O ports 0xcf8 and 0xcfc).
pub struct PciConfigIo {
    /// PCI root bridge.
    pci_root: PciRoot,
    /// Current address to read/write from (0xcf8 register, litte endian).
    config_address: u32,
}

impl PciConfigIo {
    pub fn new(pci_root: PciRoot) -> Self {
        PciConfigIo {
            pci_root,
            config_address: 0,
        }
    }

    fn config_space_read(&self) -> u32 {
        let enabled = (self.config_address & 0x8000_0000) != 0;
        if !enabled {
            return 0xffff_ffff;
        }

        let (bus, device, function, register) =
            parse_config_address(self.config_address & !0x8000_0000);
        self.pci_root
            .config_space_read(bus, device, function, register)
    }

    fn config_space_write(&mut self, offset: u64, data: &[u8]) {
        let enabled = (self.config_address & 0x8000_0000) != 0;
        if !enabled {
            return;
        }

        let (bus, device, function, register) =
            parse_config_address(self.config_address & !0x8000_0000);
        self.pci_root
            .config_space_write(bus, device, function, register, offset, data)
    }

    fn set_config_address(&mut self, offset: u64, data: &[u8]) {
        if offset as usize + data.len() > 4 {
            return;
        }
        let (mask, value): (u32, u32) = match data.len() {
            1 => (
                0x0000_00ff << (offset * 8),
                (data[0] as u32) << (offset * 8),
            ),
            2 => (
                0x0000_ffff << (offset * 16),
                ((data[1] as u32) << 8 | data[0] as u32) << (offset * 16),
            ),
            4 => (0xffff_ffff, LittleEndian::read_u32(data)),
            _ => return,
        };
        self.config_address = (self.config_address & !mask) | value;
    }
}

impl BusDevice for PciConfigIo {
    fn debug_label(&self) -> String {
        format!("pci config io-port 0x{:03x}", self.config_address)
    }

    fn read(&mut self, offset: u64, data: &mut [u8]) {
        // `offset` is relative to 0xcf8
        let value = match offset {
            0...3 => self.config_address,
            4...7 => self.config_space_read(),
            _ => 0xffff_ffff,
        };

        // Only allow reads to the register boundary.
        let start = offset as usize % 4;
        let end = start + data.len();
        if end <= 4 {
            for i in start..end {
                data[i - start] = (value >> (i * 8)) as u8;
            }
        } else {
            for d in data {
                *d = 0xff;
            }
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        // `offset` is relative to 0xcf8
        match offset {
            o @ 0...3 => self.set_config_address(o, data),
            o @ 4...7 => self.config_space_write(o - 4, data),
            _ => (),
        };
    }
}

/// Emulates PCI memory-mapped configuration access mechanism.
pub struct PciConfigMmio {
    /// PCI root bridge.
    pci_root: PciRoot,
}

impl PciConfigMmio {
    pub fn new(pci_root: PciRoot) -> Self {
        PciConfigMmio { pci_root }
    }

    fn config_space_read(&self, config_address: u32) -> u32 {
        let (bus, device, function, register) = parse_config_address(config_address);
        self.pci_root
            .config_space_read(bus, device, function, register)
    }

    fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
        let (bus, device, function, register) = parse_config_address(config_address);
        self.pci_root
            .config_space_write(bus, device, function, register, offset, data)
    }
}

impl BusDevice for PciConfigMmio {
    fn debug_label(&self) -> String {
        "pci config mmio".to_owned()
    }

    fn read(&mut self, offset: u64, data: &mut [u8]) {
        // Only allow reads to the register boundary.
        let start = offset as usize % 4;
        let end = start + data.len();
        if end > 4 || offset > u32::max_value() as u64 {
            for d in data {
                *d = 0xff;
            }
            return;
        }

        let value = self.config_space_read(offset as u32);
        for i in start..end {
            data[i - start] = (value >> (i * 8)) as u8;
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        if offset > u32::max_value() as u64 {
            return;
        }
        self.config_space_write(offset as u32, offset % 4, data)
    }
}

// Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) {
    const BUS_NUMBER_OFFSET: usize = 16;
    const BUS_NUMBER_MASK: u32 = 0x00ff;
    const DEVICE_NUMBER_OFFSET: usize = 11;
    const DEVICE_NUMBER_MASK: u32 = 0x1f;
    const FUNCTION_NUMBER_OFFSET: usize = 8;
    const FUNCTION_NUMBER_MASK: u32 = 0x07;
    const REGISTER_NUMBER_OFFSET: usize = 2;
    const REGISTER_NUMBER_MASK: u32 = 0x3f;

    let bus_number = ((config_address >> BUS_NUMBER_OFFSET) & BUS_NUMBER_MASK) as usize;
    let device_number = ((config_address >> DEVICE_NUMBER_OFFSET) & DEVICE_NUMBER_MASK) as usize;
    let function_number =
        ((config_address >> FUNCTION_NUMBER_OFFSET) & FUNCTION_NUMBER_MASK) as usize;
    let register_number =
        ((config_address >> REGISTER_NUMBER_OFFSET) & REGISTER_NUMBER_MASK) as usize;

    (bus_number, device_number, function_number, register_number)
}
<commit_msg>devices: pci: use header type 0 for host bridge<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::os::unix::io::RawFd;
use std::sync::Arc;

use byteorder::{ByteOrder, LittleEndian};
use sync::Mutex;

use crate::pci::pci_configuration::{
    PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
};
use crate::pci::pci_device::PciDevice;
use crate::BusDevice;

// A PciDevice that holds the root hub's configuration.
struct PciRootConfiguration {
    config: PciConfiguration,
}

impl PciDevice for PciRootConfiguration {
    fn debug_label(&self) -> String {
        "pci root device".to_owned()
    }
    fn keep_fds(&self) -> Vec<RawFd> {
        Vec::new()
    }
    fn config_registers(&self) -> &PciConfiguration {
        &self.config
    }

    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
        &mut self.config
    }

    fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {}

    fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
}

/// Emulates the PCI Root bridge.
pub struct PciRoot {
    /// Bus configuration for the root device.
    root_configuration: PciRootConfiguration,
    /// Devices attached to this bridge.
    devices: Vec<Arc<Mutex<dyn BusDevice>>>,
}

impl PciRoot {
    /// Create an empty PCI root bus.
    pub fn new() -> Self {
        PciRoot {
            root_configuration: PciRootConfiguration {
                config: PciConfiguration::new(
                    0,
                    0,
                    PciClassCode::BridgeDevice,
                    &PciBridgeSubclass::HostBridge,
                    None,
                    PciHeaderType::Device,
                    0,
                    0,
                ),
            },
            devices: Vec::new(),
        }
    }

    /// Add a `device` to this root PCI bus.
    pub fn add_device(&mut self, device: Arc<Mutex<dyn BusDevice>>) {
        self.devices.push(device);
    }

    pub fn config_space_read(
        &self,
        bus: usize,
        device: usize,
        _function: usize,
        register: usize,
    ) -> u32 {
        // Only support one bus.
        if bus != 0 {
            return 0xffff_ffff;
        }

        match device {
            0 => {
                // If bus and device are both zero, then read from the root config.
                self.root_configuration.config_register_read(register)
            }
            dev_num => self
                .devices
                .get(dev_num - 1)
                .map_or(0xffff_ffff, |d| d.lock().config_register_read(register)),
        }
    }

    pub fn config_space_write(
        &mut self,
        bus: usize,
        device: usize,
        _function: usize,
        register: usize,
        offset: u64,
        data: &[u8],
    ) {
        if offset as usize + data.len() > 4 {
            return;
        }

        // Only support one bus.
        if bus != 0 {
            return;
        }

        match device {
            0 => {
                // If bus and device are both zero, then read from the root config.
                self.root_configuration
                    .config_register_write(register, offset, data);
            }
            dev_num => {
                // dev_num is 1-indexed here.
                if let Some(d) = self.devices.get(dev_num - 1) {
                    d.lock().config_register_write(register, offset, data);
                }
            }
        }
    }
}

/// Emulates PCI configuration access mechanism #1 (I/O ports 0xcf8 and 0xcfc).
pub struct PciConfigIo {
    /// PCI root bridge.
    pci_root: PciRoot,
    /// Current address to read/write from (0xcf8 register, litte endian).
    config_address: u32,
}

impl PciConfigIo {
    pub fn new(pci_root: PciRoot) -> Self {
        PciConfigIo {
            pci_root,
            config_address: 0,
        }
    }

    fn config_space_read(&self) -> u32 {
        let enabled = (self.config_address & 0x8000_0000) != 0;
        if !enabled {
            return 0xffff_ffff;
        }

        let (bus, device, function, register) =
            parse_config_address(self.config_address & !0x8000_0000);
        self.pci_root
            .config_space_read(bus, device, function, register)
    }

    fn config_space_write(&mut self, offset: u64, data: &[u8]) {
        let enabled = (self.config_address & 0x8000_0000) != 0;
        if !enabled {
            return;
        }

        let (bus, device, function, register) =
            parse_config_address(self.config_address & !0x8000_0000);
        self.pci_root
            .config_space_write(bus, device, function, register, offset, data)
    }

    fn set_config_address(&mut self, offset: u64, data: &[u8]) {
        if offset as usize + data.len() > 4 {
            return;
        }
        let (mask, value): (u32, u32) = match data.len() {
            1 => (
                0x0000_00ff << (offset * 8),
                (data[0] as u32) << (offset * 8),
            ),
            2 => (
                0x0000_ffff << (offset * 16),
                ((data[1] as u32) << 8 | data[0] as u32) << (offset * 16),
            ),
            4 => (0xffff_ffff, LittleEndian::read_u32(data)),
            _ => return,
        };
        self.config_address = (self.config_address & !mask) | value;
    }
}

impl BusDevice for PciConfigIo {
    fn debug_label(&self) -> String {
        format!("pci config io-port 0x{:03x}", self.config_address)
    }

    fn read(&mut self, offset: u64, data: &mut [u8]) {
        // `offset` is relative to 0xcf8
        let value = match offset {
            0...3 => self.config_address,
            4...7 => self.config_space_read(),
            _ => 0xffff_ffff,
        };

        // Only allow reads to the register boundary.
        let start = offset as usize % 4;
        let end = start + data.len();
        if end <= 4 {
            for i in start..end {
                data[i - start] = (value >> (i * 8)) as u8;
            }
        } else {
            for d in data {
                *d = 0xff;
            }
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        // `offset` is relative to 0xcf8
        match offset {
            o @ 0...3 => self.set_config_address(o, data),
            o @ 4...7 => self.config_space_write(o - 4, data),
            _ => (),
        };
    }
}

/// Emulates PCI memory-mapped configuration access mechanism.
pub struct PciConfigMmio {
    /// PCI root bridge.
    pci_root: PciRoot,
}

impl PciConfigMmio {
    pub fn new(pci_root: PciRoot) -> Self {
        PciConfigMmio { pci_root }
    }

    fn config_space_read(&self, config_address: u32) -> u32 {
        let (bus, device, function, register) = parse_config_address(config_address);
        self.pci_root
            .config_space_read(bus, device, function, register)
    }

    fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
        let (bus, device, function, register) = parse_config_address(config_address);
        self.pci_root
            .config_space_write(bus, device, function, register, offset, data)
    }
}

impl BusDevice for PciConfigMmio {
    fn debug_label(&self) -> String {
        "pci config mmio".to_owned()
    }

    fn read(&mut self, offset: u64, data: &mut [u8]) {
        // Only allow reads to the register boundary.
        let start = offset as usize % 4;
        let end = start + data.len();
        if end > 4 || offset > u32::max_value() as u64 {
            for d in data {
                *d = 0xff;
            }
            return;
        }

        let value = self.config_space_read(offset as u32);
        for i in start..end {
            data[i - start] = (value >> (i * 8)) as u8;
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        if offset > u32::max_value() as u64 {
            return;
        }
        self.config_space_write(offset as u32, offset % 4, data)
    }
}

// Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) {
    const BUS_NUMBER_OFFSET: usize = 16;
    const BUS_NUMBER_MASK: u32 = 0x00ff;
    const DEVICE_NUMBER_OFFSET: usize = 11;
    const DEVICE_NUMBER_MASK: u32 = 0x1f;
    const FUNCTION_NUMBER_OFFSET: usize = 8;
    const FUNCTION_NUMBER_MASK: u32 = 0x07;
    const REGISTER_NUMBER_OFFSET: usize = 2;
    const REGISTER_NUMBER_MASK: u32 = 0x3f;

    let bus_number = ((config_address >> BUS_NUMBER_OFFSET) & BUS_NUMBER_MASK) as usize;
    let device_number = ((config_address >> DEVICE_NUMBER_OFFSET) & DEVICE_NUMBER_MASK) as usize;
    let function_number =
        ((config_address >> FUNCTION_NUMBER_OFFSET) & FUNCTION_NUMBER_MASK) as usize;
    let register_number =
        ((config_address >> REGISTER_NUMBER_OFFSET) & REGISTER_NUMBER_MASK) as usize;

    (bus_number, device_number, function_number, register_number)
}
<|endoftext|>


<commit_before>use postgres::Connection;
use postgres::rows::Row;
use postgres::error::Error as PgError;
use error::ScurryError;
use models::ScurryMetadata;
use versions::Version;
use util;
use connection::ScurryConnection;
use postgres::transaction::Transaction;

const METADATA_EXISTS: &'static str = "
SELECT EXISTS (
    SELECT 1 FROM pg_catalog.pg_class c
    where c.relname = '_scurry'
    and c.relkind = 'r');";

const CREATE_METADATA_TABLE: &'static str = "
CREATE TABLE _scurry (
    id serial,
    migration_date TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
    script_hash TEXT NOT NULL,
    script_name TEXT NOT NULL,
    script_version TEXT NOT NULL
);";

const INSERT_HISTORY_LINE: &'static str = "INSERT INTO _scurry(script_hash, script_name, script_version) values($1, $2, $3);";

const GET_ALL_REVISIONS: &'static str = "SELECT id, migration_date, script_hash, script_name, script_version FROM _scurry ORDER BY script_version ASC;";

const ACQUIRE_LOCK: &'static str = "LOCK TABLE _scurry IN ACCESS EXCLUSIVE MODE;";

pub struct PostgresScurryConnection<'a> {
    xact: Transaction<'a>
}

impl<'a> PostgresScurryConnection<'a> {

    fn history_table_exists(&self) -> Result<bool, ScurryError> {
        let exists = try!(self.xact.query(METADATA_EXISTS, &[]));
        for row in &exists {
            let res: bool = row.get(0);
            return Ok(res);
        }
        Ok(false)
    }

    fn write_history_line(&self, version: &Version) -> Result<(), ScurryError> {
        try!(self.xact.execute(INSERT_HISTORY_LINE,
                               &[&version.hash, &version.name, &version.version]));
        Ok(())
    }

    fn lock_table(&self) -> Result<(), ScurryError> {
        let exists = try!(self.history_table_exists());
        if !exists {
            try!(self.create_metadata_table());
        }
        try!(self.xact.execute(ACQUIRE_LOCK, &[]));
        info!("Locked table for updating");
        Ok(())
    }

    pub fn new(conn: &'a Connection) -> Result<PostgresScurryConnection<'a>, ScurryError> {
        let xact = try!(conn.transaction());
        let conn = PostgresScurryConnection { xact: xact };
        try!(conn.lock_table());
        Ok(conn)
    }
}

impl<'a> ScurryConnection for PostgresScurryConnection<'a> {
    fn create_metadata_table(&self) -> Result<(), ScurryError> {
        try!(self.xact.execute(CREATE_METADATA_TABLE, &[]));
        info!("Metadata table created");
        Ok(())
    }

    fn apply_migration(&self, version: &Version) -> Result<(), ScurryError> {
        let xact = try!(self.xact.transaction());
        let contents = try!(util::get_file_contents(&version.path));
        try!(self.xact.execute(&contents, &[]));
        try!(self.write_history_line(&version));
        try!(xact.commit());
        Ok(())
    }

    fn get_history(&self) -> Result<Vec<ScurryMetadata>, ScurryError> {
        let revisions_query = try!(self.xact.query(GET_ALL_REVISIONS, &[]));
        Ok(revisions_query.iter().map(ScurryMetadata::from).collect::<Vec<_>>())
    }

    fn commit(self) -> Result<(), ScurryError> {
        try!(self.xact.commit());
        Ok(())
    }

    fn rollback(self) -> Result<(), ScurryError> {
        try!(self.xact.finish());
        Ok(())
    }
}

impl<'a> From<Row<'a>> for ScurryMetadata {
    fn from(row: Row<'a>) -> ScurryMetadata {
        ScurryMetadata {
            id: row.get(0),
            migration_date: row.get(1),
            script_hash: row.get(2),
            script_name: row.get(3),
            script_version: row.get(4),
        }
    }
}

impl From<PgError> for ScurryError {
    fn from(e: PgError) -> ScurryError {
        ScurryError::Sql(Box::new(e))
    }
}
<commit_msg>Switch to batch_execute for better DDL handling<commit_after>use postgres::Connection;
use postgres::rows::Row;
use postgres::error::Error as PgError;
use error::ScurryError;
use models::ScurryMetadata;
use versions::Version;
use util;
use connection::ScurryConnection;
use postgres::transaction::Transaction;

const METADATA_EXISTS: &'static str = "
SELECT EXISTS (
    SELECT 1 FROM pg_catalog.pg_class c
    where c.relname = '_scurry'
    and c.relkind = 'r');";

const CREATE_METADATA_TABLE: &'static str = "
CREATE TABLE _scurry (
    id serial,
    migration_date TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT (now() AT TIME ZONE 'utc'),
    script_hash TEXT NOT NULL,
    script_name TEXT NOT NULL,
    script_version TEXT NOT NULL
);";

const INSERT_HISTORY_LINE: &'static str = "INSERT INTO _scurry(script_hash, script_name, script_version) values($1, $2, $3);";

const GET_ALL_REVISIONS: &'static str = "SELECT id, migration_date, script_hash, script_name, script_version FROM _scurry ORDER BY script_version ASC;";

const ACQUIRE_LOCK: &'static str = "LOCK TABLE _scurry IN ACCESS EXCLUSIVE MODE;";

pub struct PostgresScurryConnection<'a> {
    xact: Transaction<'a>
}

impl<'a> PostgresScurryConnection<'a> {

    fn history_table_exists(&self) -> Result<bool, ScurryError> {
        let exists = try!(self.xact.query(METADATA_EXISTS, &[]));
        for row in &exists {
            let res: bool = row.get(0);
            return Ok(res);
        }
        Ok(false)
    }

    fn write_history_line(&self, version: &Version) -> Result<(), ScurryError> {
        try!(self.xact.execute(INSERT_HISTORY_LINE,
                               &[&version.hash, &version.name, &version.version]));
        Ok(())
    }

    fn lock_table(&self) -> Result<(), ScurryError> {
        let exists = try!(self.history_table_exists());
        if !exists {
            try!(self.create_metadata_table());
        }
        try!(self.xact.execute(ACQUIRE_LOCK, &[]));
        info!("Locked table for updating");
        Ok(())
    }

    pub fn new(conn: &'a Connection) -> Result<PostgresScurryConnection<'a>, ScurryError> {
        let xact = try!(conn.transaction());
        let conn = PostgresScurryConnection { xact: xact };
        try!(conn.lock_table());
        Ok(conn)
    }
}

impl<'a> ScurryConnection for PostgresScurryConnection<'a> {
    fn create_metadata_table(&self) -> Result<(), ScurryError> {
        try!(self.xact.batch_execute(CREATE_METADATA_TABLE));
        info!("Metadata table created");
        Ok(())
    }

    fn apply_migration(&self, version: &Version) -> Result<(), ScurryError> {
        let xact = try!(self.xact.transaction());
        let contents = try!(util::get_file_contents(&version.path));
        try!(self.xact.batch_execute(&contents));
        try!(self.write_history_line(&version));
        try!(xact.commit());
        Ok(())
    }

    fn get_history(&self) -> Result<Vec<ScurryMetadata>, ScurryError> {
        let revisions_query = try!(self.xact.query(GET_ALL_REVISIONS, &[]));
        Ok(revisions_query.iter().map(ScurryMetadata::from).collect::<Vec<_>>())
    }

    fn commit(self) -> Result<(), ScurryError> {
        try!(self.xact.commit());
        Ok(())
    }

    fn rollback(self) -> Result<(), ScurryError> {
        try!(self.xact.finish());
        Ok(())
    }
}

impl<'a> From<Row<'a>> for ScurryMetadata {
    fn from(row: Row<'a>) -> ScurryMetadata {
        ScurryMetadata {
            id: row.get(0),
            migration_date: row.get(1),
            script_hash: row.get(2),
            script_name: row.get(3),
            script_version: row.get(4),
        }
    }
}

impl From<PgError> for ScurryError {
    fn from(e: PgError) -> ScurryError {
        ScurryError::Sql(Box::new(e))
    }
}
<|endoftext|>


<commit_before>extern crate lalrpop;

fn main() {
    lalrpop::process_root().ok().expect("Unable to process .lalrpop files");
}
<commit_msg>comment build file<commit_after>extern crate lalrpop;

// Generate parsing functions from all *.lalrpop files in src/
fn main() {
    lalrpop::process_root().ok().expect("Unable to process .lalrpop files");
}
<|endoftext|>


<commit_before>extern crate cmake;
extern crate pkg_config;

use std::env;
use std::env::consts;
use std::path::PathBuf;

fn build_dos(cmake_cfg: &mut cmake::Config) {
    let use_dos_dylib = option_env!("DyLib_DOtherSide").is_some();
    let dst = cmake_cfg.build();

    println!("cargo:rustc-link-search=native={}", dst.join("lib").display());

    if cfg!(windows) {
        println!("cargo:rustc-link-search=native={}", dst.join("build").join("lib").join("Release").display());
    } else {
        println!("cargo:rustc-link-search=native={}", dst.join("build").join("lib").display());
    }

    if use_dos_dylib {
        println!("cargo:rustc-link-lib=dylib=DOtherSide");
    } else {
        println!("cargo:rustc-link-lib=static=DOtherSideStatic");
    }
}

fn find_qt5(_: &mut cmake::Config) {
    /*
     * Support Qt installed via the Ports system on BSD-like systems.
     *
     * The native libs are in `/usr/local/lib`, which is not linked against by default.
     * This means that either the user or every package has to add this if they want to link
     * against something that is not part of the core distribution in `/usr/lib`.
     *
     * See https://wiki.freebsd.org/WarnerLosh/UsrLocal for the line of reasoning & how this will
     * change in the future.
     */
    if cfg!(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",
                target_os = "dragonfly", target_os = "bitrig")) {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    /*
     * Parameters for supporting QT on OS X
     *
     * Because QT5 conflicts with QT4 the homebrew package manager won't link
     * the QT5 package into the default search paths for libraries, to deal
     * with this we need to give pkg-config and cmake a nudge in the right
     * direction.
     */
    if cfg!(target_os = "macos") {
        // We use the QTDIR or QTDIR64 env variables to find the location of
        // Qt5. If these are not set, we use the default homebrew install
        // location.
        let qtdir_variable = match consts::ARCH {
            "x86_64" => "QTDIR64",
            _ => "QTDIR",
        };
        let mut qt5_lib_path = PathBuf::new();
        qt5_lib_path.push(env::var(qtdir_variable).unwrap_or(String::from("/usr/local/opt/qt5")));
        qt5_lib_path.push("lib");

        if qt5_lib_path.exists() {
            // First nudge cmake in the direction of the .cmake files added by
            // homebrew. This clobbers the existing value if present, it's
            // unlikely to be present though.
            env::set_var("CMAKE_PREFIX_PATH", qt5_lib_path.join("cmake"));

            // Nudge pkg-config in the direction of the brewed QT to ensure the
            // correct compiler flags get found for the project.
            env::set_var("PKG_CONFIG_PATH", qt5_lib_path.join("pkgconfig"));
        } else {
            panic!("QT5 was not found at the expected location ({}) please install it via homebrew, or set the {} env variable.",
            qt5_lib_path.display(), qtdir_variable);
        }
    }

    if cfg!(windows) {
        let mut qt5_lib_path = PathBuf::new();
        qt5_lib_path.push(env::var("QTDIR").unwrap_or(String::from("C:\\Qt\\5.7\\msvc2015_64")));

        if qt5_lib_path.exists() {
            env::set_var("CMAKE_PREFIX_PATH", &qt5_lib_path);

            qt5_lib_path.push("lib");

            println!("cargo:rustc-link-search=native={}\\system32",env::var("WINDIR").unwrap());
            println!("cargo:rustc-link-search=native={}",qt5_lib_path.display());

            println!("cargo:rustc-link-lib=dylib=Qt5Core");
            println!("cargo:rustc-link-lib=dylib=Qt5Gui");
            println!("cargo:rustc-link-lib=dylib=Qt5Qml");
            println!("cargo:rustc-link-lib=dylib=Qt5Quick");
            println!("cargo:rustc-link-lib=dylib=Qt5Svg");
            println!("cargo:rustc-link-lib=dylib=Qt5Widgets");
        } else {
            panic!("QT5 was not found at the expected location ({}) please install the SDK or set the QTDIR env variable.",
            qt5_lib_path.display());
        }
    } else {
        use pkg_config;

        if cfg!(target_os = "macos") {
            println!("cargo:rustc-link-lib=dylib=c++");
        } else {
            println!("cargo:rustc-link-lib=dylib=stdc++");
        }

        match pkg_config::find_library("Qt5Core Qt5Gui Qt5Qml Qt5Quick Qt5Svg") {
            Ok(lib) => {
                for p in lib.link_paths { println!("cargo:rustc-link-search=native={}",p.display()); }
                for p in lib.libs { println!("cargo:rustc-link-lib=dylib={}",p); }
                if cfg!(target_os = "macos") {
                    for p in lib.frameworks { println!("cargo:rustc-link-lib=framework={}",p); }
                }
                for p in lib.include_paths { println!("cargo:include={}",p.display()); }
            }
            Err(e) => panic!("QT5 was not found using pkg-config: {}",e)
        }
    }
}

fn main() {
    let mut cmake_cfg = cmake::Config::new("DOtherSide");
    let dos_path = PathBuf::from("DOtherSide").join("CMakeLists.txt");

    if !dos_path.exists() {
        panic!("DOtherSide submodule not checked out. Please run 'git submodule init' followed by 'git submodule update'.");
    }

    find_qt5(&mut cmake_cfg);
    build_dos(&mut cmake_cfg);
}
<commit_msg>add cmake generator override<commit_after>extern crate cmake;
extern crate pkg_config;

use std::env;
use std::env::consts;
use std::path::PathBuf;

fn build_dos(cmake_cfg: &mut cmake::Config) {
    let use_dos_dylib = option_env!("DyLib_DOtherSide").is_some();
    let dst = cmake_cfg.build();

    println!("cargo:rustc-link-search=native={}", dst.join("lib").display());

    if cfg!(windows) {
        println!("cargo:rustc-link-search=native={}", dst.join("build").join("lib").join("Release").display());
    } else {
        println!("cargo:rustc-link-search=native={}", dst.join("build").join("lib").display());
    }

    if use_dos_dylib {
        println!("cargo:rustc-link-lib=dylib=DOtherSide");
    } else {
        println!("cargo:rustc-link-lib=static=DOtherSideStatic");
    }
}

fn find_qt5(_: &mut cmake::Config) {
    /*
     * Support Qt installed via the Ports system on BSD-like systems.
     *
     * The native libs are in `/usr/local/lib`, which is not linked against by default.
     * This means that either the user or every package has to add this if they want to link
     * against something that is not part of the core distribution in `/usr/lib`.
     *
     * See https://wiki.freebsd.org/WarnerLosh/UsrLocal for the line of reasoning & how this will
     * change in the future.
     */
    if cfg!(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",
                target_os = "dragonfly", target_os = "bitrig")) {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    /*
     * Parameters for supporting QT on OS X
     *
     * Because QT5 conflicts with QT4 the homebrew package manager won't link
     * the QT5 package into the default search paths for libraries, to deal
     * with this we need to give pkg-config and cmake a nudge in the right
     * direction.
     */
    if cfg!(target_os = "macos") {
        // We use the QTDIR or QTDIR64 env variables to find the location of
        // Qt5. If these are not set, we use the default homebrew install
        // location.
        let qtdir_variable = match consts::ARCH {
            "x86_64" => "QTDIR64",
            _ => "QTDIR",
        };
        let mut qt5_lib_path = PathBuf::new();
        qt5_lib_path.push(env::var(qtdir_variable).unwrap_or(String::from("/usr/local/opt/qt5")));
        qt5_lib_path.push("lib");

        if qt5_lib_path.exists() {
            // First nudge cmake in the direction of the .cmake files added by
            // homebrew. This clobbers the existing value if present, it's
            // unlikely to be present though.
            env::set_var("CMAKE_PREFIX_PATH", qt5_lib_path.join("cmake"));

            // Nudge pkg-config in the direction of the brewed QT to ensure the
            // correct compiler flags get found for the project.
            env::set_var("PKG_CONFIG_PATH", qt5_lib_path.join("pkgconfig"));
        } else {
            panic!("QT5 was not found at the expected location ({}) please install it via homebrew, or set the {} env variable.",
            qt5_lib_path.display(), qtdir_variable);
        }
    }

    if cfg!(windows) {
        let mut qt5_lib_path = PathBuf::new();
        qt5_lib_path.push(env::var("QTDIR").unwrap_or(String::from("C:\\Qt\\5.7\\msvc2015_64")));

        if qt5_lib_path.exists() {
            env::set_var("CMAKE_PREFIX_PATH", &qt5_lib_path);

            qt5_lib_path.push("lib");

            println!("cargo:rustc-link-search=native={}\\system32",env::var("WINDIR").unwrap());
            println!("cargo:rustc-link-search=native={}",qt5_lib_path.display());

            println!("cargo:rustc-link-lib=dylib=Qt5Core");
            println!("cargo:rustc-link-lib=dylib=Qt5Gui");
            println!("cargo:rustc-link-lib=dylib=Qt5Qml");
            println!("cargo:rustc-link-lib=dylib=Qt5Quick");
            println!("cargo:rustc-link-lib=dylib=Qt5Svg");
            println!("cargo:rustc-link-lib=dylib=Qt5Widgets");
        } else {
            panic!("QT5 was not found at the expected location ({}) please install the SDK or set the QTDIR env variable.",
            qt5_lib_path.display());
        }
    } else {
        use pkg_config;

        if cfg!(target_os = "macos") {
            println!("cargo:rustc-link-lib=dylib=c++");
        } else {
            println!("cargo:rustc-link-lib=dylib=stdc++");
        }

        match pkg_config::find_library("Qt5Core Qt5Gui Qt5Qml Qt5Quick Qt5Svg") {
            Ok(lib) => {
                for p in lib.link_paths { println!("cargo:rustc-link-search=native={}",p.display()); }
                for p in lib.libs { println!("cargo:rustc-link-lib=dylib={}",p); }
                if cfg!(target_os = "macos") {
                    for p in lib.frameworks { println!("cargo:rustc-link-lib=framework={}",p); }
                }
                for p in lib.include_paths { println!("cargo:include={}",p.display()); }
            }
            Err(e) => panic!("QT5 was not found using pkg-config: {}",e)
        }
    }
}

fn main() {
    let mut cmake_cfg = cmake::Config::new("DOtherSide");
    let dos_path = PathBuf::from("DOtherSide").join("CMakeLists.txt");

    if !dos_path.exists() {
        panic!("DOtherSide submodule not checked out. Please run 'git submodule init' followed by 'git submodule update'.");
    }

    if let Ok(gen) = env::var("CMAKE_GENERATOR") {
        cmake_cfg.generator(gen);
    }

    find_qt5(&mut cmake_cfg);
    build_dos(&mut cmake_cfg);
}
<|endoftext|>


<commit_before>/// This build script checks if we can use `#![feature(specialization)]`.

extern crate rustc_version;

use rustc_version::Channel;

const SPECIALIZATION_CFG: &'static str = "has_specialization";

fn main() {
    let version = rustc_version::version_meta();

    if version.channel == Channel::Nightly {
        if let Some(ref date) = version.commit_date {
            // year, month, day
            let ndate = date.splitn(3, "-")
                                      .map(str::parse)
                                      .collect::<Result<Vec<i32>, _>>().unwrap();

            // specialization is available from nightly 2016-3-15
            if ndate >= vec![2016, 3, 15] {
                println!("cargo:rustc-cfg={}", SPECIALIZATION_CFG);
            }
        }
    }
}
<commit_msg>Prevent rebuilds of build.rs if other files change, fixes #62<commit_after>/// This build script checks if we can use `#![feature(specialization)]`.

extern crate rustc_version;

use rustc_version::Channel;

const SPECIALIZATION_CFG: &'static str = "has_specialization";

fn main() {
    // Prevent rebuilds of build.rs if other files change
    println!("cargo:rerun-if-changed=build.rs");

    let version = rustc_version::version_meta();

    if version.channel == Channel::Nightly {
        if let Some(ref date) = version.commit_date {
            // year, month, day
            let ndate = date.splitn(3, "-")
                                      .map(str::parse)
                                      .collect::<Result<Vec<i32>, _>>().unwrap();

            // specialization is available from nightly 2016-3-15
            if ndate >= vec![2016, 3, 15] {
                println!("cargo:rustc-cfg={}", SPECIALIZATION_CFG);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::path::PathBuf;
use std::env;

const LIB_NAME: &'static str = "libctxswtch.a";

fn main() {
    let arch =
        if cfg!(target_arch = "x86_64") {
            "x86_64"
        } else if cfg!(target_arch = "x86") {
            "i686"
        } else if cfg!(target_arch = "arm") {
            "arm"
        } else if cfg!(target_arch = "mips") {
            "mips"
        } else if cfg!(target_arch = "mipsel") {
            "mipsel"
        } else {
            panic!("Unsupported architecture: {}", env::var("TARGET").unwrap());
        };
    let src_path = &["src", "asm", arch, "_context.S"].iter().collect::<PathBuf>();
    gcc::compile_library(LIB_NAME, &[src_path.to_str().unwrap()]);

// seems like this line is no need actually
//    println!("cargo:rustc-flags=-l ctxswtch:static");
}
<commit_msg>use dynamic target provided by Cargo<commit_after>extern crate gcc;

use std::path::PathBuf;
use std::env;

const LIB_NAME: &'static str = "libctxswtch.a";

fn main() {
    let target = env::var("TARGET").unwrap();
    let arch_sub = target.split('-').next().unwrap();

    let arch =
        match arch_sub {
            "x86_64" => "x86_64",
            "x86" => "i686",
            "arm" => "arm",
            "mips" => "mips",
            "mipsel" => "mipsel",
            _ => {
                panic!("Unsupported architecture: {}", target);
            }
        };

    let src_path = &["src", "asm", arch, "_context.S"].iter().collect::<PathBuf>();
    gcc::compile_library(LIB_NAME, &[src_path.to_str().unwrap()]);

// seems like this line is no need actually
//    println!("cargo:rustc-flags=-l ctxswtch:static");
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::f32;
use std::f64;

use super::test_default_values::*;
use quick_protobuf::*;

#[test]
fn test_default_value_simple() {
    let bytes = &[];
    let mut reader = BytesReader::from_bytes(bytes);
    let d = TestDefaultValues::from_reader(&mut reader, bytes).unwrap();
    assert_eq!(1.0, d.double_field);
    assert_eq!(2.0, d.float_field);
    assert_eq!(3, d.int32_field);
    assert_eq!(4, d.int64_field);
    assert_eq!(5, d.uint32_field);
    assert_eq!(6, d.uint64_field);
    assert_eq!(7, d.sint32_field);
    assert_eq!(8, d.sint64_field);
    assert_eq!(9, d.fixed32_field);
    assert_eq!(10, d.fixed64_field);
    assert_eq!(11, d.sfixed32_field);
    assert_eq!(12, d.sfixed64_field);
    assert_eq!(true, d.bool_field);
    assert_eq!("abc\n22", d.string_field);
    assert_eq!(b"cde\n33".to_vec(), d.bytes_field.to_vec()); // if error - change to Cow::Borrowed(...)
    assert!(EnumForDefaultValue::TWO.eq(&d.enum_field));
    assert!(d
        .enum_field_without_default
        .map_or(true, |e| e.eq(&EnumForDefaultValue::ONE)));
}

#[test]
fn test_default_value_extreme() {
    let bytes = &[];
    let mut reader = BytesReader::from_bytes(bytes);
    let d = TestExtremeDefaultValues::from_reader(&mut reader, bytes).unwrap();
    assert_eq!(f64::INFINITY, d.inf_double);
    assert_eq!(f64::NEG_INFINITY, d.neg_inf_double);
    assert!(d.nan_double.is_nan());
    assert_eq!(f32::INFINITY, d.inf_float);
    assert_eq!(f32::NEG_INFINITY, d.neg_inf_float);
    assert!(d.nan_float.is_nan());
}
<commit_msg>Removed unnecessary comment<commit_after>use std::borrow::Cow;
use std::f32;
use std::f64;

use super::test_default_values::*;
use quick_protobuf::*;

#[test]
fn test_default_value_simple() {
    let bytes = &[];
    let mut reader = BytesReader::from_bytes(bytes);
    let d = TestDefaultValues::from_reader(&mut reader, bytes).unwrap();
    assert_eq!(1.0, d.double_field);
    assert_eq!(2.0, d.float_field);
    assert_eq!(3, d.int32_field);
    assert_eq!(4, d.int64_field);
    assert_eq!(5, d.uint32_field);
    assert_eq!(6, d.uint64_field);
    assert_eq!(7, d.sint32_field);
    assert_eq!(8, d.sint64_field);
    assert_eq!(9, d.fixed32_field);
    assert_eq!(10, d.fixed64_field);
    assert_eq!(11, d.sfixed32_field);
    assert_eq!(12, d.sfixed64_field);
    assert_eq!(true, d.bool_field);
    assert_eq!("abc\n22", d.string_field);
    assert_eq!(b"cde\n33".to_vec(), d.bytes_field.to_vec());
    assert!(EnumForDefaultValue::TWO.eq(&d.enum_field));
    assert!(d
        .enum_field_without_default
        .map_or(true, |e| e.eq(&EnumForDefaultValue::ONE)));
}

#[test]
fn test_default_value_extreme() {
    let bytes = &[];
    let mut reader = BytesReader::from_bytes(bytes);
    let d = TestExtremeDefaultValues::from_reader(&mut reader, bytes).unwrap();
    assert_eq!(f64::INFINITY, d.inf_double);
    assert_eq!(f64::NEG_INFINITY, d.neg_inf_double);
    assert!(d.nan_double.is_nan());
    assert_eq!(f32::INFINITY, d.inf_float);
    assert_eq!(f32::NEG_INFINITY, d.neg_inf_float);
    assert!(d.nan_float.is_nan());
}
<|endoftext|>


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

/* References:
  Student page: https://github.com/servo/servo/wiki/WebSocket-student-project
  Servo error enums for throwing errors: https://github.com/servo/servo/wiki/WebSocket-student-project
  Servo core - a list of all the modules like cell, char, u 16:
    https://github.com/servo/servo/wiki/WebSocket-student-project
*/
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::WebSocketBinding;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::error::Error::InvalidAccess;
use dom::bindings::error::Error::Syntax;
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::{Temporary, JSRef, Rootable};
use dom::bindings::refcounted::Trusted;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::reflect_dom_object;
use dom::closeevent::CloseEvent;
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use script_task::Runnable;
use script_task::ScriptMsg;
use std::cell::{Cell, RefCell};
use std::borrow::ToOwned;
use util::str::DOMString;

use websocket::Message;
use websocket::ws::sender::Sender as Sender_Object;
use websocket::client::sender::Sender;
use websocket::client::receiver::Receiver;
use websocket::stream::WebSocketStream;
use websocket::client::request::Url;
use websocket::Client;

#[derive(PartialEq, Copy)]
#[jstraceable]
enum WebSocketRequestState {
    Connecting = 0,
    Open = 1,
    Closing = 2,
    Closed = 3,
}

no_jsmanaged_fields!(Sender<WebSocketStream>);
no_jsmanaged_fields!(Receiver<WebSocketStream>);

#[dom_struct]
pub struct WebSocket { //Websocket attributes defined here
    eventtarget: EventTarget,
    url: DOMString,
    global: GlobalField,
    ready_state: Cell<WebSocketRequestState>,
    sender: RefCell<Option<Sender<WebSocketStream>>>,
    receiver: RefCell<Option<Receiver<WebSocketStream>>>,
    failed: Cell<bool>, //Flag to tell if websocket was closed due to failure
    full: Cell<bool>, //Flag to tell if websocket queue is full
    clean_close: Cell<bool>, //Flag to tell if the websocket closed cleanly (not due to full or fail)
    code: Cell<u16>, //Closing code
    reason: DOMRefCell<DOMString>, //Closing reason
    data: DOMRefCell<DOMString>, //Data from send
  sendCloseFrame: Cell<bool>
}

impl WebSocket {
    pub fn new_inherited(global: GlobalRef, url: DOMString) -> WebSocket {
        WebSocket {
            eventtarget: EventTarget::new_inherited(EventTargetTypeId::WebSocket),
            url: url,
            global: GlobalField::from_rooted(&global),
            ready_state: Cell::new(WebSocketRequestState::Connecting),
            failed: Cell::new(false),
            sender: RefCell::new(None),
            receiver: RefCell::new(None),
            full: Cell::new(false),
            clean_close: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned()),
            data: DOMRefCell::new("".to_owned()),
            sendCloseFrame: Cell::new(false)
        }

    }

    pub fn new(global: GlobalRef, url: DOMString) -> Temporary<WebSocket> {
        /*TODO: This constructor is only a prototype, it does not accomplish the specs
          defined here:
          http://html.spec.whatwg.org/multipage/comms.html#client-specified-protocols
          All 9 items must be satisfied.
          TODO: This constructor should be responsible for spawning a thread for the
          receive loop after ws_root.r().Open() - See comment
        */
        let ws_root = reflect_dom_object(box WebSocket::new_inherited(global, url),
                          global,
                          WebSocketBinding::Wrap).root();
        let ws_root = ws_root.r();
        let parsed_url = Url::parse(ws_root.url.as_slice()).unwrap(); //Get url
        let request = Client::connect(parsed_url).unwrap(); //Set up the request
        let response = request.send().unwrap(); //Send the request to the server
        response.validate().unwrap(); //Validate the server's response
        ws_root.ready_state.set(WebSocketRequestState::Open); //Set state to open
        //Check to see if ready_state is Closing or Closed and failed = true - means we failed the websocket
        //if so return without setting any states
        let ready_state = ws_root.ready_state.get();
        let failed = ws_root.failed.get();
        if failed && (ready_state == WebSocketRequestState::Closed || ready_state == WebSocketRequestState::Closing) {
            //Do nothing else. Let the close finish.
            return Temporary::from_rooted(ws_root);
        }
        let (temp_sender, temp_receiver) = response.begin().split(); //Set send and receiver in the attributes
        let mut other_sender = ws_root.sender.borrow_mut();
        let mut other_receiver = ws_root.receiver.borrow_mut();
        *other_sender = Some(temp_sender);
        *other_receiver = Some(temp_receiver);

        //Create everything necessary for starting the open asynchronous task, then begin the task.
        let global_root = ws_root.global.root();
        let addr: Trusted<WebSocket> = Trusted::new(global_root.r().get_cx(), ws_root, global_root.r().script_chan().clone());
        let open_task = box WebSocketTaskHandler::new(addr.clone(), WebSocketTask::Open);
        global_root.r().script_chan().send(ScriptMsg::RunnableMsg(open_task)).unwrap();
        //TODO: Spawn thread here for receive loop
        /*TODO: Add receive loop here and make new thread run this
          Receive is an infinite loop "similiar" the one shown here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop however does need to follow the spec. These are outlined here
          under "WebSocket message has been received" items 1-5:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop also needs to dispatch an asynchronous event as stated here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: When the receive loop receives a close message from the server,
          it confirms the websocket is now closed. This requires the close event
          to be fired (dispatch_close fires the close event - see implementation below)
        */
        Temporary::from_rooted(ws_root) //Return the websocket from the original thread that called this constructor
    }

    pub fn Constructor(global: GlobalRef, url: DOMString) -> Fallible<Temporary<WebSocket>> {
        Ok(WebSocket::new(global, url))
    }
}

impl<'a> WebSocketMethods for JSRef<'a, WebSocket> {
    event_handler!(open, GetOnopen, SetOnopen);
    event_handler!(close, GetOnclose, SetOnclose);
    event_handler!(error, GetOnerror, SetOnerror);

    fn Url(self) -> DOMString {
        self.url.clone()
    }

    fn ReadyState(self) -> u16 {
        self.ready_state.get() as u16
    }

    fn Send(self, data: Option<DOMString>)-> Fallible<()>{
        /*TODO: This is not up to spec see http://html.spec.whatwg.org/multipage/comms.html search for "If argument is a string"
          TODO: Need to buffer data
          TODO: bufferedAmount attribute returns the size of the buffer in bytes - this is a required attribute defined in the websocket.webidle file
          TODO: The send function needs to flag when full by using the following
          self.full.set(true). This needs to be done when the buffer is full
        */
        let mut other_sender = self.sender.borrow_mut();
        let my_sender = other_sender.as_mut().unwrap();
        if self.sendCloseFrame.get() { //TODO: Also check if the buffer is full
            self.sendCloseFrame.set(false); //Deflag the close frame request
            let _ = my_sender.send_message(Message::Close(None)); //Send close frame
            return Ok(());
        }
        let _ = my_sender.send_message(Message::Text(data.unwrap()));
        return Ok(())
    }

    /*TODO: 3 other types of send as specified in webidle/WebSocket.webidl
      The specs for each of these functions are described here:
      https://html.spec.whatwg.org/multipage/comms.html
    */
    //void send(Blob data); //Search above reference for "If the argument is a blob"
    //void send(ArrayBuffer data); //Search above reference for "If the argument is an ArrayBuffer"
    //void send(ArrayBufferView data); //Search above reference for "If the argument is an object that matches the ArrayBufferView"

    //Close is up to spec! :)
    fn Close(self, code: Option<u16>, reason: Option<DOMString>) -> Fallible<()>{
        if code.is_some() { //Code defined
            //Check code is NOT 1000 NOR in the range of 3000-4999 (inclusive)
            if  code != Some(1000) && (code < Some(3000) || code > Some(4999))
            {
                return Err(Error::InvalidAccess); //Throw InvalidAccessError and abort
            }
        }
        if reason.is_some() { //reason defined
            let a_reason = reason.as_ref().unwrap();
            if a_reason.as_bytes().len() > 123 //reason cannot be larger than 123 bytes
            {
                return Err(Error::Syntax); //Throw SyntaxError and abort
            }
        }

        match self.ready_state.get() {
            WebSocketRequestState::Closing | WebSocketRequestState::Closed  => {} //Do nothing
            WebSocketRequestState::Connecting => { //Connection is not yet established
                /*By setting the state to closing, the open function
                  will abort connecting the websocket*/
                self.ready_state.set(WebSocketRequestState::Closing);
                self.failed.set(true);
                self.sendCloseFrame.set(true);
                //-----Dispatch send task to send close frame------//
                //TODO: Sending here is just empty string, though no string is really needed. Another send, empty send, could be used.
                let _ = self.Send(None);
                //Note: After sending the close message, the receive loop confirms a close message from the server and must fire a close event
            }
            WebSocketRequestState::Open => {
                //Closing handshake not started - still in open
                //Start the closing by setting the code and reason if they exist
                if code.is_some() {
                    self.code.set(code.unwrap());
                }
                if reason.is_some(){
                    *self.reason.borrow_mut() = reason.unwrap();
                }
                self.ready_state.set(WebSocketRequestState::Closing); //Set state to closing
                self.sendCloseFrame.set(true); //Set close frame flag
                //Dispatch send task to send close frame
                let _ = self.Send(None);
                //Note: After sending the close message, the receive loop confirms a close message from the server and must fire a close event
            }
            //_ => { self.ready_state.set(WebSocketRequestState::Closing); } //Unreachable - Uncomment if you add more states to WebSocketRequestState
        }
        Ok(()) //Return Ok
    }
}

pub enum WebSocketTask {
    Open,
    Close,
}

pub struct WebSocketTaskHandler {
    addr: Trusted<WebSocket>,
    task: WebSocketTask,
}

impl WebSocketTaskHandler {
    pub fn new(addr: Trusted<WebSocket>, task: WebSocketTask) -> WebSocketTaskHandler {
        WebSocketTaskHandler {
            addr: addr,
            task: task,
        }
    }

    fn dispatch_open(&self) {
        /*TODO: Items 1, 3, 4, & 5 under "WebSocket connection is established" as specified here:
          https://html.spec.whatwg.org/multipage/comms.html#feedback-from-the-protocol
        */
        let ws = self.addr.to_temporary().root(); //Get root
        let ws = ws.r(); //Get websocket reference
        let global = ws.global.root();
        let event = Event::new(global.r(),
            "open".to_owned(),
            EventBubbles::DoesNotBubble,
            EventCancelable::Cancelable).root();
        let target: JSRef<EventTarget> = EventTargetCast::from_ref(ws);
        event.r().fire(target);
    }

    fn dispatch_close(&self) {
        let ws = self.addr.to_temporary().root();
        let global = ws.r().global.root();
        ws.r().ready_state.set(WebSocketRequestState::Closed); //Set to closed state
        //If failed or full, fire error event
        if ws.r().failed.get()||ws.r().full.get() {
            //Unset failed flag so we don't cause false positives
            ws.r().failed.set(false);
            //Unset full flag so we don't cause false positives
            ws.r().full.set(false);
            //A Bad close
            ws.r().clean_close.set(false);
            let event = Event::new(global.r(),
                "error".to_owned(),
                EventBubbles::DoesNotBubble,
                EventCancelable::Cancelable).root();
            let target: JSRef<EventTarget> = EventTargetCast::from_ref(ws.r());
            event.r().fire(target);
        }
        let ws = ws.r();
        let rsn = ws.reason.borrow();
        let rsn_clone = rsn.clone();
        /*In addition, we also have to fire a close even if error event fired
         https://html.spec.whatwg.org/multipage/comms.html#closeWebSocket
        */
        let close_event = CloseEvent::new(global.r(),
                "close".to_owned(),
                EventBubbles::DoesNotBubble,
            EventCancelable::Cancelable,
            ws.clean_close.get(),
            ws.code.get(),
            rsn_clone
            ).root();
        let target: JSRef<EventTarget> = EventTargetCast::from_ref(ws);
        let event: JSRef<Event> = EventCast::from_ref(close_event.r());
        event.set_trusted(true);
        event.fire(target);
    }
}

impl Runnable for WebSocketTaskHandler {
    fn handler(self: Box<WebSocketTaskHandler>) {
        match self.task {
            WebSocketTask::Open => {
                self.dispatch_open();
            }
            WebSocketTask::Close => {
                self.dispatch_close();
            }
        }
    }
}

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

/* References:
  Student page: https://github.com/servo/servo/wiki/WebSocket-student-project
  Servo error enums for throwing errors: https://github.com/servo/servo/wiki/WebSocket-student-project
  Servo core - a list of all the modules like cell, char, u 16:
    https://github.com/servo/servo/wiki/WebSocket-student-project
*/
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::WebSocketBinding;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::error::Error::InvalidAccess;
use dom::bindings::error::Error::Syntax;
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::{Temporary, JSRef, Rootable};
use dom::bindings::refcounted::Trusted;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::reflect_dom_object;
use dom::closeevent::CloseEvent;
use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers};
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
use script_task::Runnable;
use script_task::ScriptMsg;
use std::cell::{Cell, RefCell};
use std::borrow::ToOwned;
use util::str::DOMString;

use websocket::Message;
use websocket::ws::sender::Sender as Sender_Object;
use websocket::client::sender::Sender;
use websocket::client::receiver::Receiver;
use websocket::stream::WebSocketStream;
use websocket::client::request::Url;
use websocket::Client;

#[derive(PartialEq, Copy)]
#[jstraceable]
enum WebSocketRequestState {
    Connecting = 0,
    Open = 1,
    Closing = 2,
    Closed = 3,
}

no_jsmanaged_fields!(Sender<WebSocketStream>);
no_jsmanaged_fields!(Receiver<WebSocketStream>);

#[dom_struct]
pub struct WebSocket { //Websocket attributes defined here
    eventtarget: EventTarget,
    url: DOMString,
    global: GlobalField,
    ready_state: Cell<WebSocketRequestState>,
    sender: RefCell<Option<Sender<WebSocketStream>>>,
    receiver: RefCell<Option<Receiver<WebSocketStream>>>,
    failed: Cell<bool>, //Flag to tell if websocket was closed due to failure
    full: Cell<bool>, //Flag to tell if websocket queue is full
    clean_close: Cell<bool>, //Flag to tell if the websocket closed cleanly (not due to full or fail)
    code: Cell<u16>, //Closing code
    reason: DOMRefCell<DOMString>, //Closing reason
    data: DOMRefCell<DOMString>, //Data from send
  sendCloseFrame: Cell<bool>
}

impl WebSocket {
    pub fn new_inherited(global: GlobalRef, url: DOMString) -> WebSocket {
        WebSocket {
            eventtarget: EventTarget::new_inherited(EventTargetTypeId::WebSocket),
            url: url,
            global: GlobalField::from_rooted(&global),
            ready_state: Cell::new(WebSocketRequestState::Connecting),
            failed: Cell::new(false),
            sender: RefCell::new(None),
            receiver: RefCell::new(None),
            full: Cell::new(false),
            clean_close: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned()),
            data: DOMRefCell::new("".to_owned()),
            sendCloseFrame: Cell::new(false)
        }

    }

    pub fn new(global: GlobalRef, url: DOMString) -> Temporary<WebSocket> {
        /*TODO: This constructor is only a prototype, it does not accomplish the specs
          defined here:
          http://html.spec.whatwg.org
          All 9 items must be satisfied.
          TODO: This constructor should be responsible for spawning a thread for the
          receive loop after ws_root.r().Open() - See comment
        */
        let ws_root = reflect_dom_object(box WebSocket::new_inherited(global, url),
                          global,
                          WebSocketBinding::Wrap).root();
        let ws_root = ws_root.r();
        let parsed_url = Url::parse(ws_root.url.as_slice()).unwrap(); //Get url
        let request = Client::connect(parsed_url).unwrap(); //Set up the request
        let response = request.send().unwrap(); //Send the request to the server
        response.validate().unwrap(); //Validate the server's response
        ws_root.ready_state.set(WebSocketRequestState::Open); //Set state to open
        //Check to see if ready_state is Closing or Closed and failed = true - means we failed the websocket
        //if so return without setting any states
        let ready_state = ws_root.ready_state.get();
        let failed = ws_root.failed.get();
        if failed && (ready_state == WebSocketRequestState::Closed || ready_state == WebSocketRequestState::Closing) {
            //Do nothing else. Let the close finish.
            return Temporary::from_rooted(ws_root);
        }
        let (temp_sender, temp_receiver) = response.begin().split(); //Set send and receiver in the attributes
        let mut other_sender = ws_root.sender.borrow_mut();
        let mut other_receiver = ws_root.receiver.borrow_mut();
        *other_sender = Some(temp_sender);
        *other_receiver = Some(temp_receiver);

        //Create everything necessary for starting the open asynchronous task, then begin the task.
        let global_root = ws_root.global.root();
        let addr: Trusted<WebSocket> = Trusted::new(global_root.r().get_cx(), ws_root, global_root.r().script_chan().clone());
        let open_task = box WebSocketTaskHandler::new(addr.clone(), WebSocketTask::Open);
        global_root.r().script_chan().send(ScriptMsg::RunnableMsg(open_task)).unwrap();
        //TODO: Spawn thread here for receive loop
        /*TODO: Add receive loop here and make new thread run this
          Receive is an infinite loop "similiar" the one shown here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop however does need to follow the spec. These are outlined here
          under "WebSocket message has been received" items 1-5:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: The receive loop also needs to dispatch an asynchronous event as stated here:
          https://github.com/cyderize/rust-websocket/blob/master/examples/client.rs#L64
          TODO: When the receive loop receives a close message from the server,
          it confirms the websocket is now closed. This requires the close event
          to be fired (dispatch_close fires the close event - see implementation below)
        */
        Temporary::from_rooted(ws_root) //Return the websocket from the original thread that called this constructor
    }

    pub fn Constructor(global: GlobalRef, url: DOMString) -> Fallible<Temporary<WebSocket>> {
        Ok(WebSocket::new(global, url))
    }
}

impl<'a> WebSocketMethods for JSRef<'a, WebSocket> {
    event_handler!(open, GetOnopen, SetOnopen);
    event_handler!(close, GetOnclose, SetOnclose);
    event_handler!(error, GetOnerror, SetOnerror);

    fn Url(self) -> DOMString {
        self.url.clone()
    }

    fn ReadyState(self) -> u16 {
        self.ready_state.get() as u16
    }

    fn Send(self, data: Option<DOMString>)-> Fallible<()>{
        /*TODO: This is not up to spec see http://html.spec.whatwg.org/multipage/comms.html search for "If argument is a string"
          TODO: Need to buffer data
          TODO: bufferedAmount attribute returns the size of the buffer in bytes - this is a required attribute defined in the websocket.webidle file
          TODO: The send function needs to flag when full by using the following
          self.full.set(true). This needs to be done when the buffer is full
        */
        let mut other_sender = self.sender.borrow_mut();
        let my_sender = other_sender.as_mut().unwrap();
        if self.sendCloseFrame.get() { //TODO: Also check if the buffer is full
            self.sendCloseFrame.set(false); //Deflag the close frame request
            let _ = my_sender.send_message(Message::Close(None)); //Send close frame
            return Ok(());
        }
        let _ = my_sender.send_message(Message::Text(data.unwrap()));
        return Ok(())
    }

    /*TODO: 3 other types of send as specified in webidle/WebSocket.webidl
      The specs for each of these functions are described here:
      https://html.spec.whatwg.org/multipage/comms.html
    */
    //void send(Blob data); //Search above reference for "If the argument is a blob"
    //void send(ArrayBuffer data); //Search above reference for "If the argument is an ArrayBuffer"
    //void send(ArrayBufferView data); //Search above reference for "If the argument is an object that matches the ArrayBufferView"

    //Close is up to spec! :)
    fn Close(self, code: Option<u16>, reason: Option<DOMString>) -> Fallible<()>{
        if code.is_some() { //Code defined
            //Check code is NOT 1000 NOR in the range of 3000-4999 (inclusive)
            if  code != Some(1000) && (code < Some(3000) || code > Some(4999))
            {
                return Err(Error::InvalidAccess); //Throw InvalidAccessError and abort
            }
        }
        if reason.is_some() { //reason defined
            let a_reason = reason.as_ref().unwrap();
            if a_reason.as_bytes().len() > 123 //reason cannot be larger than 123 bytes
            {
                return Err(Error::Syntax); //Throw SyntaxError and abort
            }
        }

        match self.ready_state.get() {
            WebSocketRequestState::Closing | WebSocketRequestState::Closed  => {} //Do nothing
            WebSocketRequestState::Connecting => { //Connection is not yet established
                /*By setting the state to closing, the open function
                  will abort connecting the websocket*/
                self.ready_state.set(WebSocketRequestState::Closing);
                self.failed.set(true);
                self.sendCloseFrame.set(true);
                //-----Dispatch send task to send close frame------//
                //TODO: Sending here is just empty string, though no string is really needed. Another send, empty send, could be used.
                let _ = self.Send(None);
                //Note: After sending the close message, the receive loop confirms a close message from the server and must fire a close event
            }
            WebSocketRequestState::Open => {
                //Closing handshake not started - still in open
                //Start the closing by setting the code and reason if they exist
                if code.is_some() {
                    self.code.set(code.unwrap());
                }
                if reason.is_some(){
                    *self.reason.borrow_mut() = reason.unwrap();
                }
                self.ready_state.set(WebSocketRequestState::Closing); //Set state to closing
                self.sendCloseFrame.set(true); //Set close frame flag
                //Dispatch send task to send close frame
                let _ = self.Send(None);
                //Note: After sending the close message, the receive loop confirms a close message from the server and must fire a close event
            }
            //_ => { self.ready_state.set(WebSocketRequestState::Closing); } //Unreachable - Uncomment if you add more states to WebSocketRequestState
        }
        Ok(()) //Return Ok
    }
}

pub enum WebSocketTask {
    Open,
    Close,
}

pub struct WebSocketTaskHandler {
    addr: Trusted<WebSocket>,
    task: WebSocketTask,
}

impl WebSocketTaskHandler {
    pub fn new(addr: Trusted<WebSocket>, task: WebSocketTask) -> WebSocketTaskHandler {
        WebSocketTaskHandler {
            addr: addr,
            task: task,
        }
    }

    fn dispatch_open(&self) {
        /*TODO: Items 1, 3, 4, & 5 under "WebSocket connection is established" as specified here:
          https://html.spec.whatwg.org
        */
        let ws = self.addr.to_temporary().root(); //Get root
        let ws = ws.r(); //Get websocket reference
        let global = ws.global.root();
        let event = Event::new(global.r(),
            "open".to_owned(),
            EventBubbles::DoesNotBubble,
            EventCancelable::Cancelable).root();
        let target: JSRef<EventTarget> = EventTargetCast::from_ref(ws);
        event.r().fire(target);
    }

    fn dispatch_close(&self) {
        let ws = self.addr.to_temporary().root();
        let global = ws.r().global.root();
        ws.r().ready_state.set(WebSocketRequestState::Closed); //Set to closed state
        //If failed or full, fire error event
        if ws.r().failed.get()||ws.r().full.get() {
            //Unset failed flag so we don't cause false positives
            ws.r().failed.set(false);
            //Unset full flag so we don't cause false positives
            ws.r().full.set(false);
            //A Bad close
            ws.r().clean_close.set(false);
            let event = Event::new(global.r(),
                "error".to_owned(),
                EventBubbles::DoesNotBubble,
                EventCancelable::Cancelable).root();
            let target: JSRef<EventTarget> = EventTargetCast::from_ref(ws.r());
            event.r().fire(target);
        }
        let ws = ws.r();
        let rsn = ws.reason.borrow();
        let rsn_clone = rsn.clone();
        /*In addition, we also have to fire a close even if error event fired
         https://html.spec.whatwg.org
        */
        let close_event = CloseEvent::new(global.r(),
                "close".to_owned(),
                EventBubbles::DoesNotBubble,
            EventCancelable::Cancelable,
            ws.clean_close.get(),
            ws.code.get(),
            rsn_clone
            ).root();
        let target: JSRef<EventTarget> = EventTargetCast::from_ref(ws);
        let event: JSRef<Event> = EventCast::from_ref(close_event.r());
        event.set_trusted(true);
        event.fire(target);
    }
}

impl Runnable for WebSocketTaskHandler {
    fn handler(self: Box<WebSocketTaskHandler>) {
        match self.task {
            WebSocketTask::Open => {
                self.dispatch_open();
            }
            WebSocketTask::Close => {
                self.dispatch_close();
            }
        }
    }
}

<|endoftext|>


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

//! Generic types that share their serialization implementations
//! for both specified and computed values.

use counter_style::{Symbols, parse_counter_style_name};
use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseError, ToCss};
use super::CustomIdent;
use values::specified::url::SpecifiedUrl;

pub mod background;
pub mod basic_shape;
pub mod border;
pub mod effects;
pub mod flex;
#[cfg(feature = "gecko")]
pub mod gecko;
pub mod grid;
pub mod image;
pub mod position;
pub mod rect;
pub mod text;
pub mod transform;

// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
define_css_keyword_enum! { SymbolsType:
    "cyclic" => Cyclic,
    "numeric" => Numeric,
    "alphabetic" => Alphabetic,
    "symbolic" => Symbolic,
    "fixed" => Fixed,
}
add_impls_for_keyword_enum!(SymbolsType);

#[cfg(feature = "gecko")]
impl SymbolsType {
    /// Convert symbols type to their corresponding Gecko values.
    pub fn to_gecko_keyword(self) -> u8 {
        use gecko_bindings::structs;
        match self {
            SymbolsType::Cyclic => structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as u8,
            SymbolsType::Numeric => structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as u8,
            SymbolsType::Alphabetic => structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as u8,
            SymbolsType::Symbolic => structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as u8,
            SymbolsType::Fixed => structs::NS_STYLE_COUNTER_SYSTEM_FIXED as u8,
        }
    }
}

/// https://drafts.csswg.org/css-counter-styles/#typedef-counter-style
///
/// Since wherever <counter-style> is used, 'none' is a valid value as
/// well, we combine them into one type to make code simpler.
#[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum CounterStyleOrNone {
    /// `none`
    None,
    /// `<counter-style-name>`
    Name(CustomIdent),
    /// `symbols()`
    #[css(function)]
    Symbols(SymbolsType, Symbols),
}

impl CounterStyleOrNone {
    /// disc value
    pub fn disc() -> Self {
        CounterStyleOrNone::Name(CustomIdent(atom!("disc")))
    }

    /// decimal value
    pub fn decimal() -> Self {
        CounterStyleOrNone::Name(CustomIdent(atom!("decimal")))
    }
}

no_viewport_percentage!(CounterStyleOrNone);

impl Parse for CounterStyleOrNone {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(name) = input.try(|i| parse_counter_style_name(i)) {
            return Ok(CounterStyleOrNone::Name(name));
        }
        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
            return Ok(CounterStyleOrNone::None);
        }
        if input.try(|i| i.expect_function_matching("symbols")).is_ok() {
            return input.parse_nested_block(|input| {
                let symbols_type = input.try(|i| SymbolsType::parse(i))
                    .unwrap_or(SymbolsType::Symbolic);
                let symbols = Symbols::parse(context, input)?;
                // There must be at least two symbols for alphabetic or
                // numeric system.
                if (symbols_type == SymbolsType::Alphabetic ||
                    symbols_type == SymbolsType::Numeric) && symbols.0.len() < 2 {
                    return Err(StyleParseError::UnspecifiedError.into());
                }
                // Identifier is not allowed in symbols() function.
                if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) {
                    return Err(StyleParseError::UnspecifiedError.into());
                }
                Ok(CounterStyleOrNone::Symbols(symbols_type, symbols))
            });
        }
        Err(StyleParseError::UnspecifiedError.into())
    }
}

/// A settings tag, defined by a four-character tag and a setting value
///
/// For font-feature-settings, this is a tag and an integer,
/// for font-variation-settings this is a tag and a float
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontSettingTag<T> {
    /// A four-character tag, packed into a u32 (one byte per character)
    pub tag: u32,
    /// The value
    pub value: T,
}

impl<T> OneOrMoreSeparated for FontSettingTag<T> {
    type S = Comma;
}

impl<T: ToCss> ToCss for FontSettingTag<T> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        use byteorder::{BigEndian, ByteOrder};
        use std::str;

        let mut raw = [0u8; 4];
        BigEndian::write_u32(&mut raw, self.tag);
        str::from_utf8(&raw).unwrap_or_default().to_css(dest)?;

        self.value.to_css(dest)
    }
}

impl<T: Parse> Parse for FontSettingTag<T> {
    /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
    /// https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-
    /// settings-control-the-font-variation-settings-property
    /// <string> [ on | off | <integer> ]
    /// <string> <number>
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        use byteorder::{ReadBytesExt, BigEndian};
        use std::io::Cursor;

        let tag = input.expect_string()?;

        // allowed strings of length 4 containing chars: <U+20, U+7E>
        if tag.len() != 4 ||
           tag.chars().any(|c| c < ' ' || c > '~')
        {
            return Err(StyleParseError::UnspecifiedError.into())
        }

        let mut raw = Cursor::new(tag.as_bytes());
        let u_tag = raw.read_u32::<BigEndian>().unwrap();

        Ok(FontSettingTag { tag: u_tag, value: T::parse(context, input)? })
    }
}

/// A font settings value for font-variation-settings or font-feature-settings
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum FontSettings<T> {
    /// No settings (default)
    Normal,
    /// Set of settings
    Tag(Vec<FontSettingTag<T>>)
}

impl<T: Parse> Parse for FontSettings<T> {
    /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
            return Ok(FontSettings::Normal);
        }
        Vec::parse(context, input).map(FontSettings::Tag)
    }
}

/// An integer that can also parse "on" and "off",
/// for font-feature-settings
///
/// Do not use this type anywhere except within FontSettings
/// because it serializes with the preceding space
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontSettingTagInt(pub u32);
/// A number value to be used for font-variation-settings
///
/// Do not use this type anywhere except within FontSettings
/// because it serializes with the preceding space
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontSettingTagFloat(pub f32);

impl ToCss for FontSettingTagInt {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match self.0 {
            1 => Ok(()),
            0 => dest.write_str(" off"),
            x => write!(dest, " {}", x)
        }
    }
}

impl Parse for FontSettingTagInt {
    fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(value) = input.try(|input| input.expect_integer()) {
            // handle integer, throw if it is negative
            if value >= 0 {
                Ok(FontSettingTagInt(value as u32))
            } else {
                Err(StyleParseError::UnspecifiedError.into())
            }
        } else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) {
            // on is an alias for '1'
            Ok(FontSettingTagInt(1))
        } else if let Ok(_) = input.try(|input| input.expect_ident_matching("off")) {
            // off is an alias for '0'
            Ok(FontSettingTagInt(0))
        } else {
            // empty value is an alias for '1'
            Ok(FontSettingTagInt(1))
        }
    }
}

impl Parse for FontSettingTagFloat {
    fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        input.expect_number().map(FontSettingTagFloat).map_err(|e| e.into())
    }
}

impl ToCss for FontSettingTagFloat {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_str(" ")?;
        self.0.to_css(dest)
    }
}

/// An SVG paint value
///
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue)]
pub struct SVGPaint<ColorType> {
    /// The paint source
    pub kind: SVGPaintKind<ColorType>,
    /// The fallback color
    pub fallback: Option<ColorType>,
}

/// An SVG paint value without the fallback
///
/// Whereas the spec only allows PaintServer
/// to have a fallback, Gecko lets the context
/// properties have a fallback as well.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToCss)]
pub enum SVGPaintKind<ColorType> {
    /// `none`
    None,
    /// `<color>`
    Color(ColorType),
    /// `url(...)`
    PaintServer(SpecifiedUrl),
    /// `context-fill`
    ContextFill,
    /// `context-stroke`
    ContextStroke,
}

impl<ColorType> SVGPaintKind<ColorType> {
    /// Convert to a value with a different kind of color
    pub fn convert<F, OtherColor>(&self, f: F) -> SVGPaintKind<OtherColor>
        where F: Fn(&ColorType) -> OtherColor {
            match *self {
                SVGPaintKind::None => SVGPaintKind::None,
                SVGPaintKind::ContextStroke => SVGPaintKind::ContextStroke,
                SVGPaintKind::ContextFill => SVGPaintKind::ContextFill,
                SVGPaintKind::Color(ref color) => {
                    SVGPaintKind::Color(f(color))
                }
                SVGPaintKind::PaintServer(ref server) => {
                    SVGPaintKind::PaintServer(server.clone())
                }
            }
    }
}

impl<ColorType> SVGPaint<ColorType> {
    /// Convert to a value with a different kind of color
    pub fn convert<F, OtherColor>(&self, f: F) -> SVGPaint<OtherColor>
        where F: Fn(&ColorType) -> OtherColor {
        SVGPaint {
            kind: self.kind.convert(&f),
            fallback: self.fallback.as_ref().map(|color| f(color))
        }
    }
}

impl<ColorType> SVGPaintKind<ColorType> {
    /// Parse a keyword value only
    fn parse_ident<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
            "none" => Ok(SVGPaintKind::None),
            "context-fill" => Ok(SVGPaintKind::ContextFill),
            "context-stroke" => Ok(SVGPaintKind::ContextStroke),
        }
    }
}

impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
            let fallback = input.try(|i| ColorType::parse(context, i));
            Ok(SVGPaint {
                kind: SVGPaintKind::PaintServer(url),
                fallback: fallback.ok(),
            })
        } else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
            if let SVGPaintKind::None = kind {
                Ok(SVGPaint {
                    kind: kind,
                    fallback: None,
                })
            } else {
                let fallback = input.try(|i| ColorType::parse(context, i));
                Ok(SVGPaint {
                    kind: kind,
                    fallback: fallback.ok(),
                })
            }
        } else if let Ok(color) = input.try(|i| ColorType::parse(context, i)) {
            Ok(SVGPaint {
                kind: SVGPaintKind::Color(color),
                fallback: None,
            })
        } else {
            Err(StyleParseError::UnspecifiedError.into())
        }
    }
}

impl<ColorType: ToCss> ToCss for SVGPaint<ColorType> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        self.kind.to_css(dest)?;
        if let Some(ref fallback) = self.fallback {
            fallback.to_css(dest)?;
        }
        Ok(())
    }
}

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

//! Generic types that share their serialization implementations
//! for both specified and computed values.

use counter_style::{Symbols, parse_counter_style_name};
use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseError, ToCss};
use super::CustomIdent;
use values::specified::url::SpecifiedUrl;

pub mod background;
pub mod basic_shape;
pub mod border;
pub mod effects;
pub mod flex;
#[cfg(feature = "gecko")]
pub mod gecko;
pub mod grid;
pub mod image;
pub mod position;
pub mod rect;
pub mod text;
pub mod transform;

// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
define_css_keyword_enum! { SymbolsType:
    "cyclic" => Cyclic,
    "numeric" => Numeric,
    "alphabetic" => Alphabetic,
    "symbolic" => Symbolic,
    "fixed" => Fixed,
}
add_impls_for_keyword_enum!(SymbolsType);

#[cfg(feature = "gecko")]
impl SymbolsType {
    /// Convert symbols type to their corresponding Gecko values.
    pub fn to_gecko_keyword(self) -> u8 {
        use gecko_bindings::structs;
        match self {
            SymbolsType::Cyclic => structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as u8,
            SymbolsType::Numeric => structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as u8,
            SymbolsType::Alphabetic => structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as u8,
            SymbolsType::Symbolic => structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as u8,
            SymbolsType::Fixed => structs::NS_STYLE_COUNTER_SYSTEM_FIXED as u8,
        }
    }
}

/// https://drafts.csswg.org/css-counter-styles/#typedef-counter-style
///
/// Since wherever <counter-style> is used, 'none' is a valid value as
/// well, we combine them into one type to make code simpler.
#[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum CounterStyleOrNone {
    /// `none`
    None,
    /// `<counter-style-name>`
    Name(CustomIdent),
    /// `symbols()`
    #[css(function)]
    Symbols(SymbolsType, Symbols),
}

impl CounterStyleOrNone {
    /// disc value
    pub fn disc() -> Self {
        CounterStyleOrNone::Name(CustomIdent(atom!("disc")))
    }

    /// decimal value
    pub fn decimal() -> Self {
        CounterStyleOrNone::Name(CustomIdent(atom!("decimal")))
    }
}

no_viewport_percentage!(CounterStyleOrNone);

impl Parse for CounterStyleOrNone {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(name) = input.try(|i| parse_counter_style_name(i)) {
            return Ok(CounterStyleOrNone::Name(name));
        }
        if input.try(|i| i.expect_ident_matching("none")).is_ok() {
            return Ok(CounterStyleOrNone::None);
        }
        if input.try(|i| i.expect_function_matching("symbols")).is_ok() {
            return input.parse_nested_block(|input| {
                let symbols_type = input.try(|i| SymbolsType::parse(i))
                    .unwrap_or(SymbolsType::Symbolic);
                let symbols = Symbols::parse(context, input)?;
                // There must be at least two symbols for alphabetic or
                // numeric system.
                if (symbols_type == SymbolsType::Alphabetic ||
                    symbols_type == SymbolsType::Numeric) && symbols.0.len() < 2 {
                    return Err(StyleParseError::UnspecifiedError.into());
                }
                // Identifier is not allowed in symbols() function.
                if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) {
                    return Err(StyleParseError::UnspecifiedError.into());
                }
                Ok(CounterStyleOrNone::Symbols(symbols_type, symbols))
            });
        }
        Err(StyleParseError::UnspecifiedError.into())
    }
}

/// A settings tag, defined by a four-character tag and a setting value
///
/// For font-feature-settings, this is a tag and an integer,
/// for font-variation-settings this is a tag and a float
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontSettingTag<T> {
    /// A four-character tag, packed into a u32 (one byte per character)
    pub tag: u32,
    /// The value
    pub value: T,
}

impl<T> OneOrMoreSeparated for FontSettingTag<T> {
    type S = Comma;
}

impl<T: ToCss> ToCss for FontSettingTag<T> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        use byteorder::{BigEndian, ByteOrder};
        use std::str;

        let mut raw = [0u8; 4];
        BigEndian::write_u32(&mut raw, self.tag);
        str::from_utf8(&raw).unwrap_or_default().to_css(dest)?;

        self.value.to_css(dest)
    }
}

impl<T: Parse> Parse for FontSettingTag<T> {
    /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
    /// https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-
    /// settings-control-the-font-variation-settings-property
    /// <string> [ on | off | <integer> ]
    /// <string> <number>
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        use byteorder::{ReadBytesExt, BigEndian};
        use std::io::Cursor;

        let tag = input.expect_string()?;

        // allowed strings of length 4 containing chars: <U+20, U+7E>
        if tag.len() != 4 ||
           tag.chars().any(|c| c < ' ' || c > '~')
        {
            return Err(StyleParseError::UnspecifiedError.into())
        }

        let mut raw = Cursor::new(tag.as_bytes());
        let u_tag = raw.read_u32::<BigEndian>().unwrap();

        Ok(FontSettingTag { tag: u_tag, value: T::parse(context, input)? })
    }
}

/// A font settings value for font-variation-settings or font-feature-settings
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum FontSettings<T> {
    /// No settings (default)
    Normal,
    /// Set of settings
    Tag(Vec<FontSettingTag<T>>)
}

impl<T: Parse> Parse for FontSettings<T> {
    /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
            return Ok(FontSettings::Normal);
        }
        Vec::parse(context, input).map(FontSettings::Tag)
    }
}

/// An integer that can also parse "on" and "off",
/// for font-feature-settings
///
/// Do not use this type anywhere except within FontSettings
/// because it serializes with the preceding space
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontSettingTagInt(pub u32);
/// A number value to be used for font-variation-settings
///
/// Do not use this type anywhere except within FontSettings
/// because it serializes with the preceding space
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct FontSettingTagFloat(pub f32);

impl ToCss for FontSettingTagInt {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match self.0 {
            1 => Ok(()),
            0 => dest.write_str(" off"),
            x => write!(dest, " {}", x)
        }
    }
}

impl Parse for FontSettingTagInt {
    fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(value) = input.try(|input| input.expect_integer()) {
            // handle integer, throw if it is negative
            if value >= 0 {
                Ok(FontSettingTagInt(value as u32))
            } else {
                Err(StyleParseError::UnspecifiedError.into())
            }
        } else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) {
            // on is an alias for '1'
            Ok(FontSettingTagInt(1))
        } else if let Ok(_) = input.try(|input| input.expect_ident_matching("off")) {
            // off is an alias for '0'
            Ok(FontSettingTagInt(0))
        } else {
            // empty value is an alias for '1'
            Ok(FontSettingTagInt(1))
        }
    }
}

impl Parse for FontSettingTagFloat {
    fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        input.expect_number().map(FontSettingTagFloat).map_err(|e| e.into())
    }
}

impl ToCss for FontSettingTagFloat {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        dest.write_str(" ")?;
        self.0.to_css(dest)
    }
}

/// An SVG paint value
///
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue)]
pub struct SVGPaint<ColorType> {
    /// The paint source
    pub kind: SVGPaintKind<ColorType>,
    /// The fallback color
    pub fallback: Option<ColorType>,
}

/// An SVG paint value without the fallback
///
/// Whereas the spec only allows PaintServer
/// to have a fallback, Gecko lets the context
/// properties have a fallback as well.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToCss)]
pub enum SVGPaintKind<ColorType> {
    /// `none`
    None,
    /// `<color>`
    Color(ColorType),
    /// `url(...)`
    PaintServer(SpecifiedUrl),
    /// `context-fill`
    ContextFill,
    /// `context-stroke`
    ContextStroke,
}

impl<ColorType> SVGPaintKind<ColorType> {
    /// Convert to a value with a different kind of color
    pub fn convert<F, OtherColor>(&self, f: F) -> SVGPaintKind<OtherColor>
        where F: Fn(&ColorType) -> OtherColor {
            match *self {
                SVGPaintKind::None => SVGPaintKind::None,
                SVGPaintKind::ContextStroke => SVGPaintKind::ContextStroke,
                SVGPaintKind::ContextFill => SVGPaintKind::ContextFill,
                SVGPaintKind::Color(ref color) => {
                    SVGPaintKind::Color(f(color))
                }
                SVGPaintKind::PaintServer(ref server) => {
                    SVGPaintKind::PaintServer(server.clone())
                }
            }
    }
}

impl<ColorType> SVGPaint<ColorType> {
    /// Convert to a value with a different kind of color
    pub fn convert<F, OtherColor>(&self, f: F) -> SVGPaint<OtherColor>
        where F: Fn(&ColorType) -> OtherColor {
        SVGPaint {
            kind: self.kind.convert(&f),
            fallback: self.fallback.as_ref().map(|color| f(color))
        }
    }
}

impl<ColorType> SVGPaintKind<ColorType> {
    /// Parse a keyword value only
    fn parse_ident<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        try_match_ident_ignore_ascii_case! { input.expect_ident()?,
            "none" => Ok(SVGPaintKind::None),
            "context-fill" => Ok(SVGPaintKind::ContextFill),
            "context-stroke" => Ok(SVGPaintKind::ContextStroke),
        }
    }
}

/// Parse SVGPaint's fallback.
/// fallback is keyword(none) or Color.
/// https://svgwg.org/svg2-draft/painting.html#SpecifyingPaint
fn parse_fallback<'i, 't, ColorType: Parse>(context: &ParserContext,
                                            input: &mut Parser<'i, 't>)
                                            -> Option<ColorType> {
    if input.try(|i| i.expect_ident_matching("none")).is_ok() {
        None
    } else {
        input.try(|i| ColorType::parse(context, i)).ok()
    }
}

impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
        if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
            Ok(SVGPaint {
                kind: SVGPaintKind::PaintServer(url),
                fallback: parse_fallback(context, input),
            })
        } else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
            if let SVGPaintKind::None = kind {
                Ok(SVGPaint {
                    kind: kind,
                    fallback: None,
                })
            } else {
                Ok(SVGPaint {
                    kind: kind,
                    fallback: parse_fallback(context, input),
                })
            }
        } else if let Ok(color) = input.try(|i| ColorType::parse(context, i)) {
            Ok(SVGPaint {
                kind: SVGPaintKind::Color(color),
                fallback: None,
            })
        } else {
            Err(StyleParseError::UnspecifiedError.into())
        }
    }
}

impl<ColorType: ToCss> ToCss for SVGPaint<ColorType> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        self.kind.to_css(dest)?;
        if let Some(ref fallback) = self.fallback {
            fallback.to_css(dest)?;
        }
        Ok(())
    }
}

<|endoftext|>