<commit_before>use std::io;
use std::time::Duration;
use std::sync::Arc;

use futures::{Future, future};
use futures_cpupool::CpuPool;
use num_cpus;

use tokio_service::Service;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_proto::TcpClient;
use tokio_proto::multiplex::{ClientService};
use tokio_middleware::Timeout;
use tokio_timer::Timer;

use tcp::proto::BytesClientProto;
use tcp::shortcut;
use bifrost_hasher::hash_str;
use super::STANDALONE_ADDRESS;
use DISABLE_SHORTCUT;

pub type ResFuture = Future<Item = Vec<u8>, Error = io::Error>;

lazy_static! {
    pub static ref CONNECTING_POOL: CpuPool = CpuPool::new(10 * num_cpus::get());
}

pub struct ClientCore {
    inner: ClientService<TcpStream, BytesClientProto>,
}

pub struct Client {
    client: Option<Timeout<ClientCore>>,
    pub server_id: u64,
}

impl Service for ClientCore {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    // Again for simplicity, we are just going to box a future
    type Future = Box<Future<Item = Self::Response, Error = io::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        Box::new(self.inner.call(req))
    }
}

impl Client {
    pub fn connect_with_timeout (address: &String, timeout: Duration) -> io::Result<Client> {
        let server_id = hash_str(address);
        let client = {
            if !DISABLE_SHORTCUT && shortcut::is_local(server_id) {
                None
            } else {
                if address.eq(&STANDALONE_ADDRESS) {
                    return Err(io::Error::new(io::ErrorKind::Other, "STANDALONE server is not found"))
                }
                let mut core = Core::new()?;
                let socket_address = address.parse().unwrap();
                let future = Box::new(TcpClient::new(BytesClientProto)
                    .connect(&socket_address, &core.handle())
                    .map(|c| Timeout::new(
                        ClientCore {
                            inner: c,
                        },
                        Timer::default(),
                        timeout)));
                Some(core.run(future)?) // this is required, or client won't receive response
            }
        };
        Ok(Client {
            client,
            server_id,
        })
    }
    pub fn connect (address: &String) -> io::Result<Client> {
        Client::connect_with_timeout(address, Duration::from_secs(5))
    }
    pub fn connect_with_timeout_async (address: String, timeout: Duration)
        -> impl Future<Item = Client, Error = io::Error>
    {
        CONNECTING_POOL.spawn_fn(move ||{
            Client::connect_with_timeout(&address, timeout)
        })
    }
    pub fn connect_async (address: String)
        -> impl Future<Item = Client, Error = io::Error>
    {
        CONNECTING_POOL.spawn_fn(move || {
            Client::connect_with_timeout(&address, Duration::from_secs(5))
        })
    }
    pub fn send(&self, msg: Vec<u8>) -> io::Result<Vec<u8>> {
        self.send_async(msg).wait()
    }
    pub fn send_async(&self, msg: Vec<u8>) -> Box<ResFuture> {
        if let Some(ref client) = self.client {
            box client.call(msg)
        } else {
            shortcut::call(self.server_id, msg)
        }
    }
}

unsafe impl Send for Client {}<commit_msg>remove send in tcp client<commit_after>use std::io;
use std::time::Duration;
use std::sync::Arc;

use futures::{Future, future};
use futures_cpupool::CpuPool;
use num_cpus;

use tokio_service::Service;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_proto::TcpClient;
use tokio_proto::multiplex::{ClientService};
use tokio_middleware::Timeout;
use tokio_timer::Timer;

use tcp::proto::BytesClientProto;
use tcp::shortcut;
use bifrost_hasher::hash_str;
use super::STANDALONE_ADDRESS;
use DISABLE_SHORTCUT;

pub type ResFuture = Future<Item = Vec<u8>, Error = io::Error>;

lazy_static! {
    pub static ref CONNECTING_POOL: CpuPool = CpuPool::new(10 * num_cpus::get());
}

pub struct ClientCore {
    inner: ClientService<TcpStream, BytesClientProto>,
}

pub struct Client {
    client: Option<Timeout<ClientCore>>,
    pub server_id: u64,
}

impl Service for ClientCore {

    type Request = Vec<u8>;
    type Response = Vec<u8>;
    type Error = io::Error;
    // Again for simplicity, we are just going to box a future
    type Future = Box<Future<Item = Self::Response, Error = io::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        Box::new(self.inner.call(req))
    }
}

impl Client {
    pub fn connect_with_timeout (address: &String, timeout: Duration) -> io::Result<Client> {
        let server_id = hash_str(address);
        let client = {
            if !DISABLE_SHORTCUT && shortcut::is_local(server_id) {
                None
            } else {
                if address.eq(&STANDALONE_ADDRESS) {
                    return Err(io::Error::new(io::ErrorKind::Other, "STANDALONE server is not found"))
                }
                let mut core = Core::new()?;
                let socket_address = address.parse().unwrap();
                let future = Box::new(TcpClient::new(BytesClientProto)
                    .connect(&socket_address, &core.handle())
                    .map(|c| Timeout::new(
                        ClientCore {
                            inner: c,
                        },
                        Timer::default(),
                        timeout)));
                Some(core.run(future)?) // this is required, or client won't receive response
            }
        };
        Ok(Client {
            client,
            server_id,
        })
    }
    pub fn connect (address: &String) -> io::Result<Client> {
        Client::connect_with_timeout(address, Duration::from_secs(5))
    }
    pub fn connect_with_timeout_async (address: String, timeout: Duration)
        -> impl Future<Item = Client, Error = io::Error>
    {
        CONNECTING_POOL.spawn_fn(move ||{
            Client::connect_with_timeout(&address, timeout)
        })
    }
    pub fn connect_async (address: String)
        -> impl Future<Item = Client, Error = io::Error>
    {
        CONNECTING_POOL.spawn_fn(move || {
            Client::connect_with_timeout(&address, Duration::from_secs(5))
        })
    }
    pub fn send_async(&self, msg: Vec<u8>) -> Box<ResFuture> {
        if let Some(ref client) = self.client {
            box client.call(msg)
        } else {
            shortcut::call(self.server_id, msg)
        }
    }
}

unsafe impl Send for Client {}<|endoftext|>


<commit_before>use super::TestDatabase;
use crate::db::CratesIoData;
use crate::docbuilder::BuildResult;
use crate::utils::{Dependency, MetadataPackage, Target};
use failure::Error;

#[must_use = "FakeRelease does nothing until you call .create()"]
pub(crate) struct FakeRelease<'db> {
    db: &'db TestDatabase,
    package: MetadataPackage,
    build_result: BuildResult,
    /// name, content
    source_files: Vec<(String, Vec<u8>)>,
    /// name, content
    rustdoc_files: Vec<(String, Vec<u8>)>,
    doc_targets: Vec<String>,
    default_target: Option<String>,
    cratesio_data: CratesIoData,
    has_docs: bool,
    has_examples: bool,
}

impl<'db> FakeRelease<'db> {
    pub(super) fn new(db: &'db TestDatabase) -> Self {
        FakeRelease {
            db,
            package: MetadataPackage {
                id: "fake-package-id".into(),
                name: "fake-package".into(),
                version: "1.0.0".into(),
                license: Some("MIT".into()),
                repository: Some("https://git.example.com".into()),
                homepage: Some("https://www.example.com".into()),
                description: Some("Fake package".into()),
                documentation: Some("https://docs.example.com".into()),
                dependencies: vec![Dependency {
                    name: "fake-dependency".into(),
                    req: "^1.0.0".into(),
                    kind: None,
                }],
                targets: vec![Target::dummy_lib("fake_package".into(), None)],
                readme: None,
                keywords: vec!["fake".into(), "package".into()],
                authors: vec!["Fake Person <fake@example.com>".into()],
            },
            build_result: BuildResult {
                rustc_version: "rustc 2.0.0-nightly (000000000 1970-01-01)".into(),
                docsrs_version: "docs.rs 1.0.0 (000000000 1970-01-01)".into(),
                build_log: "It works!".into(),
                successful: true,
            },
            source_files: Vec::new(),
            rustdoc_files: Vec::new(),
            doc_targets: Vec::new(),
            default_target: None,
            cratesio_data: CratesIoData {
                release_time: time::get_time(),
                yanked: false,
                downloads: 0,
                owners: Vec::new(),
            },
            has_docs: true,
            has_examples: false,
        }
    }

    pub(crate) fn name(mut self, new: &str) -> Self {
        self.package.name = new.into();
        self.package.id = format!("{}-id", new);
        self
    }

    pub(crate) fn version(mut self, new: &str) -> Self {
        self.package.version = new.into();
        self
    }

    pub(crate) fn build_result_successful(mut self, new: bool) -> Self {
        self.build_result.successful = new;
        self
    }

    pub(crate) fn cratesio_data_yanked(mut self, new: bool) -> Self {
        self.cratesio_data.yanked = new;
        self
    }

    pub(crate) fn file<M, P, D>(mut self, mimetype: M, path: P, data: D) -> Self
        where M: Into<String>,
              P: Into<String>,
              D: Into<Vec<u8>>,
        {
        let (mimetype, path, data) = (mimetype.into(), path.into(), data.into());
        self.files.push((mimetype, path, data));
        self
    }

    pub(crate) fn rustdoc_file<P, D>(mut self, path: P, data: D) -> Self
        where P: Into<String>,
              D: Into<Vec<u8>>,
        {
        self.rustdoc_files.push((path.into(), data.into()));
        self
    }

    pub(crate) fn create(self) -> Result<i32, Error> {
        let tempdir = tempdir::TempDir::new("docs.rs-fake")?;

        let upload_files = |prefix: &str, files: Vec<(String, Vec<u8>)>, package: &MetadataPackage, db: &TestDatabase| {
            let path_prefix = tempdir.path().join(prefix);
            std::fs::create_dir(&path_prefix)?;

            for (path, data) in files {
                let file = path_prefix.join(&path);
                std::fs::write(file, data)?;
            }

            let prefix = format!("{}/{}/{}", prefix, package.name, package.version);
            crate::db::add_path_into_database(&db.conn(), &prefix, path_prefix)
        };

        let rustdoc_meta = upload_files("rustdoc", self.rustdoc_files, &self.package, self.db)?;
        log::debug!("added rustdoc files {}", rustdoc_meta);
        let source_meta = upload_files("source", self.source_files, &self.package, self.db)?;
        log::debug!("added source files {}", source_meta);

        let release_id = crate::db::add_package_into_database(
            &self.db.conn(),
            &self.package,
            tempdir.path(),
            &self.build_result,
            Some(source_meta),
            self.doc_targets,
            &self.default_target,
            &self.cratesio_data,
            self.has_docs,
            self.has_examples,
        )?;
        crate::db::add_build_into_database(&self.db.conn(), &release_id, &self.build_result)?;

        Ok(release_id)
    }
}
<commit_msg>simplify closure for test fakes<commit_after>use super::TestDatabase;
use crate::db::CratesIoData;
use crate::docbuilder::BuildResult;
use crate::utils::{Dependency, MetadataPackage, Target};
use failure::Error;

#[must_use = "FakeRelease does nothing until you call .create()"]
pub(crate) struct FakeRelease<'db> {
    db: &'db TestDatabase,
    package: MetadataPackage,
    build_result: BuildResult,
    /// name, content
    source_files: Vec<(String, Vec<u8>)>,
    /// name, content
    rustdoc_files: Vec<(String, Vec<u8>)>,
    doc_targets: Vec<String>,
    default_target: Option<String>,
    cratesio_data: CratesIoData,
    has_docs: bool,
    has_examples: bool,
}

impl<'db> FakeRelease<'db> {
    pub(super) fn new(db: &'db TestDatabase) -> Self {
        FakeRelease {
            db,
            package: MetadataPackage {
                id: "fake-package-id".into(),
                name: "fake-package".into(),
                version: "1.0.0".into(),
                license: Some("MIT".into()),
                repository: Some("https://git.example.com".into()),
                homepage: Some("https://www.example.com".into()),
                description: Some("Fake package".into()),
                documentation: Some("https://docs.example.com".into()),
                dependencies: vec![Dependency {
                    name: "fake-dependency".into(),
                    req: "^1.0.0".into(),
                    kind: None,
                }],
                targets: vec![Target::dummy_lib("fake_package".into(), None)],
                readme: None,
                keywords: vec!["fake".into(), "package".into()],
                authors: vec!["Fake Person <fake@example.com>".into()],
            },
            build_result: BuildResult {
                rustc_version: "rustc 2.0.0-nightly (000000000 1970-01-01)".into(),
                docsrs_version: "docs.rs 1.0.0 (000000000 1970-01-01)".into(),
                build_log: "It works!".into(),
                successful: true,
            },
            source_files: Vec::new(),
            rustdoc_files: Vec::new(),
            doc_targets: Vec::new(),
            default_target: None,
            cratesio_data: CratesIoData {
                release_time: time::get_time(),
                yanked: false,
                downloads: 0,
                owners: Vec::new(),
            },
            has_docs: true,
            has_examples: false,
        }
    }

    pub(crate) fn name(mut self, new: &str) -> Self {
        self.package.name = new.into();
        self.package.id = format!("{}-id", new);
        self
    }

    pub(crate) fn version(mut self, new: &str) -> Self {
        self.package.version = new.into();
        self
    }

    pub(crate) fn build_result_successful(mut self, new: bool) -> Self {
        self.build_result.successful = new;
        self
    }

    pub(crate) fn cratesio_data_yanked(mut self, new: bool) -> Self {
        self.cratesio_data.yanked = new;
        self
    }

    pub(crate) fn file<M, P, D>(mut self, mimetype: M, path: P, data: D) -> Self
        where M: Into<String>,
              P: Into<String>,
              D: Into<Vec<u8>>,
        {
        let (mimetype, path, data) = (mimetype.into(), path.into(), data.into());
        self.files.push((mimetype, path, data));
        self
    }

    pub(crate) fn rustdoc_file<P, D>(mut self, path: P, data: D) -> Self
        where P: Into<String>,
              D: Into<Vec<u8>>,
        {
        self.rustdoc_files.push((path.into(), data.into()));
        self
    }

    pub(crate) fn create(self) -> Result<i32, Error> {
        let tempdir = tempdir::TempDir::new("docs.rs-fake")?;

        let upload_files = |prefix: &str, files: &[(String, Vec<u8>)]| {
            let path_prefix = tempdir.path().join(prefix);
            std::fs::create_dir(&path_prefix)?;

            for (path, data) in files {
                let file = path_prefix.join(&path);
                std::fs::write(file, data)?;
            }

            let prefix = format!("{}/{}/{}", prefix, self.package.name, self.package.version);
            crate::db::add_path_into_database(&self.db.conn(), &prefix, path_prefix)
        };

        let rustdoc_meta = upload_files("rustdoc", &self.rustdoc_files)?;
        log::debug!("added rustdoc files {}", rustdoc_meta);
        let source_meta = upload_files("source", &self.source_files)?;
        log::debug!("added source files {}", source_meta);

        let release_id = crate::db::add_package_into_database(
            &self.db.conn(),
            &self.package,
            tempdir.path(),
            &self.build_result,
            Some(source_meta),
            self.doc_targets,
            &self.default_target,
            &self.cratesio_data,
            self.has_docs,
            self.has_examples,
        )?;
        crate::db::add_build_into_database(&self.db.conn(), &release_id, &self.build_result)?;

        Ok(release_id)
    }
}
<|endoftext|>


<commit_before>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

use Utf16Iterator;
use CharExt;
use Utf8Char;
use errors::{InvalidUtf16Slice,InvalidUtf16Tuple};
extern crate core;
use self::core::{hash,fmt,cmp};
use self::core::borrow::Borrow;
use self::core::ops::Deref;
#[cfg(feature="std")]
use std::ascii::AsciiExt;
#[cfg(feature="ascii")]
use self::core::char;
#[cfg(feature="ascii")]
extern crate ascii;
#[cfg(feature="ascii")]
use self::ascii::{AsciiChar,ToAsciiChar,ToAsciiCharError};

// I don't think there is any good default value for char, but char does.
#[derive(Default)]
// char doesn't do anything more advanced than u32 for Eq/Ord, so we shouldn't either.
// When it's a single unit, the second is zero, so Eq works.
// Ord however, breaks on surrogate pairs.
#[derive(PartialEq,Eq)]
#[derive(Clone,Copy)]

/// Store a `char` as UTF-16 so it can be borrowed as a slice
///
/// Size is identical to `char`.
/// Cannot represent all 2^32-1 possible values, but can do all valid ones.
pub struct Utf16Char {
    units: [u16; 2],
}

  /////////////////////
 //conversion traits//
/////////////////////

impl From<char> for Utf16Char {
    fn from(c: char) -> Self {
        let (first, second) = c.to_utf16_tuple();
        Utf16Char{ units: [first, second.unwrap_or(0)] }
    }
}
impl From<Utf8Char> for Utf16Char {
    fn from(utf8: Utf8Char) -> Utf16Char {
        let (b, utf8_len) = utf8.to_array();
        match utf8_len {
            1 => Utf16Char{ units: [b[0] as u16, 0] },
            4 => {// need surrogate
                let mut first = 0xd800 - (0x01_00_00u32 >> 10) as u16;
                first += (b[0] as u16 & 0x07) << 8;
                first += (b[1] as u16 & 0x3f) << 2;
                first += (b[2] as u16 & 0x30) >> 4;
                let mut second = 0xdc00;
                second |= (b[2] as u16 & 0x0f) << 6;
                second |=  b[3] as u16 & 0x3f;
                Utf16Char{ units: [first, second] }
            },
            _ => { // 2 or 3
                let mut unit = ((b[0] as u16 & 0x1f) << 6) | (b[1] as u16 & 0x3f);
                if utf8_len == 3 {
                    unit = (unit << 6) | (b[2] as u16 & 0x3f);
                }
                Utf16Char{ units: [unit, 0] }
            },
        }
    }
}
impl From<Utf16Char> for char {
    fn from(uc: Utf16Char) -> char {
        unsafe{ char::from_utf16_tuple_unchecked(uc.to_tuple()) }
    }
}
impl IntoIterator for Utf16Char {
    type Item=u16;
    type IntoIter=Utf16Iterator;
    /// Iterate over the units.
    fn into_iter(self) -> Utf16Iterator {
        Utf16Iterator::from(self)
    }
}

  /////////////////
 //getter traits//
/////////////////
impl AsRef<[u16]> for Utf16Char {
    fn as_ref(&self) -> &[u16] {
        &self.units[..self.len()]
    }
}
impl Borrow<[u16]> for Utf16Char {
    fn borrow(&self) -> &[u16] {
        self.as_ref()
    }
}
impl Deref for Utf16Char {
    type Target = [u16];
    fn deref(&self) -> &[u16] {
        self.as_ref()
    }
}

  ////////////////
 //ascii traits//
////////////////
#[cfg(feature="std")]
impl AsciiExt for Utf16Char {
    type Owned = Self;
    fn is_ascii(&self) -> bool {
        self.units[0] < 128
    }
    fn eq_ignore_ascii_case(&self,  other: &Self) -> bool {
        self.to_ascii_lowercase() == other.to_ascii_lowercase()
    }
    fn to_ascii_uppercase(&self) -> Self {
        let n = self.units[0].wrapping_sub(b'a' as u16);
        if n < 26 {Utf16Char{ units: [n+b'A' as u16, 0] }}
        else      {*self}
    }
    fn to_ascii_lowercase(&self) -> Self {
        let n = self.units[0].wrapping_sub(b'A' as u16);
        if n < 26 {Utf16Char{ units: [n+b'a' as u16, 0] }}
        else      {*self}
    }
    fn make_ascii_uppercase(&mut self) {
        *self = self.to_ascii_uppercase()
    }
    fn make_ascii_lowercase(&mut self) {
        *self = self.to_ascii_lowercase();
    }
}

#[cfg(feature="ascii")]
/// Requires feature "ascii".
impl From<AsciiChar> for Utf16Char {
    fn from(ac: AsciiChar) -> Self {
        Utf16Char{ units: [ac.as_byte() as u16, 0] }
    }
}
#[cfg(feature="ascii")]
/// Requires feature "ascii".
impl ToAsciiChar for Utf16Char {
    fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
        unsafe{ AsciiChar::from(char::from_u32_unchecked(self.units[0] as u32)) }
    }
    unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
        AsciiChar::from_unchecked(self.units[0] as u8)
    }
}

  /////////////////////////////////////////////////////////
 //Genaral traits that cannot be derived to emulate char//
/////////////////////////////////////////////////////////
impl hash::Hash for Utf16Char {
    fn hash<H : hash::Hasher>(&self,  state: &mut H) {
        self.to_char().hash(state);
    }
}
impl fmt::Debug for Utf16Char {
    fn fmt(&self,  fmtr: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.to_char(), fmtr)
    }
}
impl cmp::PartialOrd for Utf16Char {
    fn partial_cmp(&self,  rhs: &Self) -> Option<cmp::Ordering> {
        self.to_char().partial_cmp(&rhs.to_char())
    }
}
impl cmp::Ord for Utf16Char {
    fn cmp(&self,  rhs: &Self) -> cmp::Ordering {
        self.to_char().cmp(&rhs.to_char())
    }
}

  ///////////////////////////////////////////////////////
 //pub impls that should be together for nicer rustdoc//
///////////////////////////////////////////////////////
impl Utf16Char {
    /// Validate and store the first UTF-16 codepoint in the slice.
    /// Also return how many units were needed.
    pub fn from_slice(src: &[u16]) -> Result<(Self,usize), InvalidUtf16Slice> {
        char::from_utf16_slice(src).map(|(_,len)| {
            let second = if len==2 {src[1]} else {0};
            (Utf16Char{ units: [src[0], second] }, len)
        })
    }
    /// Validate and store a UTF-16 pair as returned from `char.to_utf16_tuple()`.
    pub fn from_tuple(utf16: (u16,Option<u16>)) -> Result<Self,InvalidUtf16Tuple> {
        char::from_utf16_tuple(utf16).map(|_|
            Utf16Char{ units: [utf16.0, utf16.1.unwrap_or(0)] }
        )
    }

    /// Returns 1 or 2.
    /// There is no `.is_emty()` because it would always return false.
    pub fn len(self) -> usize {
        1 + (self.units[1] as usize >> 15)
    }
    /// Is this codepoint an ASCII character?
    #[cfg(not(feature="std"))]
    pub fn is_ascii(&self) -> bool {
        self.units[0] <= 127
    }

    /// Convert from UTF-16 to UTF-32
    pub fn to_char(self) -> char {
        self.into()
    }
    /// Write the internal representation to a slice,
    /// and then returns the number of `u16`s written.
    ///
    /// # Panics
    /// Will panic the buffer is too small;
    /// You can get the required length from `.len()`,
    /// but a buffer of length two is always large enough.
    pub fn to_slice(self,  dst: &mut[u16]) -> usize {
        match self.len() {
            l if l > dst.len() => panic!("The provided buffer is too small."),
            2 => {dst[1] = self.units[1];
                  dst[0] = self.units[0];},
            1 => {dst[0] = self.units[0];},
            _ => unreachable!()
        }
        self.len()
    }
    /// The second `u16` is used for surrogate pairs.
    pub fn to_tuple(self) -> (u16,Option<u16>) {
        (self.units[0],  if self.len()==2 {Some(self.units[1])} else {None})
    }
}
<commit_msg>Optimize Utf16Char's Ord implementation<commit_after>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

use Utf16Iterator;
use CharExt;
use Utf8Char;
use errors::{InvalidUtf16Slice,InvalidUtf16Tuple};
extern crate core;
use self::core::{hash,fmt,cmp};
use self::core::borrow::Borrow;
use self::core::ops::Deref;
#[cfg(feature="std")]
use std::ascii::AsciiExt;
#[cfg(feature="ascii")]
use self::core::char;
#[cfg(feature="ascii")]
extern crate ascii;
#[cfg(feature="ascii")]
use self::ascii::{AsciiChar,ToAsciiChar,ToAsciiCharError};

// I don't think there is any good default value for char, but char does.
#[derive(Default)]
// char doesn't do anything more advanced than u32 for Eq/Ord, so we shouldn't either.
// When it's a single unit, the second is zero, so Eq works.
// Ord however, breaks on surrogate pairs.
#[derive(PartialEq,Eq)]
#[derive(Clone,Copy)]

/// Store a `char` as UTF-16 so it can be borrowed as a slice
///
/// Size is identical to `char`.
/// Cannot represent all 2^32-1 possible values, but can do all valid ones.
pub struct Utf16Char {
    units: [u16; 2],
}

  /////////////////////
 //conversion traits//
/////////////////////

impl From<char> for Utf16Char {
    fn from(c: char) -> Self {
        let (first, second) = c.to_utf16_tuple();
        Utf16Char{ units: [first, second.unwrap_or(0)] }
    }
}
impl From<Utf8Char> for Utf16Char {
    fn from(utf8: Utf8Char) -> Utf16Char {
        let (b, utf8_len) = utf8.to_array();
        match utf8_len {
            1 => Utf16Char{ units: [b[0] as u16, 0] },
            4 => {// need surrogate
                let mut first = 0xd800 - (0x01_00_00u32 >> 10) as u16;
                first += (b[0] as u16 & 0x07) << 8;
                first += (b[1] as u16 & 0x3f) << 2;
                first += (b[2] as u16 & 0x30) >> 4;
                let mut second = 0xdc00;
                second |= (b[2] as u16 & 0x0f) << 6;
                second |=  b[3] as u16 & 0x3f;
                Utf16Char{ units: [first, second] }
            },
            _ => { // 2 or 3
                let mut unit = ((b[0] as u16 & 0x1f) << 6) | (b[1] as u16 & 0x3f);
                if utf8_len == 3 {
                    unit = (unit << 6) | (b[2] as u16 & 0x3f);
                }
                Utf16Char{ units: [unit, 0] }
            },
        }
    }
}
impl From<Utf16Char> for char {
    fn from(uc: Utf16Char) -> char {
        unsafe{ char::from_utf16_tuple_unchecked(uc.to_tuple()) }
    }
}
impl IntoIterator for Utf16Char {
    type Item=u16;
    type IntoIter=Utf16Iterator;
    /// Iterate over the units.
    fn into_iter(self) -> Utf16Iterator {
        Utf16Iterator::from(self)
    }
}

  /////////////////
 //getter traits//
/////////////////
impl AsRef<[u16]> for Utf16Char {
    fn as_ref(&self) -> &[u16] {
        &self.units[..self.len()]
    }
}
impl Borrow<[u16]> for Utf16Char {
    fn borrow(&self) -> &[u16] {
        self.as_ref()
    }
}
impl Deref for Utf16Char {
    type Target = [u16];
    fn deref(&self) -> &[u16] {
        self.as_ref()
    }
}

  ////////////////
 //ascii traits//
////////////////
#[cfg(feature="std")]
impl AsciiExt for Utf16Char {
    type Owned = Self;
    fn is_ascii(&self) -> bool {
        self.units[0] < 128
    }
    fn eq_ignore_ascii_case(&self,  other: &Self) -> bool {
        self.to_ascii_lowercase() == other.to_ascii_lowercase()
    }
    fn to_ascii_uppercase(&self) -> Self {
        let n = self.units[0].wrapping_sub(b'a' as u16);
        if n < 26 {Utf16Char{ units: [n+b'A' as u16, 0] }}
        else      {*self}
    }
    fn to_ascii_lowercase(&self) -> Self {
        let n = self.units[0].wrapping_sub(b'A' as u16);
        if n < 26 {Utf16Char{ units: [n+b'a' as u16, 0] }}
        else      {*self}
    }
    fn make_ascii_uppercase(&mut self) {
        *self = self.to_ascii_uppercase()
    }
    fn make_ascii_lowercase(&mut self) {
        *self = self.to_ascii_lowercase();
    }
}

#[cfg(feature="ascii")]
/// Requires feature "ascii".
impl From<AsciiChar> for Utf16Char {
    fn from(ac: AsciiChar) -> Self {
        Utf16Char{ units: [ac.as_byte() as u16, 0] }
    }
}
#[cfg(feature="ascii")]
/// Requires feature "ascii".
impl ToAsciiChar for Utf16Char {
    fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> {
        unsafe{ AsciiChar::from(char::from_u32_unchecked(self.units[0] as u32)) }
    }
    unsafe fn to_ascii_char_unchecked(self) -> AsciiChar {
        AsciiChar::from_unchecked(self.units[0] as u8)
    }
}

  /////////////////////////////////////////////////////////
 //Genaral traits that cannot be derived to emulate char//
/////////////////////////////////////////////////////////
impl hash::Hash for Utf16Char {
    fn hash<H : hash::Hasher>(&self,  state: &mut H) {
        self.to_char().hash(state);
    }
}
impl fmt::Debug for Utf16Char {
    fn fmt(&self,  fmtr: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.to_char(), fmtr)
    }
}
impl cmp::PartialOrd for Utf16Char {
    fn partial_cmp(&self,  rhs: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(rhs))
    }
}
impl cmp::Ord for Utf16Char {
    fn cmp(&self,  rhs: &Self) -> cmp::Ordering {
        // Shift the first unit by 0xd if surrogate, and 0 otherwise.
        // This ensures surrogates are always greater than 0xffff, and
        // that the second unit only affect the result when the first are equal.
        // Multiplying by a constant factor isn't enough because that factor
        // would have to be greater than 1023 and smaller than 5.5.
        let lhs = (self.units[0] as u32, self.units[1] as u32);
        let rhs = (rhs.units[0] as u32, rhs.units[1] as u32);
        let lhs = (lhs.0 << (lhs.1 >> 12)) + lhs.1;
        let rhs = (rhs.0 << (rhs.1 >> 12)) + rhs.1;
        lhs.cmp(&rhs)
    }
}

  ///////////////////////////////////////////////////////
 //pub impls that should be together for nicer rustdoc//
///////////////////////////////////////////////////////
impl Utf16Char {
    /// Validate and store the first UTF-16 codepoint in the slice.
    /// Also return how many units were needed.
    pub fn from_slice(src: &[u16]) -> Result<(Self,usize), InvalidUtf16Slice> {
        char::from_utf16_slice(src).map(|(_,len)| {
            let second = if len==2 {src[1]} else {0};
            (Utf16Char{ units: [src[0], second] }, len)
        })
    }
    /// Validate and store a UTF-16 pair as returned from `char.to_utf16_tuple()`.
    pub fn from_tuple(utf16: (u16,Option<u16>)) -> Result<Self,InvalidUtf16Tuple> {
        char::from_utf16_tuple(utf16).map(|_|
            Utf16Char{ units: [utf16.0, utf16.1.unwrap_or(0)] }
        )
    }

    /// Returns 1 or 2.
    /// There is no `.is_emty()` because it would always return false.
    pub fn len(self) -> usize {
        1 + (self.units[1] as usize >> 15)
    }
    /// Is this codepoint an ASCII character?
    #[cfg(not(feature="std"))]
    pub fn is_ascii(&self) -> bool {
        self.units[0] <= 127
    }

    /// Convert from UTF-16 to UTF-32
    pub fn to_char(self) -> char {
        self.into()
    }
    /// Write the internal representation to a slice,
    /// and then returns the number of `u16`s written.
    ///
    /// # Panics
    /// Will panic the buffer is too small;
    /// You can get the required length from `.len()`,
    /// but a buffer of length two is always large enough.
    pub fn to_slice(self,  dst: &mut[u16]) -> usize {
        match self.len() {
            l if l > dst.len() => panic!("The provided buffer is too small."),
            2 => {dst[1] = self.units[1];
                  dst[0] = self.units[0];},
            1 => {dst[0] = self.units[0];},
            _ => unreachable!()
        }
        self.len()
    }
    /// The second `u16` is used for surrogate pairs.
    pub fn to_tuple(self) -> (u16,Option<u16>) {
        (self.units[0],  if self.len()==2 {Some(self.units[1])} else {None})
    }
}
<|endoftext|>


<commit_before>use super::LENGTH_BYTES;

pub trait Encodable {
    fn ssz_append(&self, s: &mut SszStream);
}

/// Provides a buffer for appending ssz-encodable values.
///
/// Use the `append()` fn to add a value to a list, then use
/// the `drain()` method to consume the struct and return the
/// ssz encoded bytes.
pub struct SszStream {
    buffer: Vec<u8>
}

impl SszStream {
    /// Create a new, empty stream for writing ssz values.
    pub fn new() -> Self {
        SszStream {
            buffer: Vec::new()
        }
    }

    /// Append some ssz encodable value to the stream.
    pub fn append<E>(&mut self, value: &E) -> &mut Self
        where E: Encodable
    {
        value.ssz_append(self);
        self
    }

    /// Append some ssz encoded bytes to the stream.
    ///
    /// The length of the supplied bytes will be concatenated
    /// to the stream before the supplied bytes.
    pub fn append_encoded_val(&mut self, vec: &Vec<u8>) {
        self.buffer.extend_from_slice(
            &encode_length(vec.len(),
            LENGTH_BYTES));
        self.buffer.extend_from_slice(&vec);
    }

    /// Append some vector (list) of encodable values to the stream.
    ///
    /// The length of the list will be concatenated to the stream, then
    /// each item in the vector will be encoded and concatenated.
    pub fn append_vec<E>(&mut self, vec: &Vec<E>)
        where E: Encodable
    {
        self.buffer.extend_from_slice(&encode_length(vec.len(), LENGTH_BYTES));
        for v in vec {
            v.ssz_append(self);
        }
    }

    /// Consume the stream and return the underlying bytes.
    pub fn drain(self) -> Vec<u8> {
        self.buffer
    }
}

/// Encode some length into a ssz size prefix.
///
/// The ssz size prefix is 4 bytes, which is treated as a continuious
/// 32bit big-endian integer.
pub fn encode_length(len: usize, length_bytes: usize) -> Vec<u8> {
    assert!(length_bytes > 0);  // For sanity
    assert!((len as usize) < 2usize.pow(length_bytes as u32 * 8));
    let mut header: Vec<u8> = vec![0; length_bytes];
    for i in 0..length_bytes {
        let offset = (length_bytes - i - 1) * 8;
        header[i] = ((len >> offset) & 0xff) as u8;
    };
    header
}

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

    #[test]
    #[should_panic]
    fn test_encode_length_0_bytes_panic() {
        encode_length(0, 0);
    }

    #[test]
    fn test_encode_length_4_bytes() {
        assert_eq!(
            encode_length(0, LENGTH_BYTES),
            vec![0; 3]
        );
        assert_eq!(
            encode_length(1, LENGTH_BYTES),
            vec![0, 0, 1]
        );
        assert_eq!(
            encode_length(255, LENGTH_BYTES),
            vec![0, 0, 255]
        );
        assert_eq!(
            encode_length(256, LENGTH_BYTES),
            vec![0, 1, 0]
        );
        assert_eq!(
            encode_length(16777215, LENGTH_BYTES),  // 2^(3*8) - 1
            vec![255, 255, 255]
        );
    }

    #[test]
    #[should_panic]
    fn test_encode_length_4_bytes_panic() {
        encode_length(16777216, LENGTH_BYTES);  // 2^(3*8)
    }

    /*
    #[test]
    fn test_encode_struct() {
        pub struct TestStruct {
            pub one: u32,
            pub two: H256,
            pub three: u64,
            pub four: U256,
        }

        impl Encodable for TestStruct {
            fn ssz_append(&self, s: &mut SszStream) {
                s.append(&self.one);
                s.append(&self.two);
                s.append(&self.three);
                s.append(&self.four);
            }
        }

        let t = TestStruct {
            one: 1,
            two: H256::zero(),
            three: 100,
            four: U256::zero(),
        };

        let mut s = SszStream::new();
        s.append(&t);
        let e = s.drain();

        let expected_len = {
            3 + 4 +
            3 + 32 +
            3 + 8 +
            3 + 32
        };

        assert_eq!(e[0..4], [0, 0, 0, 4]);
        assert_eq!(e[4..8], [0, 0, 0, 1]);
        assert_eq!(e[8..12], [0, 0, 0, 32]);
        assert_eq!(e[12..44], [0; 32]);
        assert_eq!(e[44..48], [0, 0, 0, 8]);
        assert_eq!(e[48..56], [0, 0, 0, 0, 0, 0, 0, 100]);
        assert_eq!(e[56..60], [0, 0, 0, 32]);
        assert_eq!(e[60..92], [0; 32]);
        assert_eq!(e.len(), expected_len);
    }
    */
}
<commit_msg>Remove commented-out function<commit_after>use super::LENGTH_BYTES;

pub trait Encodable {
    fn ssz_append(&self, s: &mut SszStream);
}

/// Provides a buffer for appending ssz-encodable values.
///
/// Use the `append()` fn to add a value to a list, then use
/// the `drain()` method to consume the struct and return the
/// ssz encoded bytes.
pub struct SszStream {
    buffer: Vec<u8>
}

impl SszStream {
    /// Create a new, empty stream for writing ssz values.
    pub fn new() -> Self {
        SszStream {
            buffer: Vec::new()
        }
    }

    /// Append some ssz encodable value to the stream.
    pub fn append<E>(&mut self, value: &E) -> &mut Self
        where E: Encodable
    {
        value.ssz_append(self);
        self
    }

    /// Append some ssz encoded bytes to the stream.
    ///
    /// The length of the supplied bytes will be concatenated
    /// to the stream before the supplied bytes.
    pub fn append_encoded_val(&mut self, vec: &Vec<u8>) {
        self.buffer.extend_from_slice(
            &encode_length(vec.len(),
            LENGTH_BYTES));
        self.buffer.extend_from_slice(&vec);
    }

    /// Append some vector (list) of encodable values to the stream.
    ///
    /// The length of the list will be concatenated to the stream, then
    /// each item in the vector will be encoded and concatenated.
    pub fn append_vec<E>(&mut self, vec: &Vec<E>)
        where E: Encodable
    {
        self.buffer.extend_from_slice(&encode_length(vec.len(), LENGTH_BYTES));
        for v in vec {
            v.ssz_append(self);
        }
    }

    /// Consume the stream and return the underlying bytes.
    pub fn drain(self) -> Vec<u8> {
        self.buffer
    }
}

/// Encode some length into a ssz size prefix.
///
/// The ssz size prefix is 4 bytes, which is treated as a continuious
/// 32bit big-endian integer.
pub fn encode_length(len: usize, length_bytes: usize) -> Vec<u8> {
    assert!(length_bytes > 0);  // For sanity
    assert!((len as usize) < 2usize.pow(length_bytes as u32 * 8));
    let mut header: Vec<u8> = vec![0; length_bytes];
    for i in 0..length_bytes {
        let offset = (length_bytes - i - 1) * 8;
        header[i] = ((len >> offset) & 0xff) as u8;
    };
    header
}

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

    #[test]
    #[should_panic]
    fn test_encode_length_0_bytes_panic() {
        encode_length(0, 0);
    }

    #[test]
    fn test_encode_length_4_bytes() {
        assert_eq!(
            encode_length(0, LENGTH_BYTES),
            vec![0; 3]
        );
        assert_eq!(
            encode_length(1, LENGTH_BYTES),
            vec![0, 0, 1]
        );
        assert_eq!(
            encode_length(255, LENGTH_BYTES),
            vec![0, 0, 255]
        );
        assert_eq!(
            encode_length(256, LENGTH_BYTES),
            vec![0, 1, 0]
        );
        assert_eq!(
            encode_length(16777215, LENGTH_BYTES),  // 2^(3*8) - 1
            vec![255, 255, 255]
        );
    }

    #[test]
    #[should_panic]
    fn test_encode_length_4_bytes_panic() {
        encode_length(16777216, LENGTH_BYTES);  // 2^(3*8)
    }
}
<|endoftext|>


<commit_before>#![feature(lookup_host)]

use std::io;
use std::net::{Ipv4Addr, Ipv6Addr};

#[derive(PartialEq)]
enum Ip {
    V4(Ipv4Addr),
    V6(Ipv6Addr),
}

fn get_ips(host: &str) -> io::Result<Vec<Ip>> {
    use std::net::{self, SocketAddr};

    let hosts = net::lookup_host(host)?;
    let ips: Vec<_> = hosts
        .filter_map(|h| match h {
            SocketAddr::V4(s_v4) => Some(Ip::V4(*s_v4.ip())),
            SocketAddr::V6(s_v6) => Some(Ip::V6(*s_v6.ip())),
        })
        .collect();
    Ok(ips)
}

fn main() {
    for ip in &(get_ips("www.kame.net").unwrap()) {
        match *ip {
            Ip::V4(ip) => println!("ip v4: {}", ip),
            Ip::V6(ip) => println!("ip v6: {}", ip),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{get_ips, Ip};
    use std::net::{Ipv4Addr, Ipv6Addr};
    use std::str::FromStr;

    #[test]
    fn ipv4() {
        let host = "203.178.141.194:80";
        if let SocketAddr::V4(addr) = host.to_socket_addrs().unwrap().next().unwrap() {
            let ip = IpAddr::V4(*addr.ip());
            assert!(get_ips("www.kame.net:80").unwrap().any(|x| x == ip));
        } else {
            panic!();
        }
    }

    #[test]
    #[ignore]
    fn ipv6() {
        let host = "2001:200:dff:fff1:216:3eff:feb1:44d7:80";
        if let SocketAddr::V6(addr) = host.to_socket_addrs().unwrap().next().unwrap() {
            let ip = IpAddr::V6(*addr.ip());
            assert!(get_ips("www.kame.net:80").unwrap().any(|x| x == ip));
        } else {
            panic!();
        }
    }
}
<commit_msg>fix dns-query<commit_after>use std::io;
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};

fn get_ips(host: &str) -> io::Result<impl Iterator<Item = IpAddr>> {
    let hosts = host.to_socket_addrs().unwrap();
    let ips = hosts.map(|h| match h {
        SocketAddr::V4(s_v4) => IpAddr::V4(*s_v4.ip()),
        SocketAddr::V6(s_v6) => IpAddr::V6(*s_v6.ip()),
    });
    Ok(ips)
}

fn main() -> io::Result<()> {
    for ip in get_ips("www.kame.net:80")? {
        match ip {
            IpAddr::V4(ip) => println!("ip v4: {}", ip),
            IpAddr::V6(ip) => println!("ip v6: {}", ip),
        }
    }

    Ok(())
}

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

    #[test]
    fn ipv4() {
        let host = "203.178.141.194:80";
        if let SocketAddr::V4(addr) = host.to_socket_addrs().unwrap().next().unwrap() {
            let ip = IpAddr::V4(*addr.ip());
            assert!(get_ips("www.kame.net:80").unwrap().any(|x| x == ip));
        } else {
            panic!();
        }
    }

    #[test]
    #[ignore]
    fn ipv6() {
        let host = "2001:200:dff:fff1:216:3eff:feb1:44d7:80";
        if let SocketAddr::V6(addr) = host.to_socket_addrs().unwrap().next().unwrap() {
            let ip = IpAddr::V6(*addr.ip());
            assert!(get_ips("www.kame.net:80").unwrap().any(|x| x == ip));
        } else {
            panic!();
        }
    }
}
<|endoftext|>


<commit_before>//! Wayland cursor utilities
//!
//! This crate aims to reimplement the functionality of the `libwayland-cursor` library in Rust.
//!
//! It allows you to load cursors from the system and display them correctly.
//!
//! First of all, you need to create a `CursorTheme`,
//! which represents the full cursor theme.
//!
//! From this theme, using the `get_cursor` method, you can load a specific `Cursor`,
//! which can contain several images if the cursor is animated. It also provides you with the
//! means of querying which frame of the animation should be displayed at
//! what time, as well as handles to the buffers containing these frames, to
//! attach them to a wayland surface.
//!
//! # Example
//!
//! ```ignore
//! use wayland_cursor::CursorTheme;
//! # use std::thread::sleep;
//! # use std::time::{Instant, Duration};
//!
//! let cursor_theme = CursorTheme::load(32, wl_shm);
//! let cursor = cursor_theme.get_cursor("wait").expect("Cursor not provided by theme");
//!
//! let start_time = Instant::now();
//! loop {
//!     // Obtain which frame we should show, and for how long.
//!     let millis = start_time.elapsed().as_millis();
//!     let fr_info = cursor.frame_and_duration(millis as u32);
//!
//!     // Here, we obtain the right cursor frame...
//!     let buffer = cursor[fr_info.frame_index];
//!     // and attach it to a wl_surface.
//!     cursor_surface.attach(Some(&buffer), 0, 0);
//!     cursor_surface.commit();
//!
//!     sleep(fr_info.frame_duration);
//! }
//! ```

use std::env;
use std::fs::File;
use std::io::{Error as IoError, Read, Result as IoResult, Seek, SeekFrom, Write};
use std::ops::{Deref, Index};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::time::{SystemTime, UNIX_EPOCH};

use nix::errno::Errno;
use nix::fcntl;
use nix::sys::{mman, stat};
use nix::unistd;
#[cfg(target_os = "linux")]
use {nix::sys::memfd, std::ffi::CStr};

use wayland_client::protocol::wl_buffer::WlBuffer;
use wayland_client::protocol::wl_shm::{Format, WlShm};
use wayland_client::protocol::wl_shm_pool::WlShmPool;
use wayland_client::{Attached, Main};

use xcursor::parser as xparser;
use xcursor::CursorTheme as XCursorTheme;
use xparser::Image as XCursorImage;

/// Represents a cursor theme loaded from the system.
pub struct CursorTheme {
    name: String,
    cursors: Vec<Cursor>,
    size: u32,
    pool: Main<WlShmPool>,
    pool_size: i32,
    file: File,
}

impl CursorTheme {
    /// Load a cursor theme from system defaults.
    ///
    /// Same as calling `load_or("default", size, shm)`
    pub fn load(size: u32, shm: &Attached<WlShm>) -> Self {
        CursorTheme::load_or("default", size, shm)
    }

    /// Load a cursor theme, using `name` as fallback.
    ///
    /// The theme name and cursor size are read from the `XCURSOR_THEME` and
    /// `XCURSOR_SIZE` environment variables, respectively, or from the provided variables
    /// if those are invalid.
    pub fn load_or(name: &str, mut size: u32, shm: &Attached<WlShm>) -> Self {
        let name_string = String::from(name);
        let name = &env::var("XCURSOR_THEME").unwrap_or(name_string);

        if let Ok(var) = env::var("XCURSOR_SIZE") {
            if let Ok(int) = var.parse() {
                size = int;
            }
        }

        CursorTheme::load_from_name(name, size, shm)
    }

    /// Create a new cursor theme, ignoring the system defaults.
    pub fn load_from_name(name: &str, size: u32, shm: &Attached<WlShm>) -> Self {
        // Set some minimal cursor size to hold it. We're not using `size` argument for that,
        // because the actual size that we'll use depends on theme sizes available on a system.
        // The minimal size covers most common minimal theme size, which is 16.
        const INITIAL_POOL_SIZE: i32 = 16 * 16 * 4;

        //  Create shm.
        let mem_fd = create_shm_fd().expect("Shm fd allocation failed");
        let mut file = unsafe { File::from_raw_fd(mem_fd) };
        file.set_len(INITIAL_POOL_SIZE as u64).expect("Failed to set buffer length");

        // Ensure that we have the same we requested.
        file.write_all(&[0; INITIAL_POOL_SIZE as usize]).expect("Write to shm fd failed");
        // Flush to ensure the compositor has access to the buffer when it tries to map it.
        file.flush().expect("Flush on shm fd failed");

        let pool = shm.create_pool(file.as_raw_fd(), INITIAL_POOL_SIZE);

        let name = String::from(name);

        CursorTheme { name, file, size, pool, pool_size: INITIAL_POOL_SIZE, cursors: Vec::new() }
    }

    /// Retrieve a cursor from the theme.
    ///
    /// This method returns `None` if this cursor is not provided
    /// either by the theme, or by one of its parents.
    pub fn get_cursor(&mut self, name: &str) -> Option<&Cursor> {
        match self.cursors.iter().position(|cursor| cursor.name == name) {
            Some(i) => Some(&self.cursors[i]),
            None => {
                let cursor = self.load_cursor(name, self.size)?;
                self.cursors.push(cursor);
                self.cursors.iter().last()
            }
        }
    }

    /// This function loads a cursor, parses it and
    /// pushes the images onto the shm pool.
    /// Keep in mind that if the cursor is already loaded,
    /// the function will make a duplicate.
    fn load_cursor(&mut self, name: &str, size: u32) -> Option<Cursor> {
        let icon_path = XCursorTheme::load(&self.name).load_icon(name)?;
        let mut icon_file = File::open(icon_path).ok()?;

        let mut buf = Vec::new();
        let images = {
            icon_file.read_to_end(&mut buf).ok()?;
            xparser::parse_xcursor(&buf)?
        };

        Some(Cursor::new(name, self, &images, size))
    }

    /// Grow the wl_shm_pool this theme is stored on.
    /// This method does nothing if the provided size is
    /// smaller or equal to the pool's current size.
    fn grow(&mut self, size: i32) {
        if size > self.pool_size {
            self.file.set_len(size as u64).expect("Failed to set new buffer length");
            self.pool.resize(size);
            self.pool_size = size;
        }
    }
}

/// A cursor from a theme. Can contain several images if animated.
#[derive(Clone)]
pub struct Cursor {
    name: String,
    images: Vec<CursorImageBuffer>,
    total_duration: u32,
}

impl Cursor {
    /// Construct a new Cursor.
    ///
    /// Each of the provided images will be written into `theme`.
    /// This will also grow `theme.pool` if necessary.
    fn new(name: &str, theme: &mut CursorTheme, images: &[XCursorImage], size: u32) -> Self {
        let mut total_duration = 0;
        let images: Vec<CursorImageBuffer> = Cursor::nearest_images(size, images)
            .map(|image| {
                let buffer = CursorImageBuffer::new(theme, image);
                total_duration += buffer.delay;

                buffer
            })
            .collect();

        Cursor { total_duration, name: String::from(name), images }
    }

    fn nearest_images(size: u32, images: &[XCursorImage]) -> impl Iterator<Item = &XCursorImage> {
        // Follow the nominal size of the cursor to choose the nearest
        let nearest_image = images
            .iter()
            .min_by_key(|image| (size as i32 - image.size as i32).abs())
            .unwrap();

        images.iter().filter(move |image| {
            image.width == nearest_image.width && image.height == nearest_image.height
        })
    }

    /// Given a time, calculate which frame to show, and how much time remains until the next frame.
    ///
    /// Time will wrap, so if for instance the cursor has an animation during 100ms,
    /// then calling this function with 5ms and 105ms as input gives the same output.
    pub fn frame_and_duration(&self, mut millis: u32) -> FrameAndDuration {
        millis %= self.total_duration;

        let mut res = 0;
        for (i, img) in self.images.iter().enumerate() {
            if millis < img.delay {
                res = i;
                break;
            }
            millis -= img.delay;
        }

        FrameAndDuration { frame_index: res, frame_duration: millis }
    }

    /// Total number of images forming this cursor animation
    pub fn image_count(&self) -> usize {
        self.images.len()
    }
}

impl Index<usize> for Cursor {
    type Output = CursorImageBuffer;

    fn index(&self, index: usize) -> &Self::Output {
        &self.images[index]
    }
}

/// A buffer containing a cursor image.
///
/// You can access the `WlBuffer` via `Deref`.
///
/// Note that this proxy will be considered as "unmanaged" by the crate, as such you should
/// not try to act on it beyond assigning it to `wl_surface`s.
#[derive(Clone)]
pub struct CursorImageBuffer {
    buffer: WlBuffer,
    delay: u32,
    xhot: u32,
    yhot: u32,
    width: u32,
    height: u32,
}

impl CursorImageBuffer {
    /// Construct a new CursorImageBuffer
    ///
    /// This function appends the pixels of the image to the provided file,
    /// and constructs a wl_buffer on that data.
    fn new(theme: &mut CursorTheme, image: &XCursorImage) -> Self {
        let buf = &image.pixels_rgba;
        let offset = theme.file.seek(SeekFrom::End(0)).unwrap();

        // Resize memory before writing to it to handle shm correctly.
        let new_size = offset + buf.len() as u64;
        theme.grow(new_size as i32);

        theme.file.write_all(&buf).unwrap();

        let buffer = theme.pool.create_buffer(
            offset as i32,
            image.width as i32,
            image.height as i32,
            (image.width * 4) as i32,
            Format::Argb8888,
        );
        buffer.quick_assign(|_, _, _| {});

        CursorImageBuffer {
            buffer: buffer.detach(),
            delay: image.delay,
            xhot: image.xhot,
            yhot: image.yhot,
            width: image.width,
            height: image.height,
        }
    }

    /// Dimensions of this image
    pub fn dimensions(&self) -> (u32, u32) {
        (self.width, self.height)
    }

    /// Location of the pointer hotspot in this image
    pub fn hotspot(&self) -> (u32, u32) {
        (self.xhot, self.yhot)
    }

    /// Time (in milliseconds) for which this image should be displayed
    pub fn delay(&self) -> u32 {
        self.delay
    }
}

impl Deref for CursorImageBuffer {
    type Target = WlBuffer;

    fn deref(&self) -> &WlBuffer {
        &self.buffer
    }
}

/// Which frame to show, and for how long.
///
/// This struct is output by `Cursor::frame_and_duration`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FrameAndDuration {
    /// The index of the frame which should be shown.
    pub frame_index: usize,
    /// The duration that the frame should be shown for (in milliseconds).
    pub frame_duration: u32,
}

/// Create a shared file descriptor in memory.
fn create_shm_fd() -> IoResult<RawFd> {
    // Only try memfd on linux.
    #[cfg(target_os = "linux")]
    loop {
        match memfd::memfd_create(
            CStr::from_bytes_with_nul(b"wayland-cursor-rs\0").unwrap(),
            memfd::MemFdCreateFlag::MFD_CLOEXEC,
        ) {
            Ok(fd) => return Ok(fd),
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(Errno::ENOSYS)) => break,
            Err(nix::Error::Sys(errno)) => return Err(IoError::from(errno)),
            Err(err) => unreachable!(err),
        }
    }

    // Fallback to using shm_open.
    let sys_time = SystemTime::now();
    let mut mem_file_handle = format!(
        "/wayland-cursor-rs-{}",
        sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
    );
    loop {
        match mman::shm_open(
            mem_file_handle.as_str(),
            fcntl::OFlag::O_CREAT
                | fcntl::OFlag::O_EXCL
                | fcntl::OFlag::O_RDWR
                | fcntl::OFlag::O_CLOEXEC,
            stat::Mode::S_IRUSR | stat::Mode::S_IWUSR,
        ) {
            Ok(fd) => match mman::shm_unlink(mem_file_handle.as_str()) {
                Ok(_) => return Ok(fd),
                Err(nix::Error::Sys(errno)) => match unistd::close(fd) {
                    Ok(_) => return Err(IoError::from(errno)),
                    Err(nix::Error::Sys(errno)) => return Err(IoError::from(errno)),
                    Err(err) => panic!("{}", err),
                },
                Err(err) => panic!("{}", err),
            },
            Err(nix::Error::Sys(Errno::EEXIST)) => {
                // If a file with that handle exists then change the handle
                mem_file_handle = format!(
                    "/wayland-cursor-rs-{}",
                    sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
                );
                continue;
            }
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(errno)) => return Err(IoError::from(errno)),
            Err(err) => unreachable!(err),
        }
    }
}
<commit_msg>cargo fmt<commit_after>//! Wayland cursor utilities
//!
//! This crate aims to reimplement the functionality of the `libwayland-cursor` library in Rust.
//!
//! It allows you to load cursors from the system and display them correctly.
//!
//! First of all, you need to create a `CursorTheme`,
//! which represents the full cursor theme.
//!
//! From this theme, using the `get_cursor` method, you can load a specific `Cursor`,
//! which can contain several images if the cursor is animated. It also provides you with the
//! means of querying which frame of the animation should be displayed at
//! what time, as well as handles to the buffers containing these frames, to
//! attach them to a wayland surface.
//!
//! # Example
//!
//! ```ignore
//! use wayland_cursor::CursorTheme;
//! # use std::thread::sleep;
//! # use std::time::{Instant, Duration};
//!
//! let cursor_theme = CursorTheme::load(32, wl_shm);
//! let cursor = cursor_theme.get_cursor("wait").expect("Cursor not provided by theme");
//!
//! let start_time = Instant::now();
//! loop {
//!     // Obtain which frame we should show, and for how long.
//!     let millis = start_time.elapsed().as_millis();
//!     let fr_info = cursor.frame_and_duration(millis as u32);
//!
//!     // Here, we obtain the right cursor frame...
//!     let buffer = cursor[fr_info.frame_index];
//!     // and attach it to a wl_surface.
//!     cursor_surface.attach(Some(&buffer), 0, 0);
//!     cursor_surface.commit();
//!
//!     sleep(fr_info.frame_duration);
//! }
//! ```

use std::env;
use std::fs::File;
use std::io::{Error as IoError, Read, Result as IoResult, Seek, SeekFrom, Write};
use std::ops::{Deref, Index};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::time::{SystemTime, UNIX_EPOCH};

use nix::errno::Errno;
use nix::fcntl;
use nix::sys::{mman, stat};
use nix::unistd;
#[cfg(target_os = "linux")]
use {nix::sys::memfd, std::ffi::CStr};

use wayland_client::protocol::wl_buffer::WlBuffer;
use wayland_client::protocol::wl_shm::{Format, WlShm};
use wayland_client::protocol::wl_shm_pool::WlShmPool;
use wayland_client::{Attached, Main};

use xcursor::parser as xparser;
use xcursor::CursorTheme as XCursorTheme;
use xparser::Image as XCursorImage;

/// Represents a cursor theme loaded from the system.
pub struct CursorTheme {
    name: String,
    cursors: Vec<Cursor>,
    size: u32,
    pool: Main<WlShmPool>,
    pool_size: i32,
    file: File,
}

impl CursorTheme {
    /// Load a cursor theme from system defaults.
    ///
    /// Same as calling `load_or("default", size, shm)`
    pub fn load(size: u32, shm: &Attached<WlShm>) -> Self {
        CursorTheme::load_or("default", size, shm)
    }

    /// Load a cursor theme, using `name` as fallback.
    ///
    /// The theme name and cursor size are read from the `XCURSOR_THEME` and
    /// `XCURSOR_SIZE` environment variables, respectively, or from the provided variables
    /// if those are invalid.
    pub fn load_or(name: &str, mut size: u32, shm: &Attached<WlShm>) -> Self {
        let name_string = String::from(name);
        let name = &env::var("XCURSOR_THEME").unwrap_or(name_string);

        if let Ok(var) = env::var("XCURSOR_SIZE") {
            if let Ok(int) = var.parse() {
                size = int;
            }
        }

        CursorTheme::load_from_name(name, size, shm)
    }

    /// Create a new cursor theme, ignoring the system defaults.
    pub fn load_from_name(name: &str, size: u32, shm: &Attached<WlShm>) -> Self {
        // Set some minimal cursor size to hold it. We're not using `size` argument for that,
        // because the actual size that we'll use depends on theme sizes available on a system.
        // The minimal size covers most common minimal theme size, which is 16.
        const INITIAL_POOL_SIZE: i32 = 16 * 16 * 4;

        //  Create shm.
        let mem_fd = create_shm_fd().expect("Shm fd allocation failed");
        let mut file = unsafe { File::from_raw_fd(mem_fd) };
        file.set_len(INITIAL_POOL_SIZE as u64).expect("Failed to set buffer length");

        // Ensure that we have the same we requested.
        file.write_all(&[0; INITIAL_POOL_SIZE as usize]).expect("Write to shm fd failed");
        // Flush to ensure the compositor has access to the buffer when it tries to map it.
        file.flush().expect("Flush on shm fd failed");

        let pool = shm.create_pool(file.as_raw_fd(), INITIAL_POOL_SIZE);

        let name = String::from(name);

        CursorTheme { name, file, size, pool, pool_size: INITIAL_POOL_SIZE, cursors: Vec::new() }
    }

    /// Retrieve a cursor from the theme.
    ///
    /// This method returns `None` if this cursor is not provided
    /// either by the theme, or by one of its parents.
    pub fn get_cursor(&mut self, name: &str) -> Option<&Cursor> {
        match self.cursors.iter().position(|cursor| cursor.name == name) {
            Some(i) => Some(&self.cursors[i]),
            None => {
                let cursor = self.load_cursor(name, self.size)?;
                self.cursors.push(cursor);
                self.cursors.iter().last()
            }
        }
    }

    /// This function loads a cursor, parses it and
    /// pushes the images onto the shm pool.
    /// Keep in mind that if the cursor is already loaded,
    /// the function will make a duplicate.
    fn load_cursor(&mut self, name: &str, size: u32) -> Option<Cursor> {
        let icon_path = XCursorTheme::load(&self.name).load_icon(name)?;
        let mut icon_file = File::open(icon_path).ok()?;

        let mut buf = Vec::new();
        let images = {
            icon_file.read_to_end(&mut buf).ok()?;
            xparser::parse_xcursor(&buf)?
        };

        Some(Cursor::new(name, self, &images, size))
    }

    /// Grow the wl_shm_pool this theme is stored on.
    /// This method does nothing if the provided size is
    /// smaller or equal to the pool's current size.
    fn grow(&mut self, size: i32) {
        if size > self.pool_size {
            self.file.set_len(size as u64).expect("Failed to set new buffer length");
            self.pool.resize(size);
            self.pool_size = size;
        }
    }
}

/// A cursor from a theme. Can contain several images if animated.
#[derive(Clone)]
pub struct Cursor {
    name: String,
    images: Vec<CursorImageBuffer>,
    total_duration: u32,
}

impl Cursor {
    /// Construct a new Cursor.
    ///
    /// Each of the provided images will be written into `theme`.
    /// This will also grow `theme.pool` if necessary.
    fn new(name: &str, theme: &mut CursorTheme, images: &[XCursorImage], size: u32) -> Self {
        let mut total_duration = 0;
        let images: Vec<CursorImageBuffer> = Cursor::nearest_images(size, images)
            .map(|image| {
                let buffer = CursorImageBuffer::new(theme, image);
                total_duration += buffer.delay;

                buffer
            })
            .collect();

        Cursor { total_duration, name: String::from(name), images }
    }

    fn nearest_images(size: u32, images: &[XCursorImage]) -> impl Iterator<Item = &XCursorImage> {
        // Follow the nominal size of the cursor to choose the nearest
        let nearest_image =
            images.iter().min_by_key(|image| (size as i32 - image.size as i32).abs()).unwrap();

        images.iter().filter(move |image| {
            image.width == nearest_image.width && image.height == nearest_image.height
        })
    }

    /// Given a time, calculate which frame to show, and how much time remains until the next frame.
    ///
    /// Time will wrap, so if for instance the cursor has an animation during 100ms,
    /// then calling this function with 5ms and 105ms as input gives the same output.
    pub fn frame_and_duration(&self, mut millis: u32) -> FrameAndDuration {
        millis %= self.total_duration;

        let mut res = 0;
        for (i, img) in self.images.iter().enumerate() {
            if millis < img.delay {
                res = i;
                break;
            }
            millis -= img.delay;
        }

        FrameAndDuration { frame_index: res, frame_duration: millis }
    }

    /// Total number of images forming this cursor animation
    pub fn image_count(&self) -> usize {
        self.images.len()
    }
}

impl Index<usize> for Cursor {
    type Output = CursorImageBuffer;

    fn index(&self, index: usize) -> &Self::Output {
        &self.images[index]
    }
}

/// A buffer containing a cursor image.
///
/// You can access the `WlBuffer` via `Deref`.
///
/// Note that this proxy will be considered as "unmanaged" by the crate, as such you should
/// not try to act on it beyond assigning it to `wl_surface`s.
#[derive(Clone)]
pub struct CursorImageBuffer {
    buffer: WlBuffer,
    delay: u32,
    xhot: u32,
    yhot: u32,
    width: u32,
    height: u32,
}

impl CursorImageBuffer {
    /// Construct a new CursorImageBuffer
    ///
    /// This function appends the pixels of the image to the provided file,
    /// and constructs a wl_buffer on that data.
    fn new(theme: &mut CursorTheme, image: &XCursorImage) -> Self {
        let buf = &image.pixels_rgba;
        let offset = theme.file.seek(SeekFrom::End(0)).unwrap();

        // Resize memory before writing to it to handle shm correctly.
        let new_size = offset + buf.len() as u64;
        theme.grow(new_size as i32);

        theme.file.write_all(&buf).unwrap();

        let buffer = theme.pool.create_buffer(
            offset as i32,
            image.width as i32,
            image.height as i32,
            (image.width * 4) as i32,
            Format::Argb8888,
        );
        buffer.quick_assign(|_, _, _| {});

        CursorImageBuffer {
            buffer: buffer.detach(),
            delay: image.delay,
            xhot: image.xhot,
            yhot: image.yhot,
            width: image.width,
            height: image.height,
        }
    }

    /// Dimensions of this image
    pub fn dimensions(&self) -> (u32, u32) {
        (self.width, self.height)
    }

    /// Location of the pointer hotspot in this image
    pub fn hotspot(&self) -> (u32, u32) {
        (self.xhot, self.yhot)
    }

    /// Time (in milliseconds) for which this image should be displayed
    pub fn delay(&self) -> u32 {
        self.delay
    }
}

impl Deref for CursorImageBuffer {
    type Target = WlBuffer;

    fn deref(&self) -> &WlBuffer {
        &self.buffer
    }
}

/// Which frame to show, and for how long.
///
/// This struct is output by `Cursor::frame_and_duration`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FrameAndDuration {
    /// The index of the frame which should be shown.
    pub frame_index: usize,
    /// The duration that the frame should be shown for (in milliseconds).
    pub frame_duration: u32,
}

/// Create a shared file descriptor in memory.
fn create_shm_fd() -> IoResult<RawFd> {
    // Only try memfd on linux.
    #[cfg(target_os = "linux")]
    loop {
        match memfd::memfd_create(
            CStr::from_bytes_with_nul(b"wayland-cursor-rs\0").unwrap(),
            memfd::MemFdCreateFlag::MFD_CLOEXEC,
        ) {
            Ok(fd) => return Ok(fd),
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(Errno::ENOSYS)) => break,
            Err(nix::Error::Sys(errno)) => return Err(IoError::from(errno)),
            Err(err) => unreachable!(err),
        }
    }

    // Fallback to using shm_open.
    let sys_time = SystemTime::now();
    let mut mem_file_handle = format!(
        "/wayland-cursor-rs-{}",
        sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
    );
    loop {
        match mman::shm_open(
            mem_file_handle.as_str(),
            fcntl::OFlag::O_CREAT
                | fcntl::OFlag::O_EXCL
                | fcntl::OFlag::O_RDWR
                | fcntl::OFlag::O_CLOEXEC,
            stat::Mode::S_IRUSR | stat::Mode::S_IWUSR,
        ) {
            Ok(fd) => match mman::shm_unlink(mem_file_handle.as_str()) {
                Ok(_) => return Ok(fd),
                Err(nix::Error::Sys(errno)) => match unistd::close(fd) {
                    Ok(_) => return Err(IoError::from(errno)),
                    Err(nix::Error::Sys(errno)) => return Err(IoError::from(errno)),
                    Err(err) => panic!("{}", err),
                },
                Err(err) => panic!("{}", err),
            },
            Err(nix::Error::Sys(Errno::EEXIST)) => {
                // If a file with that handle exists then change the handle
                mem_file_handle = format!(
                    "/wayland-cursor-rs-{}",
                    sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
                );
                continue;
            }
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(errno)) => return Err(IoError::from(errno)),
            Err(err) => unreachable!(err),
        }
    }
}
<|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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedBox", inherited=True, gecko_name="Visibility") %>

// TODO: collapse. Well, do tables first.
${helpers.single_keyword("visibility",
                         "visible hidden",
                         extra_gecko_values="collapse",
                         gecko_ffi_name="mVisible",
                         animation_value_type="ComputedValue",
                         spec="https://drafts.csswg.org/css-box/#propdef-visibility")}

// CSS Writing Modes Level 3
// https://drafts.csswg.org/css-writing-modes-3
${helpers.single_keyword("writing-mode",
                         "horizontal-tb vertical-rl vertical-lr",
                         extra_gecko_values="sideways-rl sideways-lr",
                         extra_gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \
                                              rl=horizontal-tb rl-tb=horizontal-tb \
                                              tb=vertical-rl   tb-rl=vertical-rl",
                         experimental=True,
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode")}

${helpers.single_keyword("direction", "ltr rtl", need_clone=True, animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
                         needs_conversion=True)}

${helpers.single_keyword("text-orientation",
                         "mixed upright sideways",
                         extra_gecko_aliases="sideways-right=sideways",
                         products="gecko",
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation")}

// CSS Color Module Level 4
// https://drafts.csswg.org/css-color/
${helpers.single_keyword("color-adjust",
                         "economy exact", products="gecko",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-color/#propdef-color-adjust")}

<% image_rendering_custom_consts = { "crisp-edges": "CRISPEDGES",
                                     "-moz-crisp-edges": "CRISPEDGES" } %>
// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
// And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
${helpers.single_keyword("image-rendering",
                         "auto",
                         extra_gecko_values="optimizespeed optimizequality -moz-crisp-edges",
                         extra_servo_values="pixelated crisp-edges",
                         custom_consts=image_rendering_custom_consts,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-images/#propdef-image-rendering")}

// Image Orientation
<%helpers:longhand name="image-orientation"
                   products="gecko"
                   animation_value_type="none"
    spec="https://drafts.csswg.org/css-images/#propdef-image-orientation, \
      /// additional values in https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation">
    use std::fmt;
    use style_traits::ToCss;
    use values::specified::Angle;

    use values::HasViewportPercentage;
    no_viewport_percentage!(SpecifiedValue);

    use std::f32::consts::PI;
    use values::CSSFloat;
    const TWO_PI: CSSFloat = 2.0 * PI;

    #[derive(Clone, PartialEq, Copy, Debug)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue {
        pub angle: Option<Angle>,
        pub flipped: bool
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if let Some(angle) = self.angle {
                try!(angle.to_css(dest));
                if self.flipped {
                    dest.write_str(" flipped")
                } else {
                    Ok(())
                }
            } else {
                if self.flipped {
                    dest.write_str("flipped")
                } else {
                    dest.write_str("from-image")
                }
            }
        }
    }

    pub mod computed_value {
        use values::computed::Angle;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum T {
            FromImage,
            AngleWithFlipped(Angle, bool),
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T::AngleWithFlipped(computed::Angle::zero(), false)
    }

    // According to CSS Content Module Level 3:
    // The computed value of the property is calculated by rounding the specified angle
    // to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
    #[inline]
    fn normalize_angle(angle: &computed::Angle) -> computed::Angle {
        let radians = angle.radians();
        let rounded_quarter_turns = (4.0 * radians / TWO_PI).round();
        let normalized_quarter_turns = (rounded_quarter_turns % 4.0 + 4.0) % 4.0;
        let normalized_radians = normalized_quarter_turns/4.0 * TWO_PI;
        computed::Angle::from_radians(normalized_radians)
    }

    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            if let Some(ref angle) = self.angle {
                let angle = angle.to_computed_value(context);
                let normalized_angle = normalize_angle(&angle);
                computed_value::T::AngleWithFlipped(normalized_angle, self.flipped)
            } else {
                if self.flipped {
                    computed_value::T::AngleWithFlipped(computed::Angle::zero(), true)
                } else {
                    computed_value::T::FromImage
                }
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            match *computed {
                computed_value::T::FromImage => SpecifiedValue { angle: None, flipped: false },
                computed_value::T::AngleWithFlipped(ref angle, flipped) => {
                    SpecifiedValue {
                        angle: Some(Angle::from_computed_value(angle)),
                        flipped: flipped,
                    }
                }
            }
        }
    }

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            match *self {
                computed_value::T::FromImage => dest.write_str("from-image"),
                computed_value::T::AngleWithFlipped(angle, flipped) => {
                    try!(angle.to_css(dest));
                    if flipped {
                        try!(dest.write_str(" flipped"));
                    }
                    Ok(())
                },
            }
        }
    }

    // from-image | <angle> | [<angle>? flip]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        if input.try(|input| input.expect_ident_matching("from-image")).is_ok() {
            // Handle from-image
            Ok(SpecifiedValue { angle: None, flipped: false })
        } else if input.try(|input| input.expect_ident_matching("flip")).is_ok() {
            // Handle flip
            Ok(SpecifiedValue { angle: Some(Angle::zero()), flipped: true })
        } else {
            // Handle <angle> | <angle> flip
            let angle = input.try(|input| Angle::parse(context, input)).ok();
            if angle.is_none() {
                return Err(());
            }

            let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();
            Ok(SpecifiedValue { angle: angle, flipped: flipped })
        }
    }
</%helpers:longhand>

// Used in the bottom-up flow construction traversal to avoid constructing flows for
// descendants of nodes with `display: none`.
<%helpers:longhand name="-servo-under-display-none"
                   derived_from="display"
                   products="servo"
                   animation_value_type="none"
                   spec="Nonstandard (internal layout use only)">
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::HasViewportPercentage;

    no_viewport_percentage!(SpecifiedValue);

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
    pub struct SpecifiedValue(pub bool);

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }
    impl ComputedValueAsSpecified for SpecifiedValue {}

    pub fn get_initial_value() -> computed_value::T {
        SpecifiedValue(false)
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write {
            Ok(()) // Internal property
        }
    }

    #[inline]
    pub fn derive_from_display(context: &mut Context) {
        use super::display::computed_value::T as Display;

        if context.style().get_box().clone_display() == Display::none {
            context.mutate_style().mutate_inheritedbox()
                                  .set__servo_under_display_none(SpecifiedValue(true));
        }
    }
</%helpers:longhand>
<commit_msg>Fix serialisation of 'image-orientation: <angle> flip'<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedBox", inherited=True, gecko_name="Visibility") %>

// TODO: collapse. Well, do tables first.
${helpers.single_keyword("visibility",
                         "visible hidden",
                         extra_gecko_values="collapse",
                         gecko_ffi_name="mVisible",
                         animation_value_type="ComputedValue",
                         spec="https://drafts.csswg.org/css-box/#propdef-visibility")}

// CSS Writing Modes Level 3
// https://drafts.csswg.org/css-writing-modes-3
${helpers.single_keyword("writing-mode",
                         "horizontal-tb vertical-rl vertical-lr",
                         extra_gecko_values="sideways-rl sideways-lr",
                         extra_gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \
                                              rl=horizontal-tb rl-tb=horizontal-tb \
                                              tb=vertical-rl   tb-rl=vertical-rl",
                         experimental=True,
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode")}

${helpers.single_keyword("direction", "ltr rtl", need_clone=True, animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
                         needs_conversion=True)}

${helpers.single_keyword("text-orientation",
                         "mixed upright sideways",
                         extra_gecko_aliases="sideways-right=sideways",
                         products="gecko",
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation")}

// CSS Color Module Level 4
// https://drafts.csswg.org/css-color/
${helpers.single_keyword("color-adjust",
                         "economy exact", products="gecko",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-color/#propdef-color-adjust")}

<% image_rendering_custom_consts = { "crisp-edges": "CRISPEDGES",
                                     "-moz-crisp-edges": "CRISPEDGES" } %>
// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
// And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
${helpers.single_keyword("image-rendering",
                         "auto",
                         extra_gecko_values="optimizespeed optimizequality -moz-crisp-edges",
                         extra_servo_values="pixelated crisp-edges",
                         custom_consts=image_rendering_custom_consts,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-images/#propdef-image-rendering")}

// Image Orientation
<%helpers:longhand name="image-orientation"
                   products="gecko"
                   animation_value_type="none"
    spec="https://drafts.csswg.org/css-images/#propdef-image-orientation, \
      /// additional values in https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation">
    use std::fmt;
    use style_traits::ToCss;
    use values::specified::Angle;

    use values::HasViewportPercentage;
    no_viewport_percentage!(SpecifiedValue);

    use std::f32::consts::PI;
    use values::CSSFloat;
    const TWO_PI: CSSFloat = 2.0 * PI;

    #[derive(Clone, PartialEq, Copy, Debug)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue {
        pub angle: Option<Angle>,
        pub flipped: bool
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if let Some(angle) = self.angle {
                try!(angle.to_css(dest));
                if self.flipped {
                    dest.write_str(" flipped")
                } else {
                    Ok(())
                }
            } else {
                if self.flipped {
                    dest.write_str("flipped")
                } else {
                    dest.write_str("from-image")
                }
            }
        }
    }

    pub mod computed_value {
        use values::computed::Angle;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum T {
            FromImage,
            AngleWithFlipped(Angle, bool),
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T::AngleWithFlipped(computed::Angle::zero(), false)
    }

    // According to CSS Content Module Level 3:
    // The computed value of the property is calculated by rounding the specified angle
    // to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
    #[inline]
    fn normalize_angle(angle: &computed::Angle) -> computed::Angle {
        let radians = angle.radians();
        let rounded_quarter_turns = (4.0 * radians / TWO_PI).round();
        let normalized_quarter_turns = (rounded_quarter_turns % 4.0 + 4.0) % 4.0;
        let normalized_radians = normalized_quarter_turns/4.0 * TWO_PI;
        computed::Angle::from_radians(normalized_radians)
    }

    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            if let Some(ref angle) = self.angle {
                let angle = angle.to_computed_value(context);
                let normalized_angle = normalize_angle(&angle);
                computed_value::T::AngleWithFlipped(normalized_angle, self.flipped)
            } else {
                if self.flipped {
                    computed_value::T::AngleWithFlipped(computed::Angle::zero(), true)
                } else {
                    computed_value::T::FromImage
                }
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            match *computed {
                computed_value::T::FromImage => SpecifiedValue { angle: None, flipped: false },
                computed_value::T::AngleWithFlipped(ref angle, flipped) => {
                    SpecifiedValue {
                        angle: Some(Angle::from_computed_value(angle)),
                        flipped: flipped,
                    }
                }
            }
        }
    }

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            match *self {
                computed_value::T::FromImage => dest.write_str("from-image"),
                computed_value::T::AngleWithFlipped(angle, flipped) => {
                    try!(angle.to_css(dest));
                    if flipped {
                        try!(dest.write_str(" flip"));
                    }
                    Ok(())
                },
            }
        }
    }

    // from-image | <angle> | [<angle>? flip]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        if input.try(|input| input.expect_ident_matching("from-image")).is_ok() {
            // Handle from-image
            Ok(SpecifiedValue { angle: None, flipped: false })
        } else if input.try(|input| input.expect_ident_matching("flip")).is_ok() {
            // Handle flip
            Ok(SpecifiedValue { angle: Some(Angle::zero()), flipped: true })
        } else {
            // Handle <angle> | <angle> flip
            let angle = input.try(|input| Angle::parse(context, input)).ok();
            if angle.is_none() {
                return Err(());
            }

            let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();
            Ok(SpecifiedValue { angle: angle, flipped: flipped })
        }
    }
</%helpers:longhand>

// Used in the bottom-up flow construction traversal to avoid constructing flows for
// descendants of nodes with `display: none`.
<%helpers:longhand name="-servo-under-display-none"
                   derived_from="display"
                   products="servo"
                   animation_value_type="none"
                   spec="Nonstandard (internal layout use only)">
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::HasViewportPercentage;

    no_viewport_percentage!(SpecifiedValue);

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
    pub struct SpecifiedValue(pub bool);

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }
    impl ComputedValueAsSpecified for SpecifiedValue {}

    pub fn get_initial_value() -> computed_value::T {
        SpecifiedValue(false)
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write {
            Ok(()) // Internal property
        }
    }

    #[inline]
    pub fn derive_from_display(context: &mut Context) {
        use super::display::computed_value::T as Display;

        if context.style().get_box().clone_display() == Display::none {
            context.mutate_style().mutate_inheritedbox()
                                  .set__servo_under_display_none(SpecifiedValue(true));
        }
    }
</%helpers:longhand>
<|endoftext|>