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

use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{
    self, TextTrackKind, TextTrackMethods, TextTrackMode,
};
use crate::dom::bindings::error::{Error, ErrorResult};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::eventtarget::EventTarget;
use crate::dom::texttrackcue::TextTrackCue;
use crate::dom::texttrackcuelist::TextTrackCueList;
use crate::dom::window::Window;
use dom_struct::dom_struct;
use std::cell::Cell;

#[dom_struct]
pub struct TextTrack {
    eventtarget: EventTarget,
    kind: TextTrackKind,
    label: String,
    language: String,
    id: String,
    mode: Cell<TextTrackMode>,
    cue_list: MutNullableDom<TextTrackCueList>,
}

impl TextTrack {
    pub fn new_inherited(
        id: DOMString,
        kind: TextTrackKind,
        label: DOMString,
        language: DOMString,
        mode: TextTrackMode,
    ) -> TextTrack {
        TextTrack {
            eventtarget: EventTarget::new_inherited(),
            kind: kind,
            label: label.into(),
            language: language.into(),
            id: id.into(),
            mode: Cell::new(mode),
            cue_list: Default::default(),
        }
    }

    pub fn new(
        window: &Window,
        id: DOMString,
        kind: TextTrackKind,
        label: DOMString,
        language: DOMString,
        mode: TextTrackMode,
    ) -> DomRoot<TextTrack> {
        reflect_dom_object(
            Box::new(TextTrack::new_inherited(id, kind, label, language, mode)),
            window,
            TextTrackBinding::Wrap,
        )
    }

    pub fn get_cues(&self) -> DomRoot<TextTrackCueList> {
        self.cue_list
            .or_init(|| TextTrackCueList::new(&self.global().as_window(), &[]))
    }

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

impl TextTrackMethods for TextTrack {
    // https://html.spec.whatwg.org/multipage/#dom-texttrack-kind
    fn Kind(&self) -> TextTrackKind {
        self.kind
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-label
    fn Label(&self) -> DOMString {
        DOMString::from(self.label.clone())
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-language
    fn Language(&self) -> DOMString {
        DOMString::from(self.language.clone())
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-id
    fn Id(&self) -> DOMString {
        DOMString::from(self.id.clone())
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-mode
    fn Mode(&self) -> TextTrackMode {
        self.mode.get()
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-mode
    fn SetMode(&self, value: TextTrackMode) {
        self.mode.set(value)
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-cues
    fn GetCues(&self) -> Option<DomRoot<TextTrackCueList>> {
        match self.Mode() {
            TextTrackMode::Disabled => None,
            _ => Some(self.get_cues()),
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-activecues
    fn GetActiveCues(&self) -> Option<DomRoot<TextTrackCueList>> {
        // XXX implement active cues logic
        //      https://github.com/servo/servo/issues/22314
        None
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-addcue
    fn AddCue(&self, cue: &TextTrackCue) -> ErrorResult {
        // FIXME(#22314, dlrobertson) add Step 1 & 2
        // Step 3
        if let Some(old_track) = cue.get_track() {
            // gecko calls RemoveCue when the given cue
            // has an associated track, but doesn't return
            // the error from it, so we wont either.
            if let Err(_) = old_track.RemoveCue(cue) {
                warn!("Failed to remove cues for the added cue's text track");
            }
        }
        // Step 4
        self.get_cues().add(cue);
        Ok(())
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-removecue
    fn RemoveCue(&self, cue: &TextTrackCue) -> ErrorResult {
        // Step 1
        let cues = self.get_cues();
        let index = match cues.find(cue) {
            Some(i) => Ok(i),
            None => Err(Error::NotFound),
        }?;
        // Step 2
        cues.remove(index);
        Ok(())
    }

    // https://html.spec.whatwg.org/multipage/#handler-texttrack-oncuechange
    event_handler!(oncuechange, GetOncuechange, SetOncuechange);
}
<commit_msg>Auto merge of #22730 - aditj:patch-2, r=ferjm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{
    self, TextTrackKind, TextTrackMethods, TextTrackMode,
};
use crate::dom::bindings::error::{Error, ErrorResult};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::eventtarget::EventTarget;
use crate::dom::texttrackcue::TextTrackCue;
use crate::dom::texttrackcuelist::TextTrackCueList;
use crate::dom::window::Window;
use dom_struct::dom_struct;
use std::cell::Cell;

#[dom_struct]
pub struct TextTrack {
    eventtarget: EventTarget,
    kind: TextTrackKind,
    label: String,
    language: String,
    id: String,
    mode: Cell<TextTrackMode>,
    cue_list: MutNullableDom<TextTrackCueList>,
}

impl TextTrack {
    pub fn new_inherited(
        id: DOMString,
        kind: TextTrackKind,
        label: DOMString,
        language: DOMString,
        mode: TextTrackMode,
    ) -> TextTrack {
        TextTrack {
            eventtarget: EventTarget::new_inherited(),
            kind: kind,
            label: label.into(),
            language: language.into(),
            id: id.into(),
            mode: Cell::new(mode),
            cue_list: Default::default(),
        }
    }

    pub fn new(
        window: &Window,
        id: DOMString,
        kind: TextTrackKind,
        label: DOMString,
        language: DOMString,
        mode: TextTrackMode,
    ) -> DomRoot<TextTrack> {
        reflect_dom_object(
            Box::new(TextTrack::new_inherited(id, kind, label, language, mode)),
            window,
            TextTrackBinding::Wrap,
        )
    }

    pub fn get_cues(&self) -> DomRoot<TextTrackCueList> {
        self.cue_list
            .or_init(|| TextTrackCueList::new(&self.global().as_window(), &[]))
    }

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

impl TextTrackMethods for TextTrack {
    // https://html.spec.whatwg.org/multipage/#dom-texttrack-kind
    fn Kind(&self) -> TextTrackKind {
        self.kind
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-label
    fn Label(&self) -> DOMString {
        DOMString::from(self.label.clone())
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-language
    fn Language(&self) -> DOMString {
        DOMString::from(self.language.clone())
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-id
    fn Id(&self) -> DOMString {
        DOMString::from(self.id.clone())
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-mode
    fn Mode(&self) -> TextTrackMode {
        self.mode.get()
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-mode
    fn SetMode(&self, value: TextTrackMode) {
        self.mode.set(value)
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-cues
    fn GetCues(&self) -> Option<DomRoot<TextTrackCueList>> {
        match self.Mode() {
            TextTrackMode::Disabled => None,
            _ => Some(self.get_cues()),
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-activecues
    fn GetActiveCues(&self) -> Option<DomRoot<TextTrackCueList>> {
        // XXX implement active cues logic
        //      https://github.com/servo/servo/issues/22314
        Some(TextTrackCueList::new(&self.global().as_window(), &[]))
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-addcue
    fn AddCue(&self, cue: &TextTrackCue) -> ErrorResult {
        // FIXME(#22314, dlrobertson) add Step 1 & 2
        // Step 3
        if let Some(old_track) = cue.get_track() {
            // gecko calls RemoveCue when the given cue
            // has an associated track, but doesn't return
            // the error from it, so we wont either.
            if let Err(_) = old_track.RemoveCue(cue) {
                warn!("Failed to remove cues for the added cue's text track");
            }
        }
        // Step 4
        self.get_cues().add(cue);
        Ok(())
    }

    // https://html.spec.whatwg.org/multipage/#dom-texttrack-removecue
    fn RemoveCue(&self, cue: &TextTrackCue) -> ErrorResult {
        // Step 1
        let cues = self.get_cues();
        let index = match cues.find(cue) {
            Some(i) => Ok(i),
            None => Err(Error::NotFound),
        }?;
        // Step 2
        cues.remove(index);
        Ok(())
    }

    // https://html.spec.whatwg.org/multipage/#handler-texttrack-oncuechange
    event_handler!(oncuechange, GetOncuechange, SetOncuechange);
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! MSVC-specific logic for linkers and such.
//!
//! This module contains a cross-platform interface but has a blank unix
//! implementation. The Windows implementation builds on top of Windows native
//! libraries (reading registry keys), so it otherwise wouldn't link on unix.
//!
//! Note that we don't have much special logic for finding the system linker on
//! any other platforms, so it may seem a little odd to single out MSVC to have
//! a good deal of code just to find the linker. Unlike Unix systems, however,
//! the MSVC linker is not in the system PATH by default. It also additionally
//! needs a few environment variables or command line flags to be able to link
//! against system libraries.
//!
//! In order to have a nice smooth experience on Windows, the logic in this file
//! is here to find the MSVC linker and set it up in the default configuration
//! one would need to set up anyway. This means that the Rust compiler can be
//! run not only in the developer shells of MSVC but also the standard cmd.exe
//! shell or MSYS shells.
//!
//! As a high-level note, all logic in this module for looking up various
//! paths/files is based on Microsoft's logic in their vcvars bat files, but
//! comments can also be found below leading through the various code paths.

use std::process::Command;
use session::Session;

#[cfg(windows)]
mod registry;

#[cfg(windows)]
pub fn link_exe_cmd(sess: &Session) -> Command {
    use std::env;
    use std::ffi::OsString;
    use std::fs;
    use std::path::{Path, PathBuf};
    use self::registry::{LOCAL_MACHINE};

    let arch = &sess.target.target.arch;
    let (binsub, libsub, vclibsub) =
        match (bin_subdir(arch), lib_subdir(arch), vc_lib_subdir(arch)) {
        (Some(x), Some(y), Some(z)) => (x, y, z),
        _ => return Command::new("link.exe"),
    };

    // First we need to figure out whether the environment is already correctly
    // configured by vcvars. We do this by looking at the environment variable
    // `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
    // otherwise. If it is defined, then we derive the path to `link.exe` from
    // that and trust that everything else is configured correctly.
    //
    // If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where it
    // claimed it should be), then we resort to finding everything ourselves.
    // First we find where the latest version of MSVC is installed and what
    // version it is. Then based on the version we find the appropriate SDKs.
    //
    // For MSVC 14 (VS 2015) we look for the Win10 SDK and failing that we look
    // for the Win8.1 SDK. We also look for the Universal CRT.
    //
    // For MSVC 12 (VS 2013) we look for the Win8.1 SDK.
    //
    // For MSVC 11 (VS 2012) we look for the Win8 SDK.
    //
    // For all other versions the user has to execute the appropriate vcvars bat
    // file themselves to configure the environment.
    //
    // If despite our best efforts we are still unable to find MSVC then we just
    // blindly call `link.exe` and hope for the best.
    return env::var_os("VCINSTALLDIR").and_then(|dir| {
        debug!("Environment already configured by user. Assuming it works.");
        let mut p = PathBuf::from(dir);
        p.push("bin");
        p.push(binsub);
        p.push("link.exe");
        if !p.is_file() { return None }
        Some(Command::new(p))
    }).or_else(|| {
        get_vc_dir().and_then(|(ver, vcdir)| {
            debug!("Found VC installation directory {:?}", vcdir);
            let mut linker = vcdir.clone();
            linker.push("bin");
            linker.push(binsub);
            linker.push("link.exe");
            if !linker.is_file() { return None }
            let mut cmd = Command::new(linker);
            add_lib(&mut cmd, &vcdir.join("lib").join(vclibsub));
            if ver == "14.0" {
                if let Some(dir) = get_ucrt_dir() {
                    debug!("Found Universal CRT {:?}", dir);
                    add_lib(&mut cmd, &dir.join("ucrt").join(libsub));
                }
                if let Some(dir) = get_sdk10_dir() {
                    debug!("Found Win10 SDK {:?}", dir);
                    add_lib(&mut cmd, &dir.join("um").join(libsub));
                } else if let Some(dir) = get_sdk81_dir() {
                    debug!("Found Win8.1 SDK {:?}", dir);
                    add_lib(&mut cmd, &dir.join("um").join(libsub));
                }
            } else if ver == "12.0" {
                if let Some(dir) = get_sdk81_dir() {
                    debug!("Found Win8.1 SDK {:?}", dir);
                    add_lib(&mut cmd, &dir.join("um").join(libsub));
                }
            } else { // ver == "11.0"
                if let Some(dir) = get_sdk8_dir() {
                    debug!("Found Win8 SDK {:?}", dir);
                    add_lib(&mut cmd, &dir.join("um").join(libsub));
                }
            }
            Some(cmd)
        })
    }).unwrap_or_else(|| {
        debug!("Failed to locate linker.");
        Command::new("link.exe")
    });

    // A convenience function to make the above code simpler
    fn add_lib(cmd: &mut Command, lib: &Path) {
        let mut arg: OsString = "/LIBPATH:".into();
        arg.push(lib);
        cmd.arg(arg);
    }

    // To find MSVC we look in a specific registry key for the newest of the
    // three versions that we support.
    fn get_vc_dir() -> Option<(&'static str, PathBuf)> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7".as_ref())
        .ok().and_then(|key| {
            ["14.0", "12.0", "11.0"].iter().filter_map(|ver| {
                key.query_str(ver).ok().map(|p| (*ver, p.into()))
            }).next()
        })
    }

    // To find the Universal CRT we look in a specific registry key for where
    // all the Universal CRTs are located and then sort them asciibetically to
    // find the newest version. While this sort of sorting isn't ideal,  it is
    // what vcvars does so that's good enough for us.
    fn get_ucrt_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots".as_ref())
        .ok().and_then(|key| {
            key.query_str("KitsRoot10").ok()
        }).and_then(|root| {
            fs::read_dir(Path::new(&root).join("Lib")).ok()
        }).and_then(|readdir| {
            let mut dirs: Vec<_> = readdir.filter_map(|dir| dir.ok())
                .map(|dir| dir.path()).collect();
            dirs.sort();
            dirs.pop()
        })
    }

    // Vcvars finds the correct version of the Windows 10 SDK by looking
    // for the include um/Windows.h because sometimes a given version will
    // only have UCRT bits without the rest of the SDK. Since we only care about
    // libraries and not includes, we just look for the folder `um` in the lib
    // section. Like we do for the Universal CRT, we sort the possibilities
    // asciibetically to find the newest one as that is what vcvars does.
    fn get_sdk10_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0".as_ref())
        .ok().and_then(|key| {
            key.query_str("InstallationFolder").ok()
        }).and_then(|root| {
            fs::read_dir(Path::new(&root).join("lib")).ok()
        }).and_then(|readdir| {
            let mut dirs: Vec<_> = readdir.filter_map(|dir| dir.ok())
                .map(|dir| dir.path()).collect();
            dirs.sort();
            dirs.into_iter().rev().filter(|dir| {
                dir.join("um").is_dir()
            }).next()
        })
    }

    // Interestingly there are several subdirectories, `win7` `win8` and
    // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same
    // applies to us. Note that if we were targetting kernel mode drivers
    // instead of user mode applications, we would care.
    fn get_sdk81_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1".as_ref())
        .ok().and_then(|key| {
            key.query_str("InstallationFolder").ok()
        }).map(|root| {
            Path::new(&root).join("lib").join("winv6.3")
        })
    }

    fn get_sdk8_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0".as_ref())
        .ok().and_then(|key| {
            key.query_str("InstallationFolder").ok()
        }).map(|root| {
            Path::new(&root).join("lib").join("win8")
        })
    }

    // When choosing the linker toolchain to use, we have to choose the one
    // which matches the host architecture. Otherwise we end up in situations
    // where someone on 32-bit Windows is trying to cross compile to 64-bit and
    // it tries to invoke the native 64-bit linker which won't work.
    //
    // FIXME - This currently functions based on the host architecture of rustc
    // itself but it should instead detect the bitness of the OS itself.
    //
    // FIXME - Figure out what happens when the host architecture is arm.
    //
    // FIXME - Some versions of MSVC may not come with all these toolchains.
    // Consider returning an array of toolchains and trying them one at a time
    // until the linker is found.
    fn bin_subdir(arch: &str) -> Option<&'static str> {
        if cfg!(target_arch = "x86_64") {
            match arch {
                "x86" => Some("amd64_x86"),
                "x86_64" => Some("amd64"),
                "arm" => Some("amd64_arm"),
                _ => None,
            }
        } else if cfg!(target_arch = "x86") {
            match arch {
                "x86" => Some(""),
                "x86_64" => Some("x86_amd64"),
                "arm" => Some("x86_arm"),
                _ => None,
            }
        } else { None }
    }
    fn lib_subdir(arch: &str) -> Option<&'static str> {
        match arch {
            "x86" => Some("x86"),
            "x86_64" => Some("x64"),
            "arm" => Some("arm"),
            _ => None,
        }
    }
    // MSVC's x86 libraries are not in a subfolder
    fn vc_lib_subdir(arch: &str) -> Option<&'static str> {
        match arch {
            "x86" => Some(""),
            "x86_64" => Some("amd64"),
            "arm" => Some("arm"),
            _ => None,
        }
    }
}

// If we're not on Windows, then there's no registry to search through and MSVC
// wouldn't be able to run, so we just call `link.exe` and hope for the best.
#[cfg(not(windows))]
pub fn link_exe_cmd(_sess: &Session) -> Command {
    Command::new("link.exe")
}
<commit_msg>Auto merge of #30516 - retep998:non-universal-crt, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! MSVC-specific logic for linkers and such.
//!
//! This module contains a cross-platform interface but has a blank unix
//! implementation. The Windows implementation builds on top of Windows native
//! libraries (reading registry keys), so it otherwise wouldn't link on unix.
//!
//! Note that we don't have much special logic for finding the system linker on
//! any other platforms, so it may seem a little odd to single out MSVC to have
//! a good deal of code just to find the linker. Unlike Unix systems, however,
//! the MSVC linker is not in the system PATH by default. It also additionally
//! needs a few environment variables or command line flags to be able to link
//! against system libraries.
//!
//! In order to have a nice smooth experience on Windows, the logic in this file
//! is here to find the MSVC linker and set it up in the default configuration
//! one would need to set up anyway. This means that the Rust compiler can be
//! run not only in the developer shells of MSVC but also the standard cmd.exe
//! shell or MSYS shells.
//!
//! As a high-level note, all logic in this module for looking up various
//! paths/files is based on Microsoft's logic in their vcvars bat files, but
//! comments can also be found below leading through the various code paths.

use std::process::Command;
use session::Session;

#[cfg(windows)]
mod registry;

#[cfg(windows)]
pub fn link_exe_cmd(sess: &Session) -> Command {
    use std::env;
    use std::ffi::OsString;
    use std::fs;
    use std::path::{Path, PathBuf};
    use self::registry::{LOCAL_MACHINE};

    let arch = &sess.target.target.arch;
    let (binsub, libsub, vclibsub) =
        match (bin_subdir(arch), lib_subdir(arch), vc_lib_subdir(arch)) {
        (Some(x), Some(y), Some(z)) => (x, y, z),
        _ => return Command::new("link.exe"),
    };

    // First we need to figure out whether the environment is already correctly
    // configured by vcvars. We do this by looking at the environment variable
    // `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
    // otherwise. If it is defined, then we derive the path to `link.exe` from
    // that and trust that everything else is configured correctly.
    //
    // If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where it
    // claimed it should be), then we resort to finding everything ourselves.
    // First we find where the latest version of MSVC is installed and what
    // version it is. Then based on the version we find the appropriate SDKs.
    //
    // For MSVC 14 (VS 2015) we look for the Win10 SDK and failing that we look
    // for the Win8.1 SDK. We also look for the Universal CRT.
    //
    // For MSVC 12 (VS 2013) we look for the Win8.1 SDK.
    //
    // For MSVC 11 (VS 2012) we look for the Win8 SDK.
    //
    // For all other versions the user has to execute the appropriate vcvars bat
    // file themselves to configure the environment.
    //
    // If despite our best efforts we are still unable to find MSVC then we just
    // blindly call `link.exe` and hope for the best.
    return env::var_os("VCINSTALLDIR").and_then(|dir| {
        debug!("Environment already configured by user. Assuming it works.");
        let mut p = PathBuf::from(dir);
        p.push("bin");
        p.push(binsub);
        p.push("link.exe");
        if !p.is_file() { return None }
        Some(Command::new(p))
    }).or_else(|| {
        get_vc_dir().and_then(|(ver, vcdir)| {
            debug!("Found VC installation directory {:?}", vcdir);
            let mut linker = vcdir.clone();
            linker.push("bin");
            linker.push(binsub);
            linker.push("link.exe");
            if !linker.is_file() { return None }
            let mut cmd = Command::new(linker);
            add_lib(&mut cmd, &vcdir.join("lib").join(vclibsub));
            if ver == "14.0" {
                if let Some(dir) = get_ucrt_dir() {
                    debug!("Found Universal CRT {:?}", dir);
                    add_lib(&mut cmd, &dir.join("ucrt").join(libsub));
                }
                if let Some(dir) = get_sdk10_dir() {
                    debug!("Found Win10 SDK {:?}", dir);
                    add_lib(&mut cmd, &dir.join("um").join(libsub));
                } else if let Some(dir) = get_sdk81_dir() {
                    debug!("Found Win8.1 SDK {:?}", dir);
                    add_lib(&mut cmd, &dir.join("um").join(libsub));
                }
            } else if ver == "12.0" {
                if let Some(dir) = get_sdk81_dir() {
                    debug!("Found Win8.1 SDK {:?}", dir);
                    add_lib(&mut cmd, &dir.join("um").join(libsub));
                }
            } else { // ver == "11.0"
                if let Some(dir) = get_sdk8_dir() {
                    debug!("Found Win8 SDK {:?}", dir);
                    add_lib(&mut cmd, &dir.join("um").join(libsub));
                }
            }
            Some(cmd)
        })
    }).unwrap_or_else(|| {
        debug!("Failed to locate linker.");
        Command::new("link.exe")
    });

    // A convenience function to make the above code simpler
    fn add_lib(cmd: &mut Command, lib: &Path) {
        let mut arg: OsString = "/LIBPATH:".into();
        arg.push(lib);
        cmd.arg(arg);
    }

    // To find MSVC we look in a specific registry key for the newest of the
    // three versions that we support.
    fn get_vc_dir() -> Option<(&'static str, PathBuf)> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7".as_ref())
        .ok().and_then(|key| {
            ["14.0", "12.0", "11.0"].iter().filter_map(|ver| {
                key.query_str(ver).ok().map(|p| (*ver, p.into()))
            }).next()
        })
    }

    // To find the Universal CRT we look in a specific registry key for where
    // all the Universal CRTs are located and then sort them asciibetically to
    // find the newest version. While this sort of sorting isn't ideal,  it is
    // what vcvars does so that's good enough for us.
    fn get_ucrt_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots".as_ref())
        .ok().and_then(|key| {
            key.query_str("KitsRoot10").ok()
        }).and_then(|root| {
            fs::read_dir(Path::new(&root).join("Lib")).ok()
        }).and_then(|readdir| {
            let mut dirs: Vec<_> = readdir.filter_map(|dir| {
                dir.ok()
            }).map(|dir| {
                dir.path()
            }).filter(|dir| {
                dir.components().last().and_then(|c| {
                    c.as_os_str().to_str()
                }).map(|c| c.starts_with("10.")).unwrap_or(false)
            }).collect();
            dirs.sort();
            dirs.pop()
        })
    }

    // Vcvars finds the correct version of the Windows 10 SDK by looking
    // for the include um/Windows.h because sometimes a given version will
    // only have UCRT bits without the rest of the SDK. Since we only care about
    // libraries and not includes, we just look for the folder `um` in the lib
    // section. Like we do for the Universal CRT, we sort the possibilities
    // asciibetically to find the newest one as that is what vcvars does.
    fn get_sdk10_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0".as_ref())
        .ok().and_then(|key| {
            key.query_str("InstallationFolder").ok()
        }).and_then(|root| {
            fs::read_dir(Path::new(&root).join("lib")).ok()
        }).and_then(|readdir| {
            let mut dirs: Vec<_> = readdir.filter_map(|dir| dir.ok())
                .map(|dir| dir.path()).collect();
            dirs.sort();
            dirs.into_iter().rev().filter(|dir| {
                dir.join("um").is_dir()
            }).next()
        })
    }

    // Interestingly there are several subdirectories, `win7` `win8` and
    // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same
    // applies to us. Note that if we were targetting kernel mode drivers
    // instead of user mode applications, we would care.
    fn get_sdk81_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1".as_ref())
        .ok().and_then(|key| {
            key.query_str("InstallationFolder").ok()
        }).map(|root| {
            Path::new(&root).join("lib").join("winv6.3")
        })
    }

    fn get_sdk8_dir() -> Option<PathBuf> {
        LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0".as_ref())
        .ok().and_then(|key| {
            key.query_str("InstallationFolder").ok()
        }).map(|root| {
            Path::new(&root).join("lib").join("win8")
        })
    }

    // When choosing the linker toolchain to use, we have to choose the one
    // which matches the host architecture. Otherwise we end up in situations
    // where someone on 32-bit Windows is trying to cross compile to 64-bit and
    // it tries to invoke the native 64-bit linker which won't work.
    //
    // FIXME - This currently functions based on the host architecture of rustc
    // itself but it should instead detect the bitness of the OS itself.
    //
    // FIXME - Figure out what happens when the host architecture is arm.
    //
    // FIXME - Some versions of MSVC may not come with all these toolchains.
    // Consider returning an array of toolchains and trying them one at a time
    // until the linker is found.
    fn bin_subdir(arch: &str) -> Option<&'static str> {
        if cfg!(target_arch = "x86_64") {
            match arch {
                "x86" => Some("amd64_x86"),
                "x86_64" => Some("amd64"),
                "arm" => Some("amd64_arm"),
                _ => None,
            }
        } else if cfg!(target_arch = "x86") {
            match arch {
                "x86" => Some(""),
                "x86_64" => Some("x86_amd64"),
                "arm" => Some("x86_arm"),
                _ => None,
            }
        } else { None }
    }
    fn lib_subdir(arch: &str) -> Option<&'static str> {
        match arch {
            "x86" => Some("x86"),
            "x86_64" => Some("x64"),
            "arm" => Some("arm"),
            _ => None,
        }
    }
    // MSVC's x86 libraries are not in a subfolder
    fn vc_lib_subdir(arch: &str) -> Option<&'static str> {
        match arch {
            "x86" => Some(""),
            "x86_64" => Some("amd64"),
            "arm" => Some("arm"),
            _ => None,
        }
    }
}

// If we're not on Windows, then there's no registry to search through and MSVC
// wouldn't be able to run, so we just call `link.exe` and hope for the best.
#[cfg(not(windows))]
pub fn link_exe_cmd(_sess: &Session) -> Command {
    Command::new("link.exe")
}
<|endoftext|>


<commit_before>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load,
                  wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy,
                  wlr_xcursor_manager_get_xcursor, wlr_xcursor_manager_theme};
use types::{Cursor, XCursor, XCursorTheme};
use std::ptr;
use utils::safe_as_cstring;
use std::marker::PhantomData;

#[derive(Debug)]
pub struct XCursorManagerTheme<'manager> {
    theme: *mut wlr_xcursor_manager_theme,
    phantom: PhantomData<&'manager XCursorManager>
}

#[derive(Debug)]
pub struct XCursorManager {
    manager: *mut wlr_xcursor_manager,
}

impl<'manager> XCursorManagerTheme<'manager> {
    fn new(theme: *mut wlr_xcursor_manager_theme) -> Self {
        XCursorManagerTheme {
            theme: theme,
            phantom: PhantomData
        }
    }

    pub fn scale(&self) -> f32 {
        unsafe {
            (*self.theme).scale
        }
    }

    pub fn theme(self) -> XCursorTheme {
        unsafe {
            XCursorTheme::new((*self.theme).theme)
        }
    }
}

impl XCursorManager {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager: manager })
            }
        }
    }

    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    pub fn get_xcursor<'manager, T: Into<Option<String>>>(&'manager self, name: T, scale: f32) -> Option<XCursor<'manager>> {
        let name_str = name.into().map(safe_as_cstring);
        let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
        unsafe {
            let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale);
            if xcursor.is_null() {
                None
            } else {
                Some(XCursor::from_ptr(xcursor))
            }
        }
    }

    pub fn scaled_themes<'manager>(&'manager self) -> Vec<XCursorManagerTheme<'manager>> {
        unsafe {
            let mut result = vec![];

            wl_list_for_each!((*self.manager).scaled_themes, link, (theme: wlr_xcursor_manager_theme) => {
                result.push(XCursorManagerTheme::new(theme))
            });

            result
        }
    }

    /// returns false if the scaled theme was successfully loaded and true otherwise
    pub fn load(&self, scale: f32) -> bool {
        unsafe {
            match wlr_xcursor_manager_load(self.manager, scale) {
                0 => false,
                _ => true
            }
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_str = safe_as_cstring(name);
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_str.as_ptr(), cursor.as_ptr());
        }
    }
}

impl Drop for XCursorManager {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<commit_msg>add name for xcursor manager<commit_after>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load,
                  wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy,
                  wlr_xcursor_manager_get_xcursor, wlr_xcursor_manager_theme};
use types::{Cursor, XCursor, XCursorTheme};
use std::ptr;
use utils::{safe_as_cstring, c_to_rust_string};
use std::marker::PhantomData;

#[derive(Debug)]
pub struct XCursorManagerTheme<'manager> {
    theme: *mut wlr_xcursor_manager_theme,
    phantom: PhantomData<&'manager XCursorManager>
}

#[derive(Debug)]
pub struct XCursorManager {
    manager: *mut wlr_xcursor_manager,
}

impl<'manager> XCursorManagerTheme<'manager> {
    fn new(theme: *mut wlr_xcursor_manager_theme) -> Self {
        XCursorManagerTheme {
            theme: theme,
            phantom: PhantomData
        }
    }

    pub fn scale(&self) -> f32 {
        unsafe {
            (*self.theme).scale
        }
    }

    pub fn theme(self) -> XCursorTheme {
        unsafe {
            XCursorTheme::new((*self.theme).theme)
        }
    }
}

impl XCursorManager {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager: manager })
            }
        }
    }

    pub fn name(&self) -> String {
        unsafe {
            c_to_rust_string((*self.manager).name).expect("Could not parse make as UTF-8")
        }
    }

    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    pub fn get_xcursor<'manager, T: Into<Option<String>>>(&'manager self, name: T, scale: f32) -> Option<XCursor<'manager>> {
        let name_str = name.into().map(safe_as_cstring);
        let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
        unsafe {
            let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale);
            if xcursor.is_null() {
                None
            } else {
                Some(XCursor::from_ptr(xcursor))
            }
        }
    }

    pub fn scaled_themes<'manager>(&'manager self) -> Vec<XCursorManagerTheme<'manager>> {
        unsafe {
            let mut result = vec![];

            wl_list_for_each!((*self.manager).scaled_themes, link, (theme: wlr_xcursor_manager_theme) => {
                result.push(XCursorManagerTheme::new(theme))
            });

            result
        }
    }

    /// returns false if the scaled theme was successfully loaded and true otherwise
    pub fn load(&self, scale: f32) -> bool {
        unsafe {
            match wlr_xcursor_manager_load(self.manager, scale) {
                0 => false,
                _ => true
            }
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_str = safe_as_cstring(name);
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_str.as_ptr(), cursor.as_ptr());
        }
    }
}

impl Drop for XCursorManager {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<|endoftext|>


<commit_before>// Based on StaticGenerator from `gl_generator` crate, original copyright below:
//
// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate gl_generator;

use gl_generator::registry::{Registry, Ns};
use std::io;

#[allow(missing_copy_implementations)]
pub struct EpoxyGenerator;

impl gl_generator::generators::Generator for EpoxyGenerator {
    fn write<W>(&self, registry: &Registry, ns: Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
        try!(write_header(dest));
        try!(write_metaloadfn(dest));
        try!(write_type_aliases(&ns, dest));
        try!(write_enums(registry, dest));
        try!(write_fns(registry, dest));
        try!(write_fnptr_struct_def(dest));
        try!(write_ptrs(registry, dest));
        try!(write_fn_mods(registry, &ns, dest));
        try!(write_error_fns(&ns, dest));
        try!(write_load_fn(registry, dest));
        try!(write_get_proc_addr(registry, &ns, dest));
        Ok(())
    }
}

/// Creates a `__gl_imports` module which contains all the external symbols that we need for the bindings.
fn write_header<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        mod __gl_imports {{
            extern crate gl_common;
            extern crate libc;
            pub use std::mem;
            pub use std::ptr;
            pub use std::process::exit;
        }}
    "#)
}

/// Creates the metaloadfn function for fallbacks
fn write_metaloadfn<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        fn metaloadfn<F>(mut loadfn: F,
                         symbol: &str,
                         fallbacks: &[&str]) -> *const *const __gl_imports::libc::c_void
                         where F: FnMut(&str) -> *const __gl_imports::libc::c_void {{
            let mut ptr = loadfn(symbol);
            if ptr.is_null() {{
                for &sym in fallbacks.iter() {{
                    ptr = loadfn(sym);
                    if !ptr.is_null() {{ break; }}
                }}
            }}
            ptr as *const *const __gl_imports::libc::c_void
        }}
    "#)
}

/// Creates a `types` module which contains all the type aliases.
///
/// See also `generators::gen_type_aliases`.
fn write_type_aliases<W>(ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        pub mod types {{
            #![allow(non_camel_case_types)]
            #![allow(non_snake_case)]
            #![allow(dead_code)]
            #![allow(missing_copy_implementations)]
    "#));

    try!(gl_generator::generators::gen_type_aliases(ns, dest));

    writeln!(dest, "
        }}
    ")
}

/// Creates all the `<enum>` elements at the root of the bindings.
fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    for e in registry.enum_iter() {
        try!(gl_generator::generators::gen_enum_item(e, "types::", dest));
    }

    Ok(())
}

/// Creates the functions corresponding to the GL commands.
///
/// The function calls the corresponding function pointer stored in the `storage` module created
///  by `write_ptrs`.
fn write_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    for c in registry.cmd_iter() {
        if let Some(v) = registry.aliases.get(&c.proto.ident) {
            try!(writeln!(dest, "/// Fallbacks: {}", v.join(", ")));
        }

        try!(writeln!(dest, r#"
            #[allow(non_snake_case, unused_variables, dead_code)] #[inline]
            pub unsafe fn {name}({params}) -> {return_suffix} {{
                __gl_imports::mem::transmute::<_, extern "system" fn({typed_params}) -> {return_suffix}>
                    (*storage::{name}.pf)({idents})
            }}"#,
            name = c.proto.ident,
            params = gl_generator::generators::gen_parameters(c, true, true).join(", "),
            typed_params = gl_generator::generators::gen_parameters(c, false, true).join(", "),
            return_suffix = gl_generator::generators::gen_return_type(c),
            idents = gl_generator::generators::gen_parameters(c, true, false).join(", "),
        ));
    }

    Ok(())
}

/// Creates a `FnPtr` structure which contains the store for a single binding.
fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, "
        #[allow(missing_copy_implementations)]
        pub struct FnPtr {{
            /// Pointer to the entry in libepoxy's dispatch table
            pf: *const *const __gl_imports::libc::c_void,
            /// True if the pointer points to a real function, false if points to an error fn
            is_loaded: bool,
        }}

        impl FnPtr {{
            /// Creates a `FnPtr` from a load attempt.
            pub fn new(ptr: *const *const __gl_imports::libc::c_void) -> FnPtr {{
                if ptr.is_null() {{
                    FnPtr {{
                        pf: &PMISSING_FN_EXIT,
                        is_loaded: false,
                    }}
                }} else {{
                    FnPtr {{ pf: ptr, is_loaded: true }}
                }}
            }}
        }}
    ")
}

/// Creates a `storage` module which contains a static `FnPtr` per GL command in the registry.
fn write_ptrs<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest,
        "mod storage {{
            #![allow(non_snake_case)]
            use super::PMISSING_FN_EXIT;
            use super::FnPtr;"));

    for c in registry.cmd_iter() {
        try!(writeln!(dest,
            "pub static mut {name}: FnPtr = FnPtr {{
                pf: &PMISSING_FN_EXIT,
                is_loaded: false,
            }};",
            name = c.proto.ident,
        ));
    }

    writeln!(dest, "}}")
}

/// Creates one module for each GL command.
///
/// Each module contains `is_loaded` and `load_with` which interact with the `storage` module
///  created by `write_ptrs`.
fn write_fn_mods<W>(registry: &Registry, ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    for c in registry.cmd_iter() {
        let fallbacks = match registry.aliases.get(&c.proto.ident) {
            Some(v) => {
                let names = v.iter().map(|name| format!(r#""{}""#,
                    gl_generator::generators::gen_symbol_name(ns, &name[..]))).collect::<Vec<_>>();
                format!("&[{}]", names.join(", "))
            },
            None => "&[]".to_string(),
        };
        let fnname = &c.proto.ident[..];
        let symbol = gl_generator::generators::gen_symbol_name(ns, &c.proto.ident[..]);
        let symbol = &symbol[..];

        try!(writeln!(dest, r#"
            #[allow(non_snake_case)]
            pub mod {fnname} {{
                use super::{{storage, metaloadfn}};
                use super::FnPtr;

                #[inline]
                #[allow(dead_code)]
                pub fn is_loaded() -> bool {{
                    unsafe {{ storage::{fnname}.is_loaded }}
                }}

                #[allow(dead_code)]
                pub fn load_with<F>(loadfn: F) where F: FnMut(&str) -> *const super::__gl_imports::libc::c_void {{
                    unsafe {{
                        storage::{fnname} = FnPtr::new(metaloadfn(loadfn, "epoxy_{symbol}", {fallbacks}))
                    }}
                }}
            }}"#,
            fnname = fnname,
            fallbacks = fallbacks,
            symbol = symbol,
        ));
    }

    Ok(())
}

/// Creates a `missing_fn_exit` function.
///
/// This function is the mock that is called if the real function could not be called.
fn write_error_fns<W>(ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        #[inline(never)]
        extern fn missing_fn_exit() {{
            println!("{ns} function was not loaded");
            __gl_imports::exit(1);
        }}
        const PMISSING_FN_EXIT: *const __gl_imports::libc::c_void = missing_fn_exit as *const __gl_imports::libc::c_void;"#,
        ns = ns,
    )
}

/// Creates the `load_with` function.
///
/// The function calls `load_with` in each module created by `write_fn_mods`.
fn write_load_fn<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F) where F: FnMut(&str) -> *const __gl_imports::libc::c_void {{
    "#));

    for c in registry.cmd_iter() {
        try!(writeln!(dest, "{name}::load_with(|s| loadfn(s));",
                      name = &c.proto.ident[..]));
    }

    writeln!(dest, "
        }}

        #[allow(dead_code)]
        pub fn load<T: __gl_imports::gl_common::GlFunctionsSource>(loader: &T) {{
            load_with(|name| loader.get_proc_addr(name));
        }}
    ")
}

/// Creates the `get_proc_addr` function.
///
/// The function adds in a layer of indirection, but allows compatibility with the `gl` crate
fn write_get_proc_addr<W>(registry: &Registry, ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        #[allow(dead_code)]
        pub fn get_proc_addr(symbol: &str) -> *const __gl_imports::libc::c_void {{
            match &symbol[..] {{
    "#));

    for c in registry.cmd_iter() {
        try!(writeln!(dest, r#"
            "{symbol}" => {name} as *const __gl_imports::libc::c_void,"#,
            symbol = gl_generator::generators::gen_symbol_name(ns, &c.proto.ident[..]),
            name = &c.proto.ident[..],
        ));
    }

    writeln!(dest, r#"
                _ => __gl_imports::ptr::null(),
            }}
        }}
    "#)
}
<commit_msg>Fix private extern crate error<commit_after>// Based on StaticGenerator from `gl_generator` crate, original copyright below:
//
// Copyright 2013-2014 The gl-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate gl_generator;

use gl_generator::registry::{Registry, Ns};
use std::io;

#[allow(missing_copy_implementations)]
pub struct EpoxyGenerator;

impl gl_generator::generators::Generator for EpoxyGenerator {
    fn write<W>(&self, registry: &Registry, ns: Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
        try!(write_header(dest));
        try!(write_metaloadfn(dest));
        try!(write_type_aliases(&ns, dest));
        try!(write_enums(registry, dest));
        try!(write_fns(registry, dest));
        try!(write_fnptr_struct_def(dest));
        try!(write_ptrs(registry, dest));
        try!(write_fn_mods(registry, &ns, dest));
        try!(write_error_fns(&ns, dest));
        try!(write_load_fn(registry, dest));
        try!(write_get_proc_addr(registry, &ns, dest));
        Ok(())
    }
}

/// Creates a `__gl_imports` module which contains all the external symbols that we need for the bindings.
fn write_header<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        mod __gl_imports {{
            pub extern crate gl_common;
            pub extern crate libc;
            pub use std::mem;
            pub use std::ptr;
            pub use std::process::exit;
        }}
    "#)
}

/// Creates the metaloadfn function for fallbacks
fn write_metaloadfn<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        fn metaloadfn<F>(mut loadfn: F,
                         symbol: &str,
                         fallbacks: &[&str]) -> *const *const __gl_imports::libc::c_void
                         where F: FnMut(&str) -> *const __gl_imports::libc::c_void {{
            let mut ptr = loadfn(symbol);
            if ptr.is_null() {{
                for &sym in fallbacks.iter() {{
                    ptr = loadfn(sym);
                    if !ptr.is_null() {{ break; }}
                }}
            }}
            ptr as *const *const __gl_imports::libc::c_void
        }}
    "#)
}

/// Creates a `types` module which contains all the type aliases.
///
/// See also `generators::gen_type_aliases`.
fn write_type_aliases<W>(ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        pub mod types {{
            #![allow(non_camel_case_types)]
            #![allow(non_snake_case)]
            #![allow(dead_code)]
            #![allow(missing_copy_implementations)]
    "#));

    try!(gl_generator::generators::gen_type_aliases(ns, dest));

    writeln!(dest, "
        }}
    ")
}

/// Creates all the `<enum>` elements at the root of the bindings.
fn write_enums<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    for e in registry.enum_iter() {
        try!(gl_generator::generators::gen_enum_item(e, "types::", dest));
    }

    Ok(())
}

/// Creates the functions corresponding to the GL commands.
///
/// The function calls the corresponding function pointer stored in the `storage` module created
///  by `write_ptrs`.
fn write_fns<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    for c in registry.cmd_iter() {
        if let Some(v) = registry.aliases.get(&c.proto.ident) {
            try!(writeln!(dest, "/// Fallbacks: {}", v.join(", ")));
        }

        try!(writeln!(dest, r#"
            #[allow(non_snake_case, unused_variables, dead_code)] #[inline]
            pub unsafe fn {name}({params}) -> {return_suffix} {{
                __gl_imports::mem::transmute::<_, extern "system" fn({typed_params}) -> {return_suffix}>
                    (*storage::{name}.pf)({idents})
            }}"#,
            name = c.proto.ident,
            params = gl_generator::generators::gen_parameters(c, true, true).join(", "),
            typed_params = gl_generator::generators::gen_parameters(c, false, true).join(", "),
            return_suffix = gl_generator::generators::gen_return_type(c),
            idents = gl_generator::generators::gen_parameters(c, true, false).join(", "),
        ));
    }

    Ok(())
}

/// Creates a `FnPtr` structure which contains the store for a single binding.
fn write_fnptr_struct_def<W>(dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, "
        #[allow(missing_copy_implementations)]
        pub struct FnPtr {{
            /// Pointer to the entry in libepoxy's dispatch table
            pf: *const *const __gl_imports::libc::c_void,
            /// True if the pointer points to a real function, false if points to an error fn
            is_loaded: bool,
        }}

        impl FnPtr {{
            /// Creates a `FnPtr` from a load attempt.
            pub fn new(ptr: *const *const __gl_imports::libc::c_void) -> FnPtr {{
                if ptr.is_null() {{
                    FnPtr {{
                        pf: &PMISSING_FN_EXIT,
                        is_loaded: false,
                    }}
                }} else {{
                    FnPtr {{ pf: ptr, is_loaded: true }}
                }}
            }}
        }}
    ")
}

/// Creates a `storage` module which contains a static `FnPtr` per GL command in the registry.
fn write_ptrs<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest,
        "mod storage {{
            #![allow(non_snake_case)]
            use super::PMISSING_FN_EXIT;
            use super::FnPtr;"));

    for c in registry.cmd_iter() {
        try!(writeln!(dest,
            "pub static mut {name}: FnPtr = FnPtr {{
                pf: &PMISSING_FN_EXIT,
                is_loaded: false,
            }};",
            name = c.proto.ident,
        ));
    }

    writeln!(dest, "}}")
}

/// Creates one module for each GL command.
///
/// Each module contains `is_loaded` and `load_with` which interact with the `storage` module
///  created by `write_ptrs`.
fn write_fn_mods<W>(registry: &Registry, ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    for c in registry.cmd_iter() {
        let fallbacks = match registry.aliases.get(&c.proto.ident) {
            Some(v) => {
                let names = v.iter().map(|name| format!(r#""{}""#,
                    gl_generator::generators::gen_symbol_name(ns, &name[..]))).collect::<Vec<_>>();
                format!("&[{}]", names.join(", "))
            },
            None => "&[]".to_string(),
        };
        let fnname = &c.proto.ident[..];
        let symbol = gl_generator::generators::gen_symbol_name(ns, &c.proto.ident[..]);
        let symbol = &symbol[..];

        try!(writeln!(dest, r#"
            #[allow(non_snake_case)]
            pub mod {fnname} {{
                use super::{{storage, metaloadfn}};
                use super::FnPtr;

                #[inline]
                #[allow(dead_code)]
                pub fn is_loaded() -> bool {{
                    unsafe {{ storage::{fnname}.is_loaded }}
                }}

                #[allow(dead_code)]
                pub fn load_with<F>(loadfn: F) where F: FnMut(&str) -> *const super::__gl_imports::libc::c_void {{
                    unsafe {{
                        storage::{fnname} = FnPtr::new(metaloadfn(loadfn, "epoxy_{symbol}", {fallbacks}))
                    }}
                }}
            }}"#,
            fnname = fnname,
            fallbacks = fallbacks,
            symbol = symbol,
        ));
    }

    Ok(())
}

/// Creates a `missing_fn_exit` function.
///
/// This function is the mock that is called if the real function could not be called.
fn write_error_fns<W>(ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest, r#"
        #[inline(never)]
        extern fn missing_fn_exit() {{
            println!("{ns} function was not loaded");
            __gl_imports::exit(1);
        }}
        const PMISSING_FN_EXIT: *const __gl_imports::libc::c_void = missing_fn_exit as *const __gl_imports::libc::c_void;"#,
        ns = ns,
    )
}

/// Creates the `load_with` function.
///
/// The function calls `load_with` in each module created by `write_fn_mods`.
fn write_load_fn<W>(registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F) where F: FnMut(&str) -> *const __gl_imports::libc::c_void {{
    "#));

    for c in registry.cmd_iter() {
        try!(writeln!(dest, "{name}::load_with(|s| loadfn(s));",
                      name = &c.proto.ident[..]));
    }

    writeln!(dest, "
        }}

        #[allow(dead_code)]
        pub fn load<T: __gl_imports::gl_common::GlFunctionsSource>(loader: &T) {{
            load_with(|name| loader.get_proc_addr(name));
        }}
    ")
}

/// Creates the `get_proc_addr` function.
///
/// The function adds in a layer of indirection, but allows compatibility with the `gl` crate
fn write_get_proc_addr<W>(registry: &Registry, ns: &Ns, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, r#"
        #[allow(dead_code)]
        pub fn get_proc_addr(symbol: &str) -> *const __gl_imports::libc::c_void {{
            match &symbol[..] {{
    "#));

    for c in registry.cmd_iter() {
        try!(writeln!(dest, r#"
            "{symbol}" => {name} as *const __gl_imports::libc::c_void,"#,
            symbol = gl_generator::generators::gen_symbol_name(ns, &c.proto.ident[..]),
            name = &c.proto.ident[..],
        ));
    }

    writeln!(dest, r#"
                _ => __gl_imports::ptr::null(),
            }}
        }}
    "#)
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{BufReader, BufRead, Write};

fn encode_char(ch: u8) -> u8 {
    let lower = b'a' <= ch && ch <= b'z';
    let upper = b'A' <= ch && ch <= b'Z';

    if lower || upper {
        let c = ch + 3;

        if (lower && c > b'z') || (upper && c > b'Z') {
            c - 26
        } else {
            c
        }
    } else {
        ch
    }
}

fn encode(input: &[u8]) -> String {
    let mut buf = String::with_capacity(input.len());

    for &c in input {
        buf.push(encode_char(c) as char);
    }

    buf
}

fn main() {
    let input_file = File::open("in.txt").unwrap();
    let input = BufReader::new(input_file);
    let mut output = File::create("out.txt").unwrap();

    for line in input.lines().filter_map(|res| res.ok()) {
        writeln!(&mut output, "{}", encode(line.as_bytes())).unwrap();
    }
}

<commit_msg>simplify caesar with match expressions<commit_after>use std::fs::File;
use std::io::{BufReader, BufRead, Write};

fn alpha_to_code(ch: u8) -> u8 {
    match ch {
        b'a'...b'z' => ch - b'a',
        b'A'...b'Z' => ch - b'A',
        _           => ch
    }
}

fn code_to_alpha(c: u8) -> u8 {
    c + b'a'
}

fn encode_char(ch: u8) -> u8 {
    match ch {
        b'a'...b'z' => code_to_alpha((alpha_to_code(ch) + 3) % 26),
        b'A'...b'Z' => code_to_alpha((alpha_to_code(ch) + 3) % 26) - b'a' + b'A',
        _           => ch
    }
}

fn encode(input: &[u8]) -> String {
    let mut buf = String::with_capacity(input.len());

    for &c in input {
        buf.push(encode_char(c) as char);
    }

    buf
}

fn main() {
    let input_file = File::open("in.txt").unwrap();
    let input = BufReader::new(input_file);
    let mut output = File::create("out.txt").unwrap();

    for line in input.lines().filter_map(|res| res.ok()) {
        writeln!(&mut output, "{}", encode(line.as_bytes())).unwrap();
    }
}

<|endoftext|>


<commit_before>extern crate gcc;

use std::env;

fn main() {
    let mut compiler = gcc::Build::new();
    compiler
        .file("liblz4/lib/lz4.c")
        .file("liblz4/lib/lz4frame.c")
        .file("liblz4/lib/lz4hc.c")
        .file("liblz4/lib/xxhash.c")
        // We always compile the C with optimization, because otherwise it is 20x slower.
        .opt_level(3);
    match env::var("TARGET").unwrap().as_str()
    {
      "i686-pc-windows-gnu" => {
        compiler
            .flag("-fno-tree-vectorize");
      },
      _ => {}
    }
    compiler.compile("liblz4.a");
}
<commit_msg>adjust build<commit_after>extern crate gcc;

use std::{env, fs};
use std::path::PathBuf;

fn main() {
    let mut compiler = gcc::Build::new();
    compiler
        .file("liblz4/lib/lz4.c")
        .file("liblz4/lib/lz4frame.c")
        .file("liblz4/lib/lz4hc.c")
        .file("liblz4/lib/xxhash.c")
        // We always compile the C with optimization, because otherwise it is 20x slower.
        .opt_level(3);
    match env::var("TARGET").unwrap().as_str()
    {
      "i686-pc-windows-gnu" => {
        compiler
            .flag("-fno-tree-vectorize");
      },
      _ => {}
    }
    compiler.compile("liblz4.a");

    let src = env::current_dir().unwrap().join("liblz4").join("lib");
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let include = dst.join("include");
    fs::create_dir_all(&include).unwrap();
    for e in fs::read_dir(&src).unwrap() {
        let e = e.unwrap();
        if e.file_name().into_string().unwrap().ends_with(".h") {
            fs::copy(e.path(), include.join(e.file_name())).unwrap();
        }
    }
    println!("cargo:root={}", dst.display());
}
<|endoftext|>


<commit_before>use intercom::{type_system::TypeSystem, IID};

pub trait ComImpl<TInterface: ?Sized, TS: TypeSystem>
where
    TInterface: ComInterface<TS>,
{
    fn vtable() -> &'static TInterface::VTable;
}

pub trait ComClass<TInterface: ?Sized, TS: TypeSystem>
{
    #[inline(always)]
    fn offset() -> usize;
}

pub trait ComInterface<TS: TypeSystem>
{
    type VTable;
    fn iid() -> &'static IID;
}

pub trait HasTypeInfo
{
    fn gather_type_info() -> Vec<crate::typelib::TypeInfo>;
}

pub trait InterfaceHasTypeInfo
{
    fn gather_type_info() -> Vec<crate::typelib::TypeInfo>;
}
<commit_msg>Remove #[inline] on traits<commit_after>use intercom::{type_system::TypeSystem, IID};

pub trait ComImpl<TInterface: ?Sized, TS: TypeSystem>
where
    TInterface: ComInterface<TS>,
{
    fn vtable() -> &'static TInterface::VTable;
}

pub trait ComClass<TInterface: ?Sized, TS: TypeSystem>
{
    fn offset() -> usize;
}

pub trait ComInterface<TS: TypeSystem>
{
    type VTable;
    fn iid() -> &'static IID;
}

pub trait HasTypeInfo
{
    fn gather_type_info() -> Vec<crate::typelib::TypeInfo>;
}

pub trait InterfaceHasTypeInfo
{
    fn gather_type_info() -> Vec<crate::typelib::TypeInfo>;
}
<|endoftext|>


<commit_before>#![feature(convert)]

extern crate byteorder;

pub mod error;
mod mqtt;
mod read;
mod write;

pub use mqtt::{
    Packet,
    Connect,
    Connack,
    Publish,
    Subscribe,
    Suback,
    Unsubscribe
};

pub use read::MqttRead;
pub use write::MqttWrite;

const MULTIPLIER: usize = 0x80 * 0x80 * 0x80;
const MAX_PAYLOAD_SIZE: usize = 268435455;

use error::{Error, Result};
use std::fmt;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Protocol {
    MQIsdp(u8),
    MQTT(u8)
}

impl Protocol {
    pub fn new(name: String, level: u8) -> Result<Protocol> {
        match name.as_ref() {
            "MQIsdp" => match level {
                3 => Ok(Protocol::MQIsdp(3)),
                _ => Err(Error::UnsupportedProtocolVersion)
            },
            "MQTT" => match level {
                4 => Ok(Protocol::MQTT(4)),
                _ => Err(Error::UnsupportedProtocolVersion)
            },
            _ => Err(Error::UnsupportedProtocolName)
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QoS {
    AtMostOnce,
    AtLeastOnce,
    ExactlyOnce
}

impl QoS {
    pub fn from_u8(byte: u8) -> Result<QoS> {
        match byte {
            0 => Ok(QoS::AtMostOnce),
            1 => Ok(QoS::AtLeastOnce),
            2 => Ok(QoS::ExactlyOnce),
            _ => Err(Error::UnsupportedQualityOfService)
        }
    }

    #[inline]
    pub fn from_hd(hd: u8) -> Result<QoS> {
        Self::from_u8((hd & 0b110) >> 1)
    }

    pub fn to_u8(&self) -> u8 {
        match *self {
            QoS::AtMostOnce => 0,
            QoS::AtLeastOnce => 1,
            QoS::ExactlyOnce => 2
        }
    }

    pub fn min(&self, other: QoS) -> QoS {
        match *self {
            QoS::AtMostOnce => QoS::AtMostOnce,
            QoS::AtLeastOnce => {
                if other == QoS::AtMostOnce {
                    QoS::AtMostOnce
                } else {
                    QoS::AtLeastOnce
                }
            },
            QoS::ExactlyOnce => other
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PacketType {
	Connect,
	Connack,
	Publish,
	Puback,
	Pubrec,
	Pubrel,
	Pubcomp,
	Subscribe,
	Suback,
	Unsubscribe,
	Unsuback,
	Pingreq,
	Pingresp,
	Disconnect
}

impl PacketType {
    pub fn to_u8(&self) -> u8 {
        match *self {
            PacketType::Connect => 1,
            PacketType::Connack => 2,
            PacketType::Publish => 3,
            PacketType::Puback => 4,
            PacketType::Pubrec => 5,
            PacketType::Pubrel => 6,
            PacketType::Pubcomp => 7,
            PacketType::Subscribe => 8,
            PacketType::Suback => 9,
            PacketType::Unsubscribe => 10,
            PacketType::Unsuback => 11,
            PacketType::Pingreq => 12,
            PacketType::Pingresp => 13,
            PacketType::Disconnect => 14
        }
    }

    pub fn from_u8(byte: u8) -> Result<PacketType> {
        match byte {
            1 => Ok(PacketType::Connect),
            2 => Ok(PacketType::Connack),
            3 => Ok(PacketType::Publish),
            4 => Ok(PacketType::Puback),
            5 => Ok(PacketType::Pubrec),
            6 => Ok(PacketType::Pubrel),
            7 => Ok(PacketType::Pubcomp),
            8 => Ok(PacketType::Subscribe),
            9 => Ok(PacketType::Suback),
            10 => Ok(PacketType::Unsubscribe),
            11 => Ok(PacketType::Unsuback),
            12 => Ok(PacketType::Pingreq),
            13 => Ok(PacketType::Pingresp),
            14 => Ok(PacketType::Disconnect),
            _ => Err(Error::UnsupportedPacketType)
        }
    }

    #[inline]
    pub fn from_hd(hd: u8) -> Result<PacketType> {
        Self::from_u8(hd >> 4)
    }
}

impl fmt::Display for PacketType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str = format!("{:?}", self);
        let first_space = str.find(' ').unwrap_or(str.len());
        let (str, _) = str.split_at(first_space);
        f.write_str(&str)
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ConnectReturnCode {
    Accepted,
    RefusedProtocolVersion,
    RefusedIdentifierRejected,
    ServerUnavailable,
    BadUsernamePassword,
    NotAuthorized
}

impl ConnectReturnCode {
    pub fn to_u8(&self) -> u8 {
        match *self {
            ConnectReturnCode::Accepted => 0,
            ConnectReturnCode::RefusedProtocolVersion => 1,
            ConnectReturnCode::RefusedIdentifierRejected => 2,
            ConnectReturnCode::ServerUnavailable => 3,
            ConnectReturnCode::BadUsernamePassword => 4,
            ConnectReturnCode::NotAuthorized => 5
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PacketIdentifier(u16);

impl PacketIdentifier {
    pub fn zero() -> PacketIdentifier {
        PacketIdentifier(0u16)
    }

    pub fn next(&self) -> PacketIdentifier {
        PacketIdentifier(self.0)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Header {
    hd: u8,
    pub typ: PacketType,
    pub len: usize
}

impl Header {
    pub fn new(hd: u8, len: usize) -> Result<Header> {
        Ok(Header {
            hd: hd,
            typ: try!(PacketType::from_hd(hd)),
            len: len
        })
    }

    #[inline]
    pub fn dup(&self) -> bool {
        (self.hd & 0b1000) != 0
    }

    #[inline]
    pub fn qos(&self) -> Result<QoS> {
        QoS::from_hd(self.hd)
    }

    #[inline]
    pub fn retain(&self) -> bool {
        (self.hd & 1) != 0
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct LastWill {
    pub topic: String,
    pub message: String,
    pub qos: QoS,
    pub retain: bool
}

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

    #[test]
    fn qos_min_test() {
        assert_eq!(QoS::AtMostOnce.min(QoS::AtMostOnce), QoS::AtMostOnce);
        assert_eq!(QoS::AtMostOnce.min(QoS::AtLeastOnce), QoS::AtMostOnce);
        assert_eq!(QoS::AtLeastOnce.min(QoS::AtMostOnce), QoS::AtMostOnce);
        assert_eq!(QoS::AtLeastOnce.min(QoS::ExactlyOnce), QoS::AtLeastOnce);
        assert_eq!(QoS::ExactlyOnce.min(QoS::AtMostOnce), QoS::AtMostOnce);
        assert_eq!(QoS::ExactlyOnce.min(QoS::ExactlyOnce), QoS::ExactlyOnce);
    }
}
<commit_msg>Improve Protocol struct<commit_after>#![feature(convert)]

extern crate byteorder;

pub mod error;
mod mqtt;
mod read;
mod write;

pub use mqtt::{
    Packet,
    Connect,
    Connack,
    Publish,
    Subscribe,
    Suback,
    Unsubscribe
};

pub use read::MqttRead;
pub use write::MqttWrite;

const MULTIPLIER: usize = 0x80 * 0x80 * 0x80;
const MAX_PAYLOAD_SIZE: usize = 268435455;

use error::{Error, Result};
use std::fmt;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Protocol {
    MQIsdp(u8),
    MQTT(u8)
}

impl Protocol {
    pub fn new(name: &str, level: u8) -> Result<Protocol> {
        match name {
            "MQIsdp" => match level {
                3 => Ok(Protocol::MQIsdp(3)),
                _ => Err(Error::UnsupportedProtocolVersion)
            },
            "MQTT" => match level {
                4 => Ok(Protocol::MQTT(4)),
                _ => Err(Error::UnsupportedProtocolVersion)
            },
            _ => Err(Error::UnsupportedProtocolName)
        }
    }

    pub fn name(&self) -> &'static str {
        match self {
            &Protocol::MQIsdp(_) => "MQIsdp",
            &Protocol::MQTT(_) => "MQTT"
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QoS {
    AtMostOnce,
    AtLeastOnce,
    ExactlyOnce
}

impl QoS {
    pub fn from_u8(byte: u8) -> Result<QoS> {
        match byte {
            0 => Ok(QoS::AtMostOnce),
            1 => Ok(QoS::AtLeastOnce),
            2 => Ok(QoS::ExactlyOnce),
            _ => Err(Error::UnsupportedQualityOfService)
        }
    }

    #[inline]
    pub fn from_hd(hd: u8) -> Result<QoS> {
        Self::from_u8((hd & 0b110) >> 1)
    }

    pub fn to_u8(&self) -> u8 {
        match *self {
            QoS::AtMostOnce => 0,
            QoS::AtLeastOnce => 1,
            QoS::ExactlyOnce => 2
        }
    }

    pub fn min(&self, other: QoS) -> QoS {
        match *self {
            QoS::AtMostOnce => QoS::AtMostOnce,
            QoS::AtLeastOnce => {
                if other == QoS::AtMostOnce {
                    QoS::AtMostOnce
                } else {
                    QoS::AtLeastOnce
                }
            },
            QoS::ExactlyOnce => other
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PacketType {
	Connect,
	Connack,
	Publish,
	Puback,
	Pubrec,
	Pubrel,
	Pubcomp,
	Subscribe,
	Suback,
	Unsubscribe,
	Unsuback,
	Pingreq,
	Pingresp,
	Disconnect
}

impl PacketType {
    pub fn to_u8(&self) -> u8 {
        match *self {
            PacketType::Connect => 1,
            PacketType::Connack => 2,
            PacketType::Publish => 3,
            PacketType::Puback => 4,
            PacketType::Pubrec => 5,
            PacketType::Pubrel => 6,
            PacketType::Pubcomp => 7,
            PacketType::Subscribe => 8,
            PacketType::Suback => 9,
            PacketType::Unsubscribe => 10,
            PacketType::Unsuback => 11,
            PacketType::Pingreq => 12,
            PacketType::Pingresp => 13,
            PacketType::Disconnect => 14
        }
    }

    pub fn from_u8(byte: u8) -> Result<PacketType> {
        match byte {
            1 => Ok(PacketType::Connect),
            2 => Ok(PacketType::Connack),
            3 => Ok(PacketType::Publish),
            4 => Ok(PacketType::Puback),
            5 => Ok(PacketType::Pubrec),
            6 => Ok(PacketType::Pubrel),
            7 => Ok(PacketType::Pubcomp),
            8 => Ok(PacketType::Subscribe),
            9 => Ok(PacketType::Suback),
            10 => Ok(PacketType::Unsubscribe),
            11 => Ok(PacketType::Unsuback),
            12 => Ok(PacketType::Pingreq),
            13 => Ok(PacketType::Pingresp),
            14 => Ok(PacketType::Disconnect),
            _ => Err(Error::UnsupportedPacketType)
        }
    }

    #[inline]
    pub fn from_hd(hd: u8) -> Result<PacketType> {
        Self::from_u8(hd >> 4)
    }
}

impl fmt::Display for PacketType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let str = format!("{:?}", self);
        let first_space = str.find(' ').unwrap_or(str.len());
        let (str, _) = str.split_at(first_space);
        f.write_str(&str)
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ConnectReturnCode {
    Accepted,
    RefusedProtocolVersion,
    RefusedIdentifierRejected,
    ServerUnavailable,
    BadUsernamePassword,
    NotAuthorized
}

impl ConnectReturnCode {
    pub fn to_u8(&self) -> u8 {
        match *self {
            ConnectReturnCode::Accepted => 0,
            ConnectReturnCode::RefusedProtocolVersion => 1,
            ConnectReturnCode::RefusedIdentifierRejected => 2,
            ConnectReturnCode::ServerUnavailable => 3,
            ConnectReturnCode::BadUsernamePassword => 4,
            ConnectReturnCode::NotAuthorized => 5
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PacketIdentifier(u16);

impl PacketIdentifier {
    pub fn zero() -> PacketIdentifier {
        PacketIdentifier(0u16)
    }

    pub fn next(&self) -> PacketIdentifier {
        PacketIdentifier(self.0)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Header {
    hd: u8,
    pub typ: PacketType,
    pub len: usize
}

impl Header {
    pub fn new(hd: u8, len: usize) -> Result<Header> {
        Ok(Header {
            hd: hd,
            typ: try!(PacketType::from_hd(hd)),
            len: len
        })
    }

    #[inline]
    pub fn dup(&self) -> bool {
        (self.hd & 0b1000) != 0
    }

    #[inline]
    pub fn qos(&self) -> Result<QoS> {
        QoS::from_hd(self.hd)
    }

    #[inline]
    pub fn retain(&self) -> bool {
        (self.hd & 1) != 0
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct LastWill {
    pub topic: String,
    pub message: String,
    pub qos: QoS,
    pub retain: bool
}

#[cfg(test)]
mod test {
    use super::{QoS, Protocol};

    #[test]
    fn protocol_test() {
        assert_eq!(Protocol::new("MQTT", 4).unwrap(), Protocol::MQTT(4));
        assert_eq!(Protocol::new("MQIsdp", 3).unwrap(), Protocol::MQIsdp(3));
        assert_eq!(Protocol::MQIsdp(3).name(), "MQIsdp");
        assert_eq!(Protocol::MQTT(4).name(), "MQTT");
    }

    #[test]
    fn qos_min_test() {
        assert_eq!(QoS::AtMostOnce.min(QoS::AtMostOnce), QoS::AtMostOnce);
        assert_eq!(QoS::AtMostOnce.min(QoS::AtLeastOnce), QoS::AtMostOnce);
        assert_eq!(QoS::AtLeastOnce.min(QoS::AtMostOnce), QoS::AtMostOnce);
        assert_eq!(QoS::AtLeastOnce.min(QoS::ExactlyOnce), QoS::AtLeastOnce);
        assert_eq!(QoS::ExactlyOnce.min(QoS::AtMostOnce), QoS::AtMostOnce);
        assert_eq!(QoS::ExactlyOnce.min(QoS::ExactlyOnce), QoS::ExactlyOnce);
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeSet, HashSet};
use std::hash::{Hash, Hasher};
use std::mem;

type Book = u32;
type GroupedBasket = Vec<Group>;
type Price = u32;
const BOOK_PRICE: Price = 800;

#[derive(Debug, Clone, PartialEq, Eq)]
struct Group(RefCell<BTreeSet<Book>>);

impl Group {
    fn new() -> Group {
        Group(RefCell::new(BTreeSet::new()))
    }

    fn new_containing(book: Book) -> Group {
        let g = Group::new();
        g.0.borrow_mut().insert(book);
        g
    }

    fn price(&self) -> Price {
        (self.0.borrow().len() as Price)
            * BOOK_PRICE
            * match self.0.borrow().len() {
                2 => 95,
                3 => 90,
                4 => 80,
                5 => 75,
                _ => 100,
            }
            / 100
    }
}

impl Ord for Group {
    // we want to order groups first by qty contained DESC, then by lowest value ASC
    fn cmp(&self, other: &Group) -> Ordering {
        match other.0.borrow().len().cmp(&self.0.borrow().len()) {
            Ordering::Equal => {
                if self.0.borrow().is_empty() {
                    Ordering::Equal
                } else {
                    self.0
                        .borrow()
                        .iter()
                        .next()
                        .unwrap()
                        .cmp(other.0.borrow().iter().next().unwrap())
                }
            }
            otherwise => otherwise,
        }
    }
}

impl PartialOrd for Group {
    fn partial_cmp(&self, other: &Group) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Hash for Group {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.0.borrow().hash(hasher);
    }
}

fn basket_price(basket: &GroupedBasket) -> Price {
    basket.iter().map(|g| g.price()).sum()
}

/// Compute the hash of a GroupedBasket
///
/// Note that we don't actually care at all about the _values_ within
/// the groups, only their lengths. Therefore, let's hash not the actual
/// GB but its lengths.
fn hash_of(basket: &GroupedBasket) -> u64 {
    let lengths = basket
        .iter()
        .map(|g| g.0.borrow().len())
        .collect::<Vec<_>>();
    let mut hasher = DefaultHasher::new();
    lengths.hash(&mut hasher);
    hasher.finish()
}

pub fn lowest_price(books: &[Book]) -> Price {
    DecomposeGroups::new(books)
        .map(|gb| basket_price(&gb))
        .min()
        .unwrap_or(0)
}

struct DecomposeGroups {
    prev_states: HashSet<u64>,
    next: Option<GroupedBasket>,
}

impl Iterator for DecomposeGroups {
    type Item = GroupedBasket;
    fn next(&mut self) -> Option<Self::Item> {
        // our goal here: produce a stream of valid groups, differentiated by their
        // counts, from most compact to most dispersed.
        //
        // Algorithm:
        //  - Start with the most compact groups possible
        //  - If the number of groups == 0 or the max population of any group == 1, return None
        //  - For every item in the most populous group:
        //      - Try removing it and adding it to a smaller group.
        //          - Can any smaller group accept it? if yes, move it there and return
        //  - If it cannot be added to any smaller group, try the next item from this set
        //  - If no item from the most populous group can be added to any smaller group,
        //    then move the last item from the most populous group into a new group, alone,
        //    and return
        let return_value = self.next.clone();
        if let Some(groups) = mem::replace(&mut self.next, None) {
            if !(groups.is_empty() || groups.iter().all(|g| g.0.borrow().len() == 1)) {
                let mut hypothetical;
                for mpg_book in groups[0].0.borrow().iter() {
                    for (idx, other_group) in groups[1..].iter().enumerate() {
                        if !other_group.0.borrow().contains(mpg_book) {
                            hypothetical = groups.clone();
                            hypothetical[0].0.borrow_mut().remove(mpg_book);
                            hypothetical[1 + idx].0.borrow_mut().insert(*mpg_book);
                            hypothetical.sort();
                            let hypothetical_hash = hash_of(&hypothetical);
                            if !self.prev_states.contains(&hypothetical_hash) {
                                self.prev_states.insert(hypothetical_hash);
                                self.next = Some(hypothetical);
                                return return_value;
                            }
                        }
                    }
                }
                // we've gone through all the items of the most populous group,
                // and none of them can be added to any other existing group.
                // We need to create a new group;
                let book = {
                    let backing_bt = groups[0].0.borrow();
                    let mut book_iter = backing_bt.iter();
                    *book_iter.next().unwrap()
                };
                hypothetical = groups.clone();
                hypothetical[0].0.borrow_mut().remove(&book);
                hypothetical.push(Group::new_containing(book));
                hypothetical.sort();
                self.prev_states.insert(hash_of(&hypothetical));
                self.next = Some(hypothetical);
            }
        }
        return_value
    }
}

impl DecomposeGroups {
    fn new(books: &[Book]) -> DecomposeGroups {
        let mut book_groups = GroupedBasket::new();
        'nextbook: for book in books {
            for Group(book_group) in book_groups.iter() {
                if !book_group.borrow().contains(&book) {
                    book_group.borrow_mut().insert(*book);
                    continue 'nextbook;
                }
            }
            // if we're here, we still haven't found a place for the book.
            // better add it to a new group
            book_groups.push(Group::new_containing(*book));
        }
        book_groups.sort();

        DecomposeGroups {
            next: Some(book_groups),
            prev_states: HashSet::new(),
        }
    }
}
<commit_msg>book-store: explicitly implement PartialEq<commit_after>use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeSet, HashSet};
use std::hash::{Hash, Hasher};
use std::mem;

type Book = u32;
type GroupedBasket = Vec<Group>;
type Price = u32;
const BOOK_PRICE: Price = 800;

#[derive(Debug, Clone)]
struct Group(RefCell<BTreeSet<Book>>);

impl Group {
    fn new() -> Group {
        Group(RefCell::new(BTreeSet::new()))
    }

    fn new_containing(book: Book) -> Group {
        let g = Group::new();
        g.0.borrow_mut().insert(book);
        g
    }

    fn price(&self) -> Price {
        (self.0.borrow().len() as Price)
            * BOOK_PRICE
            * match self.0.borrow().len() {
                2 => 95,
                3 => 90,
                4 => 80,
                5 => 75,
                _ => 100,
            }
            / 100
    }
}

impl Ord for Group {
    // we want to order groups first by qty contained DESC, then by lowest value ASC
    fn cmp(&self, other: &Group) -> Ordering {
        match other.0.borrow().len().cmp(&self.0.borrow().len()) {
            Ordering::Equal => {
                if self.0.borrow().is_empty() {
                    Ordering::Equal
                } else {
                    self.0
                        .borrow()
                        .iter()
                        .next()
                        .unwrap()
                        .cmp(other.0.borrow().iter().next().unwrap())
                }
            }
            otherwise => otherwise,
        }
    }
}

impl PartialOrd for Group {
    fn partial_cmp(&self, other: &Group) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for Group {
    fn eq(&self, other: &Group) -> bool {
        self.0.borrow().eq(&other.0.borrow())
    }
}

impl Eq for Group {}

impl Hash for Group {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.0.borrow().hash(hasher);
    }
}

fn basket_price(basket: &GroupedBasket) -> Price {
    basket.iter().map(|g| g.price()).sum()
}

/// Compute the hash of a GroupedBasket
///
/// Note that we don't actually care at all about the _values_ within
/// the groups, only their lengths. Therefore, let's hash not the actual
/// GB but its lengths.
fn hash_of(basket: &GroupedBasket) -> u64 {
    let lengths = basket
        .iter()
        .map(|g| g.0.borrow().len())
        .collect::<Vec<_>>();
    let mut hasher = DefaultHasher::new();
    lengths.hash(&mut hasher);
    hasher.finish()
}

pub fn lowest_price(books: &[Book]) -> Price {
    DecomposeGroups::new(books)
        .map(|gb| basket_price(&gb))
        .min()
        .unwrap_or(0)
}

struct DecomposeGroups {
    prev_states: HashSet<u64>,
    next: Option<GroupedBasket>,
}

impl Iterator for DecomposeGroups {
    type Item = GroupedBasket;
    fn next(&mut self) -> Option<Self::Item> {
        // our goal here: produce a stream of valid groups, differentiated by their
        // counts, from most compact to most dispersed.
        //
        // Algorithm:
        //  - Start with the most compact groups possible
        //  - If the number of groups == 0 or the max population of any group == 1, return None
        //  - For every item in the most populous group:
        //      - Try removing it and adding it to a smaller group.
        //          - Can any smaller group accept it? if yes, move it there and return
        //  - If it cannot be added to any smaller group, try the next item from this set
        //  - If no item from the most populous group can be added to any smaller group,
        //    then move the last item from the most populous group into a new group, alone,
        //    and return
        let return_value = self.next.clone();
        if let Some(groups) = mem::replace(&mut self.next, None) {
            if !(groups.is_empty() || groups.iter().all(|g| g.0.borrow().len() == 1)) {
                let mut hypothetical;
                for mpg_book in groups[0].0.borrow().iter() {
                    for (idx, other_group) in groups[1..].iter().enumerate() {
                        if !other_group.0.borrow().contains(mpg_book) {
                            hypothetical = groups.clone();
                            hypothetical[0].0.borrow_mut().remove(mpg_book);
                            hypothetical[1 + idx].0.borrow_mut().insert(*mpg_book);
                            hypothetical.sort();
                            let hypothetical_hash = hash_of(&hypothetical);
                            if !self.prev_states.contains(&hypothetical_hash) {
                                self.prev_states.insert(hypothetical_hash);
                                self.next = Some(hypothetical);
                                return return_value;
                            }
                        }
                    }
                }
                // we've gone through all the items of the most populous group,
                // and none of them can be added to any other existing group.
                // We need to create a new group;
                let book = {
                    let backing_bt = groups[0].0.borrow();
                    let mut book_iter = backing_bt.iter();
                    *book_iter.next().unwrap()
                };
                hypothetical = groups.clone();
                hypothetical[0].0.borrow_mut().remove(&book);
                hypothetical.push(Group::new_containing(book));
                hypothetical.sort();
                self.prev_states.insert(hash_of(&hypothetical));
                self.next = Some(hypothetical);
            }
        }
        return_value
    }
}

impl DecomposeGroups {
    fn new(books: &[Book]) -> DecomposeGroups {
        let mut book_groups = GroupedBasket::new();
        'nextbook: for book in books {
            for Group(book_group) in book_groups.iter() {
                if !book_group.borrow().contains(&book) {
                    book_group.borrow_mut().insert(*book);
                    continue 'nextbook;
                }
            }
            // if we're here, we still haven't found a place for the book.
            // better add it to a new group
            book_groups.push(Group::new_containing(*book));
        }
        book_groups.sort();

        DecomposeGroups {
            next: Some(book_groups),
            prev_states: HashSet::new(),
        }
    }
}
<|endoftext|>


<commit_before>use libsyntax2::{
    File, TextUnit, AstNode,
    ast::self,
    algo::{
        ancestors,
    },
};

use {
    AtomEdit, find_node_at_offset,
    scope::{FnScopes, ModuleScope},
};

#[derive(Debug)]
pub struct CompletionItem {
    pub name: String,
}

pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> {
    // Insert a fake ident to get a valid parse tree
    let file = {
        let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
        // Don't bother with completion if incremental reparse fails
        file.incremental_reparse(&edit)?
    };
    let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?;
    let mut res = Vec::new();
    if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() {
        let scopes = FnScopes::new(fn_def);
        complete_fn(name_ref, &scopes, &mut res);
    }
    if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() {
        let scope = ModuleScope::new(root);
        res.extend(
            scope.entries().iter()
                .map(|entry| CompletionItem { name: entry.name().to_string() })
        )
    }
    Some(res)
}

fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
    acc.extend(
        scopes.scope_chain(name_ref.syntax())
            .flat_map(|scope| scopes.entries(scope).iter())
            .map(|entry| CompletionItem { name: entry.name().to_string() })
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_utils::{assert_eq_dbg, extract_offset};

    fn do_check(code: &str, expected_completions: &str) {
        let (off, code) = extract_offset(&code);
        let file = File::parse(&code);
        let completions = scope_completion(&file, off).unwrap();
        assert_eq_dbg(expected_completions, &completions);
    }

    #[test]
    fn test_completion_let_scope() {
        do_check(r"
            fn quux(x: i32) {
                let y = 92;
                1 + <|>;
                let z = ();
            }
            ", r#"[CompletionItem { name: "y" },
                   CompletionItem { name: "x" },
                   CompletionItem { name: "quux" }]"#);
    }

    #[test]
    fn test_completion_if_let_scope() {
        do_check(r"
            fn quux() {
                if let Some(x) = foo() {
                    let y = 92;
                };
                if let Some(a) = bar() {
                    let b = 62;
                    1 + <|>
                }
            }
            ", r#"[CompletionItem { name: "b" },
                   CompletionItem { name: "a" },
                   CompletionItem { name: "quux" }]"#);
    }

    #[test]
    fn test_completion_for_scope() {
        do_check(r"
            fn quux() {
                for x in &[1, 2, 3] {
                    <|>
                }
            }
            ", r#"[CompletionItem { name: "x" },
                   CompletionItem { name: "quux" }]"#);
    }

    #[test]
    fn test_completion_mod_scope() {
        do_check(r"
            struct Foo;
            enum Baz {}
            fn quux() {
                <|>
            }
            ", r#"[CompletionItem { name: "Foo" },
                   CompletionItem { name: "Baz" },
                   CompletionItem { name: "quux" }]"#);
    }
}
<commit_msg>completion snippets<commit_after>use libsyntax2::{
    File, TextUnit, AstNode,
    ast::self,
    algo::{
        ancestors,
    },
};

use {
    AtomEdit, find_node_at_offset,
    scope::{FnScopes, ModuleScope},
};

#[derive(Debug)]
pub struct CompletionItem {
    pub name: String,
    pub snippet: Option<String>
}

pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> {
    // Insert a fake ident to get a valid parse tree
    let file = {
        let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
        // Don't bother with completion if incremental reparse fails
        file.incremental_reparse(&edit)?
    };
    let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?;
    let mut res = Vec::new();
    if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() {
        let scopes = FnScopes::new(fn_def);
        complete_fn(name_ref, &scopes, &mut res);
    }
    if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() {
        let scope = ModuleScope::new(root);
        res.extend(
            scope.entries().iter()
                .map(|entry| CompletionItem {
                    name: entry.name().to_string(),
                    snippet: None,
                })
        )
    }
    Some(res)
}

fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
    acc.extend(
        scopes.scope_chain(name_ref.syntax())
            .flat_map(|scope| scopes.entries(scope).iter())
            .map(|entry| CompletionItem {
                name: entry.name().to_string(),
                snippet: None,
            })
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_utils::{assert_eq_dbg, extract_offset};

    fn do_check(code: &str, expected_completions: &str) {
        let (off, code) = extract_offset(&code);
        let file = File::parse(&code);
        let completions = scope_completion(&file, off).unwrap();
        assert_eq_dbg(expected_completions, &completions);
    }

    #[test]
    fn test_completion_let_scope() {
        do_check(r"
            fn quux(x: i32) {
                let y = 92;
                1 + <|>;
                let z = ();
            }
            ", r#"[CompletionItem { name: "y" },
                   CompletionItem { name: "x" },
                   CompletionItem { name: "quux" }]"#);
    }

    #[test]
    fn test_completion_if_let_scope() {
        do_check(r"
            fn quux() {
                if let Some(x) = foo() {
                    let y = 92;
                };
                if let Some(a) = bar() {
                    let b = 62;
                    1 + <|>
                }
            }
            ", r#"[CompletionItem { name: "b" },
                   CompletionItem { name: "a" },
                   CompletionItem { name: "quux" }]"#);
    }

    #[test]
    fn test_completion_for_scope() {
        do_check(r"
            fn quux() {
                for x in &[1, 2, 3] {
                    <|>
                }
            }
            ", r#"[CompletionItem { name: "x" },
                   CompletionItem { name: "quux" }]"#);
    }

    #[test]
    fn test_completion_mod_scope() {
        do_check(r"
            struct Foo;
            enum Baz {}
            fn quux() {
                <|>
            }
            ", r#"[CompletionItem { name: "Foo" },
                   CompletionItem { name: "Baz" },
                   CompletionItem { name: "quux" }]"#);
    }
}
<|endoftext|>