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

//! The `servo` test application.
//!
//! Creates a `Browser` instance with a simple implementation of
//! the compositor's `WindowMethods` to create a working web browser.
//!
//! This browser's implementation of `WindowMethods` is built on top
//! of [glutin], the cross-platform OpenGL utility and windowing
//! library.
//!
//! For the engine itself look next door in `components/servo/lib.rs`.
//!
//! [glutin]: https://github.com/tomaka/glutin

#![feature(start, core_intrinsics)]

#[cfg(target_os = "android")]
extern crate android_injected_glue;
extern crate backtrace;
// The window backed by glutin
extern crate glutin_app as app;
#[macro_use]
extern crate log;
// The Servo engine
extern crate servo;
#[cfg(not(target_os = "android"))]
#[macro_use]
extern crate sig;

use backtrace::Backtrace;
use servo::Browser;
use servo::compositing::windowing::WindowEvent;
#[cfg(target_os = "android")]
use servo::config;
use servo::config::opts::{self, ArgumentParsingResult};
use servo::config::servo_version;
use servo::servo_config::prefs::PREFS;
use servo::servo_url::ServoUrl;
use std::env;
use std::panic;
use std::process;
use std::rc::Rc;
use std::thread;

pub mod platform {
    #[cfg(target_os = "macos")]
    pub use platform::macos::deinit;

    #[cfg(target_os = "macos")]
    pub mod macos;

    #[cfg(not(target_os = "macos"))]
    pub fn deinit() {}
}

#[cfg(not(target_os = "android"))]
fn install_crash_handler() {
    use backtrace::Backtrace;
    use sig::ffi::Sig;
    use std::intrinsics::abort;
    use std::thread;

    fn handler(_sig: i32) {
        let name = thread::current()
            .name()
            .map(|n| format!(" for thread \"{}\"", n))
            .unwrap_or("".to_owned());
        println!("Stack trace{}\n{:?}", name, Backtrace::new());
        unsafe {
            // N.B. Using process::abort() here causes the crash handler to be
            //      triggered recursively.
            abort();
        }
    }

    signal!(Sig::SEGV, handler); // handle segfaults
    signal!(Sig::ILL, handler); // handle stack overflow and unsupported CPUs
    signal!(Sig::IOT, handler); // handle double panics
    signal!(Sig::BUS, handler); // handle invalid memory access
}

#[cfg(target_os = "android")]
fn install_crash_handler() {}

fn main() {
    install_crash_handler();

    // Parse the command line options and store them globally
    let opts_result = opts::from_cmdline_args(&*args());

    let content_process_token = if let ArgumentParsingResult::ContentProcess(token) = opts_result {
        Some(token)
    } else {
        if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() {
            ::std::env::set_var("RUST_LOG", "compositing::constellation");
        }

        None
    };

    // TODO: once log-panics is released, can this be replaced by
    // log_panics::init()?
    panic::set_hook(Box::new(|info| {
        warn!("Panic hook called.");
        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => {
                match info.payload().downcast_ref::<String>() {
                    Some(s) => &**s,
                    None => "Box<Any>",
                }
            },
        };
        let current_thread = thread::current();
        let name = current_thread.name().unwrap_or("<unnamed>");
        if let Some(location) = info.location() {
            println!("{} (thread {}, at {}:{})",
                     msg,
                     name,
                     location.file(),
                     location.line());
        } else {
            println!("{} (thread {})", msg, name);
        }
        if env::var("RUST_BACKTRACE").is_ok() {
            println!("{:?}", Backtrace::new());
        }

        error!("{}", msg);
    }));

    setup_logging();

    if let Some(token) = content_process_token {
        return servo::run_content_process(token);
    }

    if opts::get().is_printing_version {
        println!("{}", servo_version());
        process::exit(0);
    }

    let window = app::create_window(None);

    // If the url is not provided, we fallback to the homepage in PREFS,
    // or a blank page in case the homepage is not set either.
    let target_url = opts::get().url.clone()
                .unwrap_or(ServoUrl::parse(PREFS.get("shell.homepage").as_string()
                    .unwrap_or("about:blank")).unwrap());

    // Our wrapper around `Browser` that also implements some
    // callbacks required by the glutin window implementation.
    let mut browser = BrowserWrapper {
        browser: Browser::new(window.clone(), target_url)
    };

    browser.browser.setup_logging();

    register_glutin_resize_handler(&window, &mut browser);

    browser.browser.handle_events(vec![WindowEvent::InitializeCompositing]);

    // Feed events from the window to the browser until the browser
    // says to stop.
    loop {
        let should_continue = browser.browser.handle_events(window.wait_events());
        if !should_continue {
            break;
        }
    }

    unregister_glutin_resize_handler(&window);

    platform::deinit()
}

fn register_glutin_resize_handler(window: &Rc<app::window::Window>, browser: &mut BrowserWrapper) {
    unsafe {
        window.set_nested_event_loop_listener(browser);
    }
}

fn unregister_glutin_resize_handler(window: &Rc<app::window::Window>) {
    unsafe {
        window.remove_nested_event_loop_listener();
    }
}

struct BrowserWrapper {
    browser: Browser<app::window::Window>,
}

impl app::NestedEventLoopListener for BrowserWrapper {
    fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool {
        let is_resize = match event {
            WindowEvent::Resize(..) => true,
            _ => false,
        };
        if !self.browser.handle_events(vec![event]) {
            return false;
        }
        if is_resize {
            self.browser.repaint_synchronously()
        }
        true
    }
}

#[cfg(target_os = "android")]
fn setup_logging() {
    // Piping logs from stdout/stderr to logcat happens in android_injected_glue.
    ::std::env::set_var("RUST_LOG", "error");

    unsafe { android_injected_glue::ffi::app_dummy() };
}

#[cfg(not(target_os = "android"))]
fn setup_logging() {}

#[cfg(target_os = "android")]
/// Attempt to read parameters from a file since they are not passed to us in Android environments.
/// The first line should be the "servo" argument and the last should be the URL to load.
/// Blank lines and those beginning with a '#' are ignored.
/// Each line should be a separate parameter as would be parsed by the shell.
/// For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 lines.
fn args() -> Vec<String> {
    use std::error::Error;
    use std::fs::File;
    use std::io::{BufRead, BufReader};

    let mut params_file = config::basedir::default_config_dir().unwrap();
    params_file.push("android_params");
    match File::open(params_file.to_str().unwrap()) {
        Ok(f) => {
            let mut vec = Vec::new();
            let file = BufReader::new(&f);
            for line in file.lines() {
                let l = line.unwrap().trim().to_owned();
                // ignore blank lines and those that start with a '#'
                match l.is_empty() || l.as_bytes()[0] == b'#' {
                    true => (),
                    false => vec.push(l),
                }
            }
            vec
        },
        Err(e) => {
            debug!("Failed to open params file '{}': {}",
                   params_file.to_str().unwrap(),
                   Error::description(&e));
            vec!["servo".to_owned(), "http://en.wikipedia.org/wiki/Rust".to_owned()]
        },
    }
}

#[cfg(not(target_os = "android"))]
fn args() -> Vec<String> {
    use std::env;
    env::args().collect()
}

#[cfg(target_os = "android")]
#[no_mangle]
#[inline(never)]
#[allow(non_snake_case)]
pub extern "C" fn android_main(app: *mut ()) {
    android_injected_glue::android_main2(app as *mut _, move |_, _| main());
}
<commit_msg>Fix parsing of shell.homepage<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The `servo` test application.
//!
//! Creates a `Browser` instance with a simple implementation of
//! the compositor's `WindowMethods` to create a working web browser.
//!
//! This browser's implementation of `WindowMethods` is built on top
//! of [glutin], the cross-platform OpenGL utility and windowing
//! library.
//!
//! For the engine itself look next door in `components/servo/lib.rs`.
//!
//! [glutin]: https://github.com/tomaka/glutin

#![feature(start, core_intrinsics)]

#[cfg(target_os = "android")]
extern crate android_injected_glue;
extern crate backtrace;
// The window backed by glutin
extern crate glutin_app as app;
#[macro_use]
extern crate log;
// The Servo engine
extern crate servo;
#[cfg(not(target_os = "android"))]
#[macro_use]
extern crate sig;

use backtrace::Backtrace;
use servo::Browser;
use servo::compositing::windowing::WindowEvent;
#[cfg(target_os = "android")]
use servo::config;
use servo::config::opts::{self, ArgumentParsingResult, parse_url_or_filename};
use servo::config::servo_version;
use servo::servo_config::prefs::PREFS;
use servo::servo_url::ServoUrl;
use std::env;
use std::panic;
use std::process;
use std::rc::Rc;
use std::thread;

pub mod platform {
    #[cfg(target_os = "macos")]
    pub use platform::macos::deinit;

    #[cfg(target_os = "macos")]
    pub mod macos;

    #[cfg(not(target_os = "macos"))]
    pub fn deinit() {}
}

#[cfg(not(target_os = "android"))]
fn install_crash_handler() {
    use backtrace::Backtrace;
    use sig::ffi::Sig;
    use std::intrinsics::abort;
    use std::thread;

    fn handler(_sig: i32) {
        let name = thread::current()
            .name()
            .map(|n| format!(" for thread \"{}\"", n))
            .unwrap_or("".to_owned());
        println!("Stack trace{}\n{:?}", name, Backtrace::new());
        unsafe {
            // N.B. Using process::abort() here causes the crash handler to be
            //      triggered recursively.
            abort();
        }
    }

    signal!(Sig::SEGV, handler); // handle segfaults
    signal!(Sig::ILL, handler); // handle stack overflow and unsupported CPUs
    signal!(Sig::IOT, handler); // handle double panics
    signal!(Sig::BUS, handler); // handle invalid memory access
}

#[cfg(target_os = "android")]
fn install_crash_handler() {}

fn main() {
    install_crash_handler();

    // Parse the command line options and store them globally
    let opts_result = opts::from_cmdline_args(&*args());

    let content_process_token = if let ArgumentParsingResult::ContentProcess(token) = opts_result {
        Some(token)
    } else {
        if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() {
            ::std::env::set_var("RUST_LOG", "compositing::constellation");
        }

        None
    };

    // TODO: once log-panics is released, can this be replaced by
    // log_panics::init()?
    panic::set_hook(Box::new(|info| {
        warn!("Panic hook called.");
        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => {
                match info.payload().downcast_ref::<String>() {
                    Some(s) => &**s,
                    None => "Box<Any>",
                }
            },
        };
        let current_thread = thread::current();
        let name = current_thread.name().unwrap_or("<unnamed>");
        if let Some(location) = info.location() {
            println!("{} (thread {}, at {}:{})",
                     msg,
                     name,
                     location.file(),
                     location.line());
        } else {
            println!("{} (thread {})", msg, name);
        }
        if env::var("RUST_BACKTRACE").is_ok() {
            println!("{:?}", Backtrace::new());
        }

        error!("{}", msg);
    }));

    setup_logging();

    if let Some(token) = content_process_token {
        return servo::run_content_process(token);
    }

    if opts::get().is_printing_version {
        println!("{}", servo_version());
        process::exit(0);
    }

    let window = app::create_window(None);

    // If the url is not provided, we fallback to the homepage in PREFS,
    // or a blank page in case the homepage is not set either.
    let cwd = env::current_dir().unwrap();
    let cmdline_url = opts::get().url.clone();
    let pref_url = PREFS.get("shell.homepage").as_string()
        .and_then(|str| parse_url_or_filename(&cwd, str).ok());
    let blank_url = ServoUrl::parse("about:blank").ok();

    let target_url = cmdline_url.or(pref_url).or(blank_url).unwrap();

    // Our wrapper around `Browser` that also implements some
    // callbacks required by the glutin window implementation.
    let mut browser = BrowserWrapper {
        browser: Browser::new(window.clone(), target_url)
    };

    browser.browser.setup_logging();

    register_glutin_resize_handler(&window, &mut browser);

    browser.browser.handle_events(vec![WindowEvent::InitializeCompositing]);

    // Feed events from the window to the browser until the browser
    // says to stop.
    loop {
        let should_continue = browser.browser.handle_events(window.wait_events());
        if !should_continue {
            break;
        }
    }

    unregister_glutin_resize_handler(&window);

    platform::deinit()
}

fn register_glutin_resize_handler(window: &Rc<app::window::Window>, browser: &mut BrowserWrapper) {
    unsafe {
        window.set_nested_event_loop_listener(browser);
    }
}

fn unregister_glutin_resize_handler(window: &Rc<app::window::Window>) {
    unsafe {
        window.remove_nested_event_loop_listener();
    }
}

struct BrowserWrapper {
    browser: Browser<app::window::Window>,
}

impl app::NestedEventLoopListener for BrowserWrapper {
    fn handle_event_from_nested_event_loop(&mut self, event: WindowEvent) -> bool {
        let is_resize = match event {
            WindowEvent::Resize(..) => true,
            _ => false,
        };
        if !self.browser.handle_events(vec![event]) {
            return false;
        }
        if is_resize {
            self.browser.repaint_synchronously()
        }
        true
    }
}

#[cfg(target_os = "android")]
fn setup_logging() {
    // Piping logs from stdout/stderr to logcat happens in android_injected_glue.
    ::std::env::set_var("RUST_LOG", "error");

    unsafe { android_injected_glue::ffi::app_dummy() };
}

#[cfg(not(target_os = "android"))]
fn setup_logging() {}

#[cfg(target_os = "android")]
/// Attempt to read parameters from a file since they are not passed to us in Android environments.
/// The first line should be the "servo" argument and the last should be the URL to load.
/// Blank lines and those beginning with a '#' are ignored.
/// Each line should be a separate parameter as would be parsed by the shell.
/// For example, "servo -p 10 http://en.wikipedia.org/wiki/Rust" would take 4 lines.
fn args() -> Vec<String> {
    use std::error::Error;
    use std::fs::File;
    use std::io::{BufRead, BufReader};

    let mut params_file = config::basedir::default_config_dir().unwrap();
    params_file.push("android_params");
    match File::open(params_file.to_str().unwrap()) {
        Ok(f) => {
            let mut vec = Vec::new();
            let file = BufReader::new(&f);
            for line in file.lines() {
                let l = line.unwrap().trim().to_owned();
                // ignore blank lines and those that start with a '#'
                match l.is_empty() || l.as_bytes()[0] == b'#' {
                    true => (),
                    false => vec.push(l),
                }
            }
            vec
        },
        Err(e) => {
            debug!("Failed to open params file '{}': {}",
                   params_file.to_str().unwrap(),
                   Error::description(&e));
            vec!["servo".to_owned(), "http://en.wikipedia.org/wiki/Rust".to_owned()]
        },
    }
}

#[cfg(not(target_os = "android"))]
fn args() -> Vec<String> {
    use std::env;
    env::args().collect()
}

#[cfg(target_os = "android")]
#[no_mangle]
#[inline(never)]
#[allow(non_snake_case)]
pub extern "C" fn android_main(app: *mut ()) {
    android_injected_glue::android_main2(app as *mut _, move |_, _| main());
}
<|endoftext|>


<commit_before>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Represents an address in the guest's memory space.

use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::ops::{Add, BitAnd, BitOr, Sub};

/// Simple helper trait used to store a raw address value.
pub trait AddressValue {
    /// Type of the address raw value.
    type V: Copy
        + PartialEq
        + Eq
        + PartialOrd
        + Ord
        + Add<Output = Self::V>
        + Sub<Output = Self::V>
        + BitAnd<Output = Self::V>
        + BitOr<Output = Self::V>;
}

/// Trait to represent an address within an address space.
///
/// To simplify the design and implementation, assume the same raw data type (AddressValue::V)
/// could be used to store address, size and offset for the address space. Thus the Address trait
/// could be used to manage address, size and offset. On the other hand, type aliases may be
/// defined to improve code readability.
///
/// One design rule is applied to the Address trait that operators (+, -, &, | etc) are not
/// supported and it forces clients to explicitly invoke corresponding methods. But there are
/// always exceptions:
///     Address (BitAnd|BitOr) AddressValue are supported.
pub trait Address:
    AddressValue
    + Sized
    + Default
    + Copy
    + Eq
    + PartialEq
    + Ord
    + PartialOrd
    + BitAnd<<Self as AddressValue>::V, Output = Self>
    + BitOr<<Self as AddressValue>::V, Output = Self>
{
    /// Get the raw value of the address.
    fn raw_value(&self) -> Self::V;

    /// Returns the offset from this address to the given base address.
    /// Only use this when `base` is guaranteed not to overflow.
    fn unchecked_offset_from(&self, base: Self) -> Self::V {
        self.raw_value() - base.raw_value()
    }

    /// Returns the result of the add or None if there is overflow.
    fn checked_add(&self, other: Self::V) -> Option<Self>;

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    fn unchecked_add(&self, offset: Self::V) -> Self;

    /// Returns the result of the subtraction or None if there is underflow.
    fn checked_sub(&self, other: Self::V) -> Option<Self>;
}

/// Represents an Address in the guest's memory.
#[derive(Clone, Copy, Debug)]
pub struct GuestAddress(pub usize);

impl AddressValue for GuestAddress {
    type V = usize;
}

impl Address for GuestAddress {
    /// Returns the address as a `Self::V` offset from 0x0.
    /// Use this when a raw number is needed to pass to the kernel.
    fn raw_value(&self) -> Self::V {
        self.0
    }

    /// Returns the result of the add or None if there is overflow.
    fn checked_add(&self, other: Self::V) -> Option<GuestAddress> {
        self.0.checked_add(other).map(GuestAddress)
    }

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    fn unchecked_add(&self, offset: Self::V) -> GuestAddress {
        GuestAddress(self.0 + offset)
    }

    /// Returns the result of the subtraction of None if there is underflow.
    fn checked_sub(&self, other: Self::V) -> Option<GuestAddress> {
        self.0.checked_sub(other).map(GuestAddress)
    }
}

impl Default for GuestAddress {
    fn default() -> GuestAddress {
        GuestAddress(0)
    }
}

impl BitAnd<<GuestAddress as AddressValue>::V> for GuestAddress {
    type Output = GuestAddress;

    fn bitand(self, other: <GuestAddress as AddressValue>::V) -> GuestAddress {
        GuestAddress(self.0 & other)
    }
}

impl BitOr<<GuestAddress as AddressValue>::V> for GuestAddress {
    type Output = GuestAddress;

    fn bitor(self, other: <GuestAddress as AddressValue>::V) -> GuestAddress {
        GuestAddress(self.0 | other)
    }
}

impl PartialEq for GuestAddress {
    fn eq(&self, other: &GuestAddress) -> bool {
        self.0 == other.0
    }
}
impl Eq for GuestAddress {}

impl Ord for GuestAddress {
    fn cmp(&self, other: &GuestAddress) -> Ordering {
        self.0.cmp(&other.0)
    }
}

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

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

    #[test]
    fn equals() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x300);
        let c = GuestAddress(0x301);
        assert_eq!(a, GuestAddress(a.raw_value()));
        assert_eq!(a, b);
        assert_eq!(b, a);
        assert_ne!(a, c);
        assert_ne!(c, a);
    }

    #[test]
    fn cmp() {
        for i in 1..10 {
            for j in 1..10 {
                assert_eq!(i < j, GuestAddress(i) < GuestAddress(j));
                assert_eq!(i > j, GuestAddress(i) > GuestAddress(j));
            }
        }
    }

    #[test]
    fn add_sub() {
        let a = GuestAddress(0x50);
        let b = GuestAddress(0x60);
        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
        assert_eq!(0x10, b.unchecked_offset_from(a));
    }

    #[test]
    fn checked_add_overflow() {
        let a = GuestAddress(0xffff_ffff_ffff_ff55);
        assert_eq!(Some(GuestAddress(0xffff_ffff_ffff_ff57)), a.checked_add(2));
        assert!(a.checked_add(0xf0).is_none());
    }

    #[test]
    fn checked_sub_underflow() {
        let a = GuestAddress(0xff);
        assert_eq!(Some(GuestAddress(0x0f)), a.checked_sub(0xf0));
        assert!(a.checked_sub(0xffff).is_none());
    }

    #[test]
    fn default() {
        assert_eq!(GuestAddress::default(), GuestAddress(0));
    }

    #[test]
    fn and() {
        let a = GuestAddress(0x00);
        let b = GuestAddress(0xff);
        assert_eq!(a & b.raw_value(), a);
    }

    #[test]
    fn or() {
        let a = GuestAddress(0x00);
        let b = GuestAddress(0xff);
        assert_eq!(a | b.raw_value(), b);
    }
}
<commit_msg>[GuestAddress] fix unit tests naming<commit_after>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Represents an address in the guest's memory space.

use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::ops::{Add, BitAnd, BitOr, Sub};

/// Simple helper trait used to store a raw address value.
pub trait AddressValue {
    /// Type of the address raw value.
    type V: Copy
        + PartialEq
        + Eq
        + PartialOrd
        + Ord
        + Add<Output = Self::V>
        + Sub<Output = Self::V>
        + BitAnd<Output = Self::V>
        + BitOr<Output = Self::V>;
}

/// Trait to represent an address within an address space.
///
/// To simplify the design and implementation, assume the same raw data type (AddressValue::V)
/// could be used to store address, size and offset for the address space. Thus the Address trait
/// could be used to manage address, size and offset. On the other hand, type aliases may be
/// defined to improve code readability.
///
/// One design rule is applied to the Address trait that operators (+, -, &, | etc) are not
/// supported and it forces clients to explicitly invoke corresponding methods. But there are
/// always exceptions:
///     Address (BitAnd|BitOr) AddressValue are supported.
pub trait Address:
    AddressValue
    + Sized
    + Default
    + Copy
    + Eq
    + PartialEq
    + Ord
    + PartialOrd
    + BitAnd<<Self as AddressValue>::V, Output = Self>
    + BitOr<<Self as AddressValue>::V, Output = Self>
{
    /// Get the raw value of the address.
    fn raw_value(&self) -> Self::V;

    /// Returns the offset from this address to the given base address.
    /// Only use this when `base` is guaranteed not to overflow.
    fn unchecked_offset_from(&self, base: Self) -> Self::V {
        self.raw_value() - base.raw_value()
    }

    /// Returns the result of the add or None if there is overflow.
    fn checked_add(&self, other: Self::V) -> Option<Self>;

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    fn unchecked_add(&self, offset: Self::V) -> Self;

    /// Returns the result of the subtraction or None if there is underflow.
    fn checked_sub(&self, other: Self::V) -> Option<Self>;
}

/// Represents an Address in the guest's memory.
#[derive(Clone, Copy, Debug)]
pub struct GuestAddress(pub usize);

impl AddressValue for GuestAddress {
    type V = usize;
}

impl Address for GuestAddress {
    /// Returns the address as a `Self::V` offset from 0x0.
    /// Use this when a raw number is needed to pass to the kernel.
    fn raw_value(&self) -> Self::V {
        self.0
    }

    /// Returns the result of the add or None if there is overflow.
    fn checked_add(&self, other: Self::V) -> Option<GuestAddress> {
        self.0.checked_add(other).map(GuestAddress)
    }

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    fn unchecked_add(&self, offset: Self::V) -> GuestAddress {
        GuestAddress(self.0 + offset)
    }

    /// Returns the result of the subtraction of None if there is underflow.
    fn checked_sub(&self, other: Self::V) -> Option<GuestAddress> {
        self.0.checked_sub(other).map(GuestAddress)
    }
}

impl Default for GuestAddress {
    fn default() -> GuestAddress {
        GuestAddress(0)
    }
}

impl BitAnd<<GuestAddress as AddressValue>::V> for GuestAddress {
    type Output = GuestAddress;

    fn bitand(self, other: <GuestAddress as AddressValue>::V) -> GuestAddress {
        GuestAddress(self.0 & other)
    }
}

impl BitOr<<GuestAddress as AddressValue>::V> for GuestAddress {
    type Output = GuestAddress;

    fn bitor(self, other: <GuestAddress as AddressValue>::V) -> GuestAddress {
        GuestAddress(self.0 | other)
    }
}

impl PartialEq for GuestAddress {
    fn eq(&self, other: &GuestAddress) -> bool {
        self.0 == other.0
    }
}
impl Eq for GuestAddress {}

impl Ord for GuestAddress {
    fn cmp(&self, other: &GuestAddress) -> Ordering {
        self.0.cmp(&other.0)
    }
}

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

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

    #[test]
    fn test_equals() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x300);
        let c = GuestAddress(0x301);
        assert_eq!(a, GuestAddress(a.raw_value()));
        assert_eq!(a, b);
        assert_eq!(b, a);
        assert_ne!(a, c);
        assert_ne!(c, a);
    }

    #[test]
    fn test_cmp() {
        for i in 1..10 {
            for j in 1..10 {
                assert_eq!(i < j, GuestAddress(i) < GuestAddress(j));
                assert_eq!(i > j, GuestAddress(i) > GuestAddress(j));
            }
        }
    }

    #[test]
    fn test_add_sub() {
        let a = GuestAddress(0x50);
        let b = GuestAddress(0x60);
        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
        assert_eq!(0x10, b.unchecked_offset_from(a));
    }

    #[test]
    fn test_checked_add_with_overflow() {
        let a = GuestAddress(0xffff_ffff_ffff_ff55);
        assert_eq!(Some(GuestAddress(0xffff_ffff_ffff_ff57)), a.checked_add(2));
        assert!(a.checked_add(0xf0).is_none());
    }

    #[test]
    fn test_checked_sub_with_underflow() {
        let a = GuestAddress(0xff);
        assert_eq!(Some(GuestAddress(0x0f)), a.checked_sub(0xf0));
        assert!(a.checked_sub(0xffff).is_none());
    }

    #[test]
    fn test_default() {
        assert_eq!(GuestAddress::default(), GuestAddress(0));
    }

    #[test]
    fn test_bit_and() {
        let a = GuestAddress(0x00);
        let b = GuestAddress(0xff);
        assert_eq!(a & b.raw_value(), a);
    }

    #[test]
    fn test_bit_or() {
        let a = GuestAddress(0x00);
        let b = GuestAddress(0xff);
        assert_eq!(a | b.raw_value(), b);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use aptos_metrics::{
    register_histogram, register_int_counter_vec, register_int_gauge_vec, DurationHistogram,
    IntCounterVec, IntGaugeVec,
};
use once_cell::sync::Lazy;

/// Histogram of busy time of spent in event processing loop
pub static EVENT_PROCESSING_LOOP_BUSY_DURATION_S: Lazy<DurationHistogram> = Lazy::new(|| {
    DurationHistogram::new(
        register_histogram!(
            "simple_onchain_discovery_event_processing_loop_busy_duration_s",
            "Histogram of busy time of spent in event processing loop"
        )
        .unwrap(),
    )
});

pub static DISCOVERY_COUNTS: Lazy<IntCounterVec> = Lazy::new(|| {
    register_int_counter_vec!(
        "diem_simple_onchain_discovery_counts",
        "Histogram of busy time of spent in event processing loop",
        &["role_type", "network_id", "peer_id", "metric"]
    )
    .unwrap()
});

pub static NETWORK_KEY_MISMATCH: Lazy<IntGaugeVec> = Lazy::new(|| {
    register_int_gauge_vec!(
        "aptos_network_key_mismatch",
        "Gauge of whether the network key mismatches onchain state",
        &["role_type", "network_id", "peer_id"]
    )
    .unwrap()
});
<commit_msg>[rename] simple_onchain_discovery_counts<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use aptos_metrics::{
    register_histogram, register_int_counter_vec, register_int_gauge_vec, DurationHistogram,
    IntCounterVec, IntGaugeVec,
};
use once_cell::sync::Lazy;

/// Histogram of busy time of spent in event processing loop
pub static EVENT_PROCESSING_LOOP_BUSY_DURATION_S: Lazy<DurationHistogram> = Lazy::new(|| {
    DurationHistogram::new(
        register_histogram!(
            "simple_onchain_discovery_event_processing_loop_busy_duration_s",
            "Histogram of busy time of spent in event processing loop"
        )
        .unwrap(),
    )
});

pub static DISCOVERY_COUNTS: Lazy<IntCounterVec> = Lazy::new(|| {
    register_int_counter_vec!(
        "aptos_simple_onchain_discovery_counts",
        "Histogram of busy time of spent in event processing loop",
        &["role_type", "network_id", "peer_id", "metric"]
    )
    .unwrap()
});

pub static NETWORK_KEY_MISMATCH: Lazy<IntGaugeVec> = Lazy::new(|| {
    register_int_gauge_vec!(
        "aptos_network_key_mismatch",
        "Gauge of whether the network key mismatches onchain state",
        &["role_type", "network_id", "peer_id"]
    )
    .unwrap()
});
<|endoftext|>


<commit_before>//! Utilities to support "extension" fields.
//!
//! Extensions are [described in the official protobuf documentation][exts].
//!
//! [exts]: https://developers.google.com/protocol-buffers/docs/proto#extensions

use std::marker::PhantomData;

use crate::core::Message;
use crate::reflect::runtime_types::RuntimeType;
use crate::reflect::types::ProtobufType;

/// Optional ext field
pub struct ExtFieldOptional<M: Message, T: ProtobufType> {
    /// Extension field number
    pub field_number: u32,
    /// Marker
    // TODO: hide
    pub phantom: PhantomData<(M, T)>,
}

/// Repeated ext field
pub struct ExtFieldRepeated<M: Message, T: ProtobufType> {
    /// Extension field number
    pub field_number: u32,
    /// Extension field number
    // TODO: hide
    pub phantom: PhantomData<(M, T)>,
}

impl<M: Message, T: ProtobufType> ExtFieldOptional<M, T> {
    /// Get a copy of value from a message.
    ///
    /// Extension data is stored in [`UnknownFields`](crate::UnknownFields).
    pub fn get(&self, m: &M) -> Option<<T::RuntimeType as RuntimeType>::Value> {
        m.get_unknown_fields()
            .get(self.field_number)
            .and_then(T::get_from_unknown)
    }
}

impl<M: Message, T: ProtobufType> ExtFieldRepeated<M, T> {
    /// Get a copy of value from a message (**not implemented**).
    pub fn get(&self, _m: &M) -> Vec<<T::RuntimeType as RuntimeType>::Value> {
        // TODO
        unimplemented!()
    }
}
<commit_msg>Hide ExtField* fields<commit_after>//! Utilities to support "extension" fields.
//!
//! Extensions are [described in the official protobuf documentation][exts].
//!
//! [exts]: https://developers.google.com/protocol-buffers/docs/proto#extensions

use std::marker::PhantomData;

use crate::core::Message;
use crate::reflect::runtime_types::RuntimeType;
use crate::reflect::types::ProtobufType;

/// Optional ext field
///
/// This is initialized from generated code, do not instantiate directly.
pub struct ExtFieldOptional<M: Message, T: ProtobufType> {
    /// Extension field number
    #[doc(hidden)]
    pub field_number: u32,
    /// Marker
    #[doc(hidden)]
    pub phantom: PhantomData<(M, T)>,
}

/// Repeated ext field
///
/// This is initialized from generated code, do not instantiate directly.
pub struct ExtFieldRepeated<M: Message, T: ProtobufType> {
    /// Extension field number
    #[doc(hidden)]
    pub field_number: u32,
    /// Extension field number
    #[doc(hidden)]
    pub phantom: PhantomData<(M, T)>,
}

impl<M: Message, T: ProtobufType> ExtFieldOptional<M, T> {
    /// Get a copy of value from a message.
    ///
    /// Extension data is stored in [`UnknownFields`](crate::UnknownFields).
    pub fn get(&self, m: &M) -> Option<<T::RuntimeType as RuntimeType>::Value> {
        m.get_unknown_fields()
            .get(self.field_number)
            .and_then(T::get_from_unknown)
    }
}

impl<M: Message, T: ProtobufType> ExtFieldRepeated<M, T> {
    /// Get a copy of value from a message (**not implemented**).
    pub fn get(&self, _m: &M) -> Vec<<T::RuntimeType as RuntimeType>::Value> {
        // TODO
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>use crate::result::*;
use crate::sign::Signature;
use chrono::Utc;
use rand::{thread_rng, Rng};
use reqwest;
use reqwest::header::HeaderMap;
pub use reqwest::{Method, Request, RequestBuilder, Response, StatusCode, Url};
use std::sync::RwLock;
use std::time::{Duration, Instant};

const BASE_URL: &'static str = "https://marketplace.walmartapis.com";

#[derive(Debug, Clone, Copy)]
pub enum WalmartMarketplace {
  USA,
  Canada,
}

pub enum WalmartCredential {
  TokenApi {
    client_id: String,
    client_secret: String,
  },
  Signature {
    channel_type: String,
    consumer_id: String,
    private_key: String,
  },
}

enum AuthState {
  TokenApi {
    client_id: String,
    client_secret: String,
    bearer_token: RwLock<Option<BearerToken>>,
  },
  Signature {
    channel_type: String,
    signature: Signature,
  },
}

struct BearerToken {
  access_token: String,
  expires_at: Instant,
}

pub trait ExtendUrlParams {
  fn extend_url_params(self, url: &mut Url);
}

impl ExtendUrlParams for () {
  fn extend_url_params(self, _: &mut Url) {}
}

impl<'a> ExtendUrlParams for &'a str {
  fn extend_url_params(self, url: &mut Url) {
    url.set_query(Some(self));
  }
}

impl<'a> ExtendUrlParams for String {
  fn extend_url_params(self, url: &mut Url) {
    if !self.is_empty() {
      url.set_query(Some(self.as_ref()));
    }
  }
}

impl<T1: AsRef<str>, T2: AsRef<str>> ExtendUrlParams for Vec<(T1, T2)> {
  fn extend_url_params(self, url: &mut Url) {
    url.query_pairs_mut().extend_pairs(self);
  }
}

pub struct Client {
  marketplace: WalmartMarketplace,
  base_url: Url,
  auth_state: AuthState,
  http: reqwest::Client,
}

impl Client {
  pub fn new(
    marketplace: WalmartMarketplace,
    credential: WalmartCredential,
  ) -> WalmartResult<Client> {
    let http = reqwest::Client::new();
    Client::with_http_client(marketplace, credential, http)
  }

  pub fn with_http_client(
    marketplace: WalmartMarketplace,
    credential: WalmartCredential,
    http: reqwest::Client,
  ) -> WalmartResult<Client> {
    Ok(Client {
      marketplace,
      base_url: Url::parse(BASE_URL)?,
      auth_state: match credential {
        WalmartCredential::Signature {
          consumer_id,
          private_key,
          channel_type,
        } => AuthState::Signature {
          signature: Signature::new(&consumer_id, &private_key)?,
          channel_type,
        },
        WalmartCredential::TokenApi {
          client_id,
          client_secret,
        } => AuthState::TokenApi {
          client_id,
          client_secret,
          bearer_token: RwLock::new(None),
        },
      },
      http,
    })
  }

  fn request<P>(&self, method: Method, path: &str, params: P) -> WalmartResult<RequestBuilder>
  where
    P: ExtendUrlParams,
  {
    let mut url = match self.marketplace {
      WalmartMarketplace::USA => self.base_url.join(path)?,
      WalmartMarketplace::Canada => {
        // add `ca` to url
        let path = path
          .split('/')
          .enumerate()
          .map(|(i, seg)| {
            if i == 1 {
              format!("{}/ca", seg)
            } else {
              seg.to_string()
            }
          })
          .collect::<Vec<String>>()
          .join("/");
        self.base_url.join(&path)?
      }
    };
    params.extend_url_params(&mut url);

    debug!("request: method = {}, url = {}", method, url);

    let timestamp = Utc::now();
    let timestamp = timestamp.timestamp() * 1000 + timestamp.timestamp_subsec_millis() as i64;

    let mut req = self.http.request(method.clone(), url.as_str());

    let mut headers = HeaderMap::new();
    let rid: String = thread_rng().gen_ascii_chars().take(10).collect();
    headers.insert("WM_SVC.NAME", "Walmart Marketplace".parse()?);
    headers.insert("WM_QOS.CORRELATION_ID", rid.parse()?);
    headers.insert("WM_SEC.TIMESTAMP", timestamp.to_string().parse()?);

    match self.auth_state {
      AuthState::Signature {
        ref channel_type,
        ref signature,
      } => {
        let sign = signature.sign(url.as_str(), method.clone(), timestamp)?;
        debug!("auth: Signature: sign = {}", sign);
        headers.insert("WM_CONSUMER.CHANNEL.TYPE", channel_type.parse()?);
        headers.insert("WM_CONSUMER.ID", signature.consumer_id().parse()?);
        headers.insert("WM_SEC.AUTH_SIGNATURE", sign.parse()?);
      }
      AuthState::TokenApi {
        ref client_id,
        ref client_secret,
        ..
      } => {
        let access_token = self.get_access_token(false)?;
        debug!("auth: TokenApi: access_token = {}", access_token);
        headers.insert("WM_SEC.ACCESS_TOKEN", access_token.parse()?);
        req = req.basic_auth(client_id, Some(client_secret));
      }
    }
    let req = req.headers(headers);
    Ok(req)
  }

  fn clear_access_token(&self) {
    match self.auth_state {
      AuthState::TokenApi {
        ref bearer_token, ..
      } => {
        bearer_token.write().unwrap().take();
      }
      _ => {}
    }
  }

  fn get_access_token(&self, force_renew: bool) -> WalmartResult<String> {
    use std::collections::HashMap;
    #[derive(Debug, Deserialize)]
    struct WalmartBearerToken {
      access_token: String,
      token_type: String,
      expires_in: u64,
    }

    match self.auth_state {
      AuthState::TokenApi {
        ref bearer_token,
        ref client_id,
        ref client_secret,
      } => {
        if !force_renew {
          let lock = bearer_token.read().unwrap();
          if let Some(ref token) = lock.as_ref() {
            if Instant::now() - token.expires_at > Duration::from_secs(120) {
              return Ok(token.access_token.clone());
            }
          }
          drop(lock);
        }

        let mut form = HashMap::new();
        form.insert("grant_type", "client_credentials");

        let mut headers = HeaderMap::new();
        let rid: String = thread_rng().gen_ascii_chars().take(10).collect();
        headers.insert("WM_SVC.NAME", "Walmart Marketplace".parse()?);
        headers.insert("WM_QOS.CORRELATION_ID", rid.parse()?);
        headers.insert("Accept", "application/json".parse()?);

        let mut res = self
          .http
          .request(Method::POST, &format!("{}/v3/token", BASE_URL))
          .headers(headers)
          .form(&form)
          .basic_auth(client_id, Some(client_secret))
          .send()?;

        let token: WalmartBearerToken = res.json()?;
        let access_token = token.access_token.clone();

        if token.token_type != "Bearer" {
          return Err(WalmartError::Msg(format!(
            "unsupported token type: {}",
            token.token_type
          )));
        }

        let mut lock = bearer_token.write().unwrap();
        std::mem::replace(
          &mut lock as &mut Option<_>,
          Some(BearerToken {
            access_token: token.access_token,
            expires_at: Instant::now() + Duration::from_secs(token.expires_in),
          }),
        );

        Ok(access_token)
      }
      _ => {
        return Err(WalmartError::Msg(
          "cannot get bearer with Signature Authentication".to_string(),
        ))
      }
    }
  }

  pub fn request_json<P>(
    &self,
    method: Method,
    path: &str,
    params: P,
  ) -> WalmartResult<RequestBuilder>
  where
    P: ExtendUrlParams,
  {
    use reqwest::header::{HeaderValue, ACCEPT};

    self
      .request(method, path, params)
      .map(|req| req.header(ACCEPT, HeaderValue::from_static("application/json")))
  }

  pub fn request_xml<P>(
    &self,
    method: Method,
    path: &str,
    params: P,
  ) -> WalmartResult<RequestBuilder>
  where
    P: ExtendUrlParams,
  {
    use reqwest::header::{HeaderValue, ACCEPT};

    self
      .request(method, path, params)
      .map(|req| req.header(ACCEPT, HeaderValue::from_static("application/xml")))
  }

  pub fn send(&self, req: RequestBuilder) -> WalmartResult<Response> {
    match req.send() {
      Ok(res) => {
        if res.status() == StatusCode::UNAUTHORIZED {
          self.clear_access_token();
        }
        Ok(res)
      }
      Err(err) => Err(err.into()),
    }
  }

  pub(crate) fn get_marketplace(&self) -> WalmartMarketplace {
    self.marketplace
  }
}

// #[cfg(test)]
// mod tests {
//   use super::*;
//   use dotenv::dotenv;
//   use std::env;

//   #[test]
//   fn client() {
//     use std::io::Read;
//     dotenv().ok();

//     let client = Client::new(&env::var("WALMART_CONSUMER_ID").unwrap(), &env::var("WALMART_PRIVATE_KEY").unwrap()).unwrap();
//     let mut res = client.request_json(Method::Get, "/v3/feeds/117E39F0B7654B08A059457FB6E803FF@AQYBAAA", ()).unwrap().send().unwrap();
//     println!("status: {}", res.status());
//     let mut json = String::new();
//     res.read_to_string(&mut json).unwrap();
//     println!("body: {}", json);
//     {
//       use std::fs::File;
//       use std::io::Write;
//       let mut f = File::create("samples/get_feed_aand_item_status.json").unwrap();
//       write!(&mut f, "{}", json).unwrap()
//     }
//   }
// }
<commit_msg>fix: Fix bearer token reuse.<commit_after>use crate::result::*;
use crate::sign::Signature;
use chrono::Utc;
use rand::{thread_rng, Rng};
use reqwest;
use reqwest::header::HeaderMap;
pub use reqwest::{Method, Request, RequestBuilder, Response, StatusCode, Url};
use std::sync::RwLock;
use std::time::{Duration, Instant};

const BASE_URL: &'static str = "https://marketplace.walmartapis.com";

#[derive(Debug, Clone, Copy)]
pub enum WalmartMarketplace {
  USA,
  Canada,
}

pub enum WalmartCredential {
  TokenApi {
    client_id: String,
    client_secret: String,
  },
  Signature {
    channel_type: String,
    consumer_id: String,
    private_key: String,
  },
}

enum AuthState {
  TokenApi {
    client_id: String,
    client_secret: String,
    bearer_token: RwLock<Option<BearerToken>>,
  },
  Signature {
    channel_type: String,
    signature: Signature,
  },
}

struct BearerToken {
  access_token: String,
  expires_at: Instant,
}

pub trait ExtendUrlParams {
  fn extend_url_params(self, url: &mut Url);
}

impl ExtendUrlParams for () {
  fn extend_url_params(self, _: &mut Url) {}
}

impl<'a> ExtendUrlParams for &'a str {
  fn extend_url_params(self, url: &mut Url) {
    url.set_query(Some(self));
  }
}

impl<'a> ExtendUrlParams for String {
  fn extend_url_params(self, url: &mut Url) {
    if !self.is_empty() {
      url.set_query(Some(self.as_ref()));
    }
  }
}

impl<T1: AsRef<str>, T2: AsRef<str>> ExtendUrlParams for Vec<(T1, T2)> {
  fn extend_url_params(self, url: &mut Url) {
    url.query_pairs_mut().extend_pairs(self);
  }
}

pub struct Client {
  marketplace: WalmartMarketplace,
  base_url: Url,
  auth_state: AuthState,
  http: reqwest::Client,
}

impl Client {
  pub fn new(
    marketplace: WalmartMarketplace,
    credential: WalmartCredential,
  ) -> WalmartResult<Client> {
    let http = reqwest::Client::new();
    Client::with_http_client(marketplace, credential, http)
  }

  pub fn with_http_client(
    marketplace: WalmartMarketplace,
    credential: WalmartCredential,
    http: reqwest::Client,
  ) -> WalmartResult<Client> {
    Ok(Client {
      marketplace,
      base_url: Url::parse(BASE_URL)?,
      auth_state: match credential {
        WalmartCredential::Signature {
          consumer_id,
          private_key,
          channel_type,
        } => AuthState::Signature {
          signature: Signature::new(&consumer_id, &private_key)?,
          channel_type,
        },
        WalmartCredential::TokenApi {
          client_id,
          client_secret,
        } => AuthState::TokenApi {
          client_id,
          client_secret,
          bearer_token: RwLock::new(None),
        },
      },
      http,
    })
  }

  fn request<P>(&self, method: Method, path: &str, params: P) -> WalmartResult<RequestBuilder>
  where
    P: ExtendUrlParams,
  {
    let mut url = match self.marketplace {
      WalmartMarketplace::USA => self.base_url.join(path)?,
      WalmartMarketplace::Canada => {
        // add `ca` to url
        let path = path
          .split('/')
          .enumerate()
          .map(|(i, seg)| {
            if i == 1 {
              format!("{}/ca", seg)
            } else {
              seg.to_string()
            }
          })
          .collect::<Vec<String>>()
          .join("/");
        self.base_url.join(&path)?
      }
    };
    params.extend_url_params(&mut url);

    debug!("request: method = {}, url = {}", method, url);

    let timestamp = Utc::now();
    let timestamp = timestamp.timestamp() * 1000 + timestamp.timestamp_subsec_millis() as i64;

    let mut req = self.http.request(method.clone(), url.as_str());

    let mut headers = HeaderMap::new();
    let rid: String = thread_rng().gen_ascii_chars().take(10).collect();
    headers.insert("WM_SVC.NAME", "Walmart Marketplace".parse()?);
    headers.insert("WM_QOS.CORRELATION_ID", rid.parse()?);
    headers.insert("WM_SEC.TIMESTAMP", timestamp.to_string().parse()?);

    match self.auth_state {
      AuthState::Signature {
        ref channel_type,
        ref signature,
      } => {
        let sign = signature.sign(url.as_str(), method.clone(), timestamp)?;
        debug!("auth: Signature: sign = {}", sign);
        headers.insert("WM_CONSUMER.CHANNEL.TYPE", channel_type.parse()?);
        headers.insert("WM_CONSUMER.ID", signature.consumer_id().parse()?);
        headers.insert("WM_SEC.AUTH_SIGNATURE", sign.parse()?);
      }
      AuthState::TokenApi {
        ref client_id,
        ref client_secret,
        ..
      } => {
        let access_token = self.get_access_token(false)?;
        debug!("auth: TokenApi: access_token = {}", access_token);
        headers.insert("WM_SEC.ACCESS_TOKEN", access_token.parse()?);
        req = req.basic_auth(client_id, Some(client_secret));
      }
    }
    let req = req.headers(headers);
    Ok(req)
  }

  fn clear_access_token(&self) {
    match self.auth_state {
      AuthState::TokenApi {
        ref bearer_token, ..
      } => {
        bearer_token.write().unwrap().take();
      }
      _ => {}
    }
  }

  fn get_access_token(&self, force_renew: bool) -> WalmartResult<String> {
    use std::collections::HashMap;
    #[derive(Debug, Deserialize)]
    struct WalmartBearerToken {
      access_token: String,
      token_type: String,
      expires_in: u64,
    }

    match self.auth_state {
      AuthState::TokenApi {
        ref bearer_token,
        ref client_id,
        ref client_secret,
      } => {
        if !force_renew {
          let lock = bearer_token.read().unwrap();
          if let Some(ref token) = lock.as_ref() {
            if token.expires_at - Instant::now() > Duration::from_secs(120) {
              return Ok(token.access_token.clone());
            }
          }
          drop(lock);
        }

        let mut form = HashMap::new();
        form.insert("grant_type", "client_credentials");

        let mut headers = HeaderMap::new();
        let rid: String = thread_rng().gen_ascii_chars().take(10).collect();
        headers.insert("WM_SVC.NAME", "Walmart Marketplace".parse()?);
        headers.insert("WM_QOS.CORRELATION_ID", rid.parse()?);
        headers.insert("Accept", "application/json".parse()?);

        let mut res = self
          .http
          .request(Method::POST, &format!("{}/v3/token", BASE_URL))
          .headers(headers)
          .form(&form)
          .basic_auth(client_id, Some(client_secret))
          .send()?;

        let token: WalmartBearerToken = res.json()?;
        let access_token = token.access_token.clone();

        if token.token_type != "Bearer" {
          return Err(WalmartError::Msg(format!(
            "unsupported token type: {}",
            token.token_type
          )));
        }

        debug!("token: {:#?}", token);

        let mut lock = bearer_token.write().unwrap();
        std::mem::replace(
          &mut lock as &mut Option<_>,
          Some(BearerToken {
            access_token: token.access_token,
            expires_at: Instant::now() + Duration::from_secs(token.expires_in),
          }),
        );

        Ok(access_token)
      }
      _ => {
        return Err(WalmartError::Msg(
          "cannot get bearer with Signature Authentication".to_string(),
        ))
      }
    }
  }

  pub fn request_json<P>(
    &self,
    method: Method,
    path: &str,
    params: P,
  ) -> WalmartResult<RequestBuilder>
  where
    P: ExtendUrlParams,
  {
    use reqwest::header::{HeaderValue, ACCEPT};

    self
      .request(method, path, params)
      .map(|req| req.header(ACCEPT, HeaderValue::from_static("application/json")))
  }

  pub fn request_xml<P>(
    &self,
    method: Method,
    path: &str,
    params: P,
  ) -> WalmartResult<RequestBuilder>
  where
    P: ExtendUrlParams,
  {
    use reqwest::header::{HeaderValue, ACCEPT};

    self
      .request(method, path, params)
      .map(|req| req.header(ACCEPT, HeaderValue::from_static("application/xml")))
  }

  pub fn send(&self, req: RequestBuilder) -> WalmartResult<Response> {
    match req.send() {
      Ok(res) => {
        if res.status() == StatusCode::UNAUTHORIZED {
          self.clear_access_token();
        }
        Ok(res)
      }
      Err(err) => Err(err.into()),
    }
  }

  pub(crate) fn get_marketplace(&self) -> WalmartMarketplace {
    self.marketplace
  }
}

// #[cfg(test)]
// mod tests {
//   use super::*;
//   use dotenv::dotenv;
//   use std::env;

//   #[test]
//   fn client() {
//     use std::io::Read;
//     dotenv().ok();

//     let client = Client::new(&env::var("WALMART_CONSUMER_ID").unwrap(), &env::var("WALMART_PRIVATE_KEY").unwrap()).unwrap();
//     let mut res = client.request_json(Method::Get, "/v3/feeds/117E39F0B7654B08A059457FB6E803FF@AQYBAAA", ()).unwrap().send().unwrap();
//     println!("status: {}", res.status());
//     let mut json = String::new();
//     res.read_to_string(&mut json).unwrap();
//     println!("body: {}", json);
//     {
//       use std::fs::File;
//       use std::io::Write;
//       let mut f = File::create("samples/get_feed_aand_item_status.json").unwrap();
//       write!(&mut f, "{}", json).unwrap()
//     }
//   }
// }
<|endoftext|>


<commit_before>pub mod fullscreen_shell {
    wayland_protocol!("fullscreen-shell",
        (wl_surface, wl_surface_interface),
        (wl_output, wl_output_interface)
    );
}

pub mod idle_inhibit {
    wayland_protocol!("idle-inhibit",
        (wl_surface, wl_surface_interface)
    );
}

pub mod input_method {
    wayland_protocol!("input-method",
        (wl_surface, wl_surface_interface),
        (wl_output, wl_output_interface),
        (wl_keyboard, wl_keyboard_interface)
    );
}

pub mod linux_dmabuf {
    wayland_protocol!("linux-dmabuf",
        (wl_buffer, wl_buffer_interface)
    );
}

pub mod pointer_constraints {
    //! protocol for constraining pointer motions
    //!
    //! This protocol specifies a set of interfaces used for adding constraints to
    //! the motion of a pointer. Possible constraints include confining pointer
    //! motions to a given region, or locking it to its current position.
    //!
    //! In order to constrain the pointer, a client must first bind the global
    //! interface "wp_pointer_constraints" which, if a compositor supports pointer
    //! constraints, is exposed by the registry. Using the bound global object, the
    //! client uses the request that corresponds to the type of constraint it wants
    //! to make. See wp_pointer_constraints for more details.

    wayland_protocol!("pointer-constraints",
        (wl_surface, wl_surface_interface),
        (wl_pointer, wl_pointer_interface),
        (wl_region, wl_region_interface)
    );
}

pub mod pointer_gestures {
    wayland_protocol!("pointer-gestures",
        (wl_surface, wl_surface_interface),
        (wl_pointer, wl_pointer_interface)
    );
}

pub mod relative_pointer {
    //! protocol for relative pointer motion events
    //!
    //! This protocol specifies a set of interfaces used for making clients able to
    //! receive relative pointer events not obstructed by barriers (such as the
    //! monitor edge or other pointer barriers).
    //!
    //! To start receiving relative pointer events, a client must first bind the
    //! global interface "wp_relative_pointer_manager" which, if a compositor
    //! supports relative pointer motion events, is exposed by the registry. After
    //! having created the relative pointer manager proxy object, the client uses
    //! it to create the actual relative pointer object using the
    //! "get_relative_pointer" request given a wl_pointer. The relative pointer
    //! motion events will then, when applicable, be transmitted via the proxy of
    //! the newly created relative pointer object. See the documentation of the
    //! relative pointer interface for more details.

    wayland_protocol!("relative-pointer",
        (wl_pointer, wl_pointer_interface)
    );
}

pub mod tablet {
    //! Wayland protocol for graphics tablets
    //!
    //! This description provides a high-level overview of the interplay between
    //! the interfaces defined this protocol. For details, see the protocol
    //! specification.
    //!
    //! More than one tablet may exist, and device-specifics matter. Tablets are
    //! not represented by a single virtual device like wl_pointer. A client
    //! binds to the tablet manager object which is just a proxy object. From
    //! that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
    //! and that returns the actual interface that has all the tablets. With
    //! this indirection, we can avoid merging wp_tablet into the actual Wayland
    //! protocol, a long-term benefit.
    //!
    //! The wp_tablet_seat sends a "tablet added" event for each tablet
    //! connected. That event is followed by descriptive events about the
    //! hardware; currently that includes events for name, vid/pid and
    //! a wp_tablet.path event that describes a local path. This path can be
    //! used to uniquely identify a tablet or get more information through
    //! libwacom. Emulated or nested tablets can skip any of those, e.g. a
    //! virtual tablet may not have a vid/pid. The sequence of descriptive
    //! events is terminated by a wp_tablet.done event to signal that a client
    //! may now finalize any initialization for that tablet.
    //!
    //! Events from tablets require a tool in proximity. Tools are also managed
    //! by the tablet seat; a "tool added" event is sent whenever a tool is new
    //! to the compositor. That event is followed by a number of descriptive
    //! events about the hardware; currently that includes capabilities,
    //! hardware id and serial number, and tool type. Similar to the tablet
    //! interface, a wp_tablet_tool.done event is sent to terminate that initial
    //! sequence.
    //!
    //! Any event from a tool happens on the wp_tablet_tool interface. When the
    //! tool gets into proximity of the tablet, a proximity_in event is sent on
    //! the wp_tablet_tool interface, listing the tablet and the surface. That
    //! event is followed by a motion event with the coordinates. After that,
    //! it's the usual motion, axis, button, etc. events. The protocol's
    //! serialisation means events are grouped by wp_tablet_tool.frame events.
    //!
    //! Two special events (that don't exist in X) are down and up. They signal
    //! "tip touching the surface". For tablets without real proximity
    //! detection, the sequence is: proximity_in, motion, down, frame.
    //!
    //! When the tool leaves proximity, a proximity_out event is sent. If any
    //! button is still down, a button release event is sent before this
    //! proximity event. These button events are sent in the same frame as the
    //! proximity event to signal to the client that the buttons were held when
    //! the tool left proximity.
    //!
    //! If the tool moves out of the surface but stays in proximity (i.e.
    //! between windows), compositor-specific grab policies apply. This usually
    //! means that the proximity-out is delayed until all buttons are released.
    //!
    //! Moving a tool physically from one tablet to the other has no real effect
    //! on the protocol, since we already have the tool object from the "tool
    //! added" event. All the information is already there and the proximity
    //! events on both tablets are all a client needs to reconstruct what
    //! happened.
    //!
    //! Some extra axes are normalized, i.e. the client knows the range as
    //! specified in the protocol (e.g. [0, 65535]), the granularity however is
    //! unknown. The current normalized axes are pressure, distance, and slider.
    //!
    //! Other extra axes are in physical units as specified in the protocol.
    //! The current extra axes with physical units are tilt, rotation and
    //! wheel rotation.
    //!
    //! Since tablets work independently of the pointer controlled by the mouse,
    //! the focus handling is independent too and controlled by proximity.
    //! The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
    //! This cursor surface may be the same as the mouse cursor, and it may be
    //! the same across tools but it is possible to be more fine-grained. For
    //! example, a client may set different cursors for the pen and eraser.
    //!
    //! Tools are generally independent of tablets and it is
    //! compositor-specific policy when a tool can be removed. Common approaches
    //! will likely include some form of removing a tool when all tablets the
    //! tool was used on are removed.

    wayland_protocol!("tablet",
        (wl_seat, wl_seat_interface),
        (wl_surface, wl_surface_interface)
    );
}

pub mod text_input {
    wayland_protocol!("text-input",
        (wl_seat, wl_seat_interface),
        (wl_surface, wl_surface_interface)
    );
}

pub mod xdg_foreign {
    //! Protocol for exporting xdg surface handles
    //!
    //! This protocol specifies a way for making it possible to reference a surface
    //! of a different client. With such a reference, a client can, by using the
    //! interfaces provided by this protocol, manipulate the relationship between
    //! its own surfaces and the surface of some other client. For example, stack
    //! some of its own surface above the other clients surface.
    //!
    //! In order for a client A to get a reference of a surface of client B, client
    //! B must first export its surface using xdg_exporter.export. Upon doing this,
    //! client B will receive a handle (a unique string) that it may share with
    //! client A in some way (for example D-Bus). After client A has received the
    //! handle from client B, it may use xdg_importer.import to create a reference
    //! to the surface client B just exported. See the corresponding requests for
    //! details.
    //!
    //! A possible use case for this is out-of-process dialogs. For example when a
    //! sandboxed client without file system access needs the user to select a file
    //! on the file system, given sandbox environment support, it can export its
    //! surface, passing the exported surface handle to an unsandboxed process that
    //! can show a file browser dialog and stack it above the sandboxed client's
    //! surface.

    wayland_protocol!("xdg-foreign",
        (wl_surface, wl_surface_interface)
    );
}

/*
 * This will need some more refinements on the bitflags!() macro
 * Hopefully associated consts could improve scoping, the issue is that
 * there are two bitflags in the same wayland interface that declare values
 * with the same name
 *
#[cfg(feature = "nightly")]
pub mod xdg_shell {
    wayland_protocol!("xdg-shell",
        (wl_surface, wl_surface_interface),
        (wl_output, wl_output_interface),
        (wl_seat, wl_seat_interface)
    );
}
* */
<commit_msg>protocols: enable xdg_shell<commit_after>pub mod fullscreen_shell {
    wayland_protocol!("fullscreen-shell",
        (wl_surface, wl_surface_interface),
        (wl_output, wl_output_interface)
    );
}

pub mod idle_inhibit {
    wayland_protocol!("idle-inhibit",
        (wl_surface, wl_surface_interface)
    );
}

pub mod input_method {
    wayland_protocol!("input-method",
        (wl_surface, wl_surface_interface),
        (wl_output, wl_output_interface),
        (wl_keyboard, wl_keyboard_interface)
    );
}

pub mod linux_dmabuf {
    wayland_protocol!("linux-dmabuf",
        (wl_buffer, wl_buffer_interface)
    );
}

pub mod pointer_constraints {
    //! protocol for constraining pointer motions
    //!
    //! This protocol specifies a set of interfaces used for adding constraints to
    //! the motion of a pointer. Possible constraints include confining pointer
    //! motions to a given region, or locking it to its current position.
    //!
    //! In order to constrain the pointer, a client must first bind the global
    //! interface "wp_pointer_constraints" which, if a compositor supports pointer
    //! constraints, is exposed by the registry. Using the bound global object, the
    //! client uses the request that corresponds to the type of constraint it wants
    //! to make. See wp_pointer_constraints for more details.

    wayland_protocol!("pointer-constraints",
        (wl_surface, wl_surface_interface),
        (wl_pointer, wl_pointer_interface),
        (wl_region, wl_region_interface)
    );
}

pub mod pointer_gestures {
    wayland_protocol!("pointer-gestures",
        (wl_surface, wl_surface_interface),
        (wl_pointer, wl_pointer_interface)
    );
}

pub mod relative_pointer {
    //! protocol for relative pointer motion events
    //!
    //! This protocol specifies a set of interfaces used for making clients able to
    //! receive relative pointer events not obstructed by barriers (such as the
    //! monitor edge or other pointer barriers).
    //!
    //! To start receiving relative pointer events, a client must first bind the
    //! global interface "wp_relative_pointer_manager" which, if a compositor
    //! supports relative pointer motion events, is exposed by the registry. After
    //! having created the relative pointer manager proxy object, the client uses
    //! it to create the actual relative pointer object using the
    //! "get_relative_pointer" request given a wl_pointer. The relative pointer
    //! motion events will then, when applicable, be transmitted via the proxy of
    //! the newly created relative pointer object. See the documentation of the
    //! relative pointer interface for more details.

    wayland_protocol!("relative-pointer",
        (wl_pointer, wl_pointer_interface)
    );
}

pub mod tablet {
    //! Wayland protocol for graphics tablets
    //!
    //! This description provides a high-level overview of the interplay between
    //! the interfaces defined this protocol. For details, see the protocol
    //! specification.
    //!
    //! More than one tablet may exist, and device-specifics matter. Tablets are
    //! not represented by a single virtual device like wl_pointer. A client
    //! binds to the tablet manager object which is just a proxy object. From
    //! that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
    //! and that returns the actual interface that has all the tablets. With
    //! this indirection, we can avoid merging wp_tablet into the actual Wayland
    //! protocol, a long-term benefit.
    //!
    //! The wp_tablet_seat sends a "tablet added" event for each tablet
    //! connected. That event is followed by descriptive events about the
    //! hardware; currently that includes events for name, vid/pid and
    //! a wp_tablet.path event that describes a local path. This path can be
    //! used to uniquely identify a tablet or get more information through
    //! libwacom. Emulated or nested tablets can skip any of those, e.g. a
    //! virtual tablet may not have a vid/pid. The sequence of descriptive
    //! events is terminated by a wp_tablet.done event to signal that a client
    //! may now finalize any initialization for that tablet.
    //!
    //! Events from tablets require a tool in proximity. Tools are also managed
    //! by the tablet seat; a "tool added" event is sent whenever a tool is new
    //! to the compositor. That event is followed by a number of descriptive
    //! events about the hardware; currently that includes capabilities,
    //! hardware id and serial number, and tool type. Similar to the tablet
    //! interface, a wp_tablet_tool.done event is sent to terminate that initial
    //! sequence.
    //!
    //! Any event from a tool happens on the wp_tablet_tool interface. When the
    //! tool gets into proximity of the tablet, a proximity_in event is sent on
    //! the wp_tablet_tool interface, listing the tablet and the surface. That
    //! event is followed by a motion event with the coordinates. After that,
    //! it's the usual motion, axis, button, etc. events. The protocol's
    //! serialisation means events are grouped by wp_tablet_tool.frame events.
    //!
    //! Two special events (that don't exist in X) are down and up. They signal
    //! "tip touching the surface". For tablets without real proximity
    //! detection, the sequence is: proximity_in, motion, down, frame.
    //!
    //! When the tool leaves proximity, a proximity_out event is sent. If any
    //! button is still down, a button release event is sent before this
    //! proximity event. These button events are sent in the same frame as the
    //! proximity event to signal to the client that the buttons were held when
    //! the tool left proximity.
    //!
    //! If the tool moves out of the surface but stays in proximity (i.e.
    //! between windows), compositor-specific grab policies apply. This usually
    //! means that the proximity-out is delayed until all buttons are released.
    //!
    //! Moving a tool physically from one tablet to the other has no real effect
    //! on the protocol, since we already have the tool object from the "tool
    //! added" event. All the information is already there and the proximity
    //! events on both tablets are all a client needs to reconstruct what
    //! happened.
    //!
    //! Some extra axes are normalized, i.e. the client knows the range as
    //! specified in the protocol (e.g. [0, 65535]), the granularity however is
    //! unknown. The current normalized axes are pressure, distance, and slider.
    //!
    //! Other extra axes are in physical units as specified in the protocol.
    //! The current extra axes with physical units are tilt, rotation and
    //! wheel rotation.
    //!
    //! Since tablets work independently of the pointer controlled by the mouse,
    //! the focus handling is independent too and controlled by proximity.
    //! The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
    //! This cursor surface may be the same as the mouse cursor, and it may be
    //! the same across tools but it is possible to be more fine-grained. For
    //! example, a client may set different cursors for the pen and eraser.
    //!
    //! Tools are generally independent of tablets and it is
    //! compositor-specific policy when a tool can be removed. Common approaches
    //! will likely include some form of removing a tool when all tablets the
    //! tool was used on are removed.

    wayland_protocol!("tablet",
        (wl_seat, wl_seat_interface),
        (wl_surface, wl_surface_interface)
    );
}

pub mod text_input {
    wayland_protocol!("text-input",
        (wl_seat, wl_seat_interface),
        (wl_surface, wl_surface_interface)
    );
}

pub mod xdg_foreign {
    //! Protocol for exporting xdg surface handles
    //!
    //! This protocol specifies a way for making it possible to reference a surface
    //! of a different client. With such a reference, a client can, by using the
    //! interfaces provided by this protocol, manipulate the relationship between
    //! its own surfaces and the surface of some other client. For example, stack
    //! some of its own surface above the other clients surface.
    //!
    //! In order for a client A to get a reference of a surface of client B, client
    //! B must first export its surface using xdg_exporter.export. Upon doing this,
    //! client B will receive a handle (a unique string) that it may share with
    //! client A in some way (for example D-Bus). After client A has received the
    //! handle from client B, it may use xdg_importer.import to create a reference
    //! to the surface client B just exported. See the corresponding requests for
    //! details.
    //!
    //! A possible use case for this is out-of-process dialogs. For example when a
    //! sandboxed client without file system access needs the user to select a file
    //! on the file system, given sandbox environment support, it can export its
    //! surface, passing the exported surface handle to an unsandboxed process that
    //! can show a file browser dialog and stack it above the sandboxed client's
    //! surface.

    wayland_protocol!("xdg-foreign",
        (wl_surface, wl_surface_interface)
    );
}

#[cfg(feature = "nightly")]
pub mod xdg_shell {
    wayland_protocol!("xdg-shell",
        (wl_surface, wl_surface_interface),
        (wl_output, wl_output_interface),
        (wl_seat, wl_seat_interface)
    );
}
<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

#![feature(libc)]

extern crate wayland_client;
extern crate tempfile;
extern crate libc;

use std::{ptr, cmp};
use std::num::Wrapping;
use std::io::Result;
use std::os::unix::io::AsRawFd;

use tempfile::TempFile;

use wayland_client::client::{Display, Compositor, Shell, Shm, ShmFormat, Surface,
                             Registry, RegistryEventHandler,
                             ShellSurface, ShellSurfaceEventHandler,
                             Buffer, BufferEventHandler,
                             Callback, CallbackEventHandler};

struct MyRegistry {
    registry: Registry,
    compositor: Option<Compositor>,
    shell: Option<Shell>,
    shm: Option<Shm>,
}

impl MyRegistry {
    fn new(display: &mut Display) -> Box<MyRegistry> {
        let registry = display.get_registry().unwrap();
        return Box::new(MyRegistry {
            registry: registry,
            compositor: None,
            shell: None,
            shm: None,
        });
    }

    fn take_compositor(&mut self) -> Compositor {
        return self.compositor.take().unwrap();
    }

    fn take_shell(&mut self) -> Shell {
        return self.shell.take().unwrap();
    }

    fn take_shm(&mut self) -> Shm {
        return self.shm.take().unwrap();
    }
}

impl RegistryEventHandler for MyRegistry {
    fn get_registry(&mut self) -> &mut Registry {
        return &mut self.registry;
    }

    fn on_global(&mut self, name: u32, interface: String, version: u32) {
        if interface == "wl_compositor" {
            self.compositor = self.registry.bind(name, version).ok();
        } else if interface == "wl_shell" {
            self.shell = self.registry.bind(name, version).ok();
        } else if interface == "wl_shm" {
            self.shm = self.registry.bind(name, version).ok();
        }
    }
}

struct MyShellSurface {
    pub shell_surface: ShellSurface,
}

impl MyShellSurface {
    fn new(shell: &mut Shell, surface: &mut Surface) -> Box<MyShellSurface> {
        let mut shell_surface = shell.get_shell_surface(surface).unwrap();
        shell_surface.set_title("simple shm");
        shell_surface.set_toplevel();
        return Box::new(MyShellSurface {
            shell_surface: shell_surface,
        });
    }
}

impl ShellSurfaceEventHandler for MyShellSurface {
    fn get_shell_surface(&mut self) -> &mut ShellSurface {
        return &mut self.shell_surface;
    }

    fn on_ping(&mut self, serial: u32) {
        self.shell_surface.pong(serial);
    }
}

struct MyBuffer {
    buffer: Buffer,
    _file: TempFile,
    memory: *mut libc::c_void,
    size: i32,
    busy: bool,
}

impl MyBuffer {
    fn new(width: i32, height: i32, shm: &mut Shm) -> Result<Box<MyBuffer>> {
        let size = width * height * 4;
        let file = try!(TempFile::new());
        file.set_len(size as u64).unwrap();

        let memory = unsafe {
            libc::mmap(ptr::null_mut(), size as libc::size_t,
                       libc::PROT_WRITE | libc::PROT_READ,
                       libc::MAP_SHARED | libc::MAP_FILE,
                       file.as_raw_fd(), 0)
        };

        if memory == libc::MAP_FAILED {
            panic!("Failed to allocate the memory map");
        }

        let mut pool = shm.create_pool(file.as_raw_fd(), size).unwrap();
        let buffer = pool.create_buffer(0, width, height, width * 4,
                                        ShmFormat::XRGB8888 as u32).unwrap();
        pool.destroy();
        return Ok(Box::new(MyBuffer {
            buffer: buffer,
            _file: file,
            memory: memory,
            size: size,
            busy: false,
        }));
    }

    fn is_not_busy(&self) -> bool {
        return !self.busy;
    }

    fn set_busy(&mut self) {
        self.busy = true;
    }

    fn get_pointer(&mut self) -> *mut u32 {
        return self.memory as *mut u32;
    }
}

impl BufferEventHandler for MyBuffer {
    fn get_buffer(&mut self) -> &mut Buffer {
        return &mut self.buffer;
    }

    fn on_release(&mut self) {
        self.busy = false;
    }
}

impl Drop for MyBuffer {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(self.memory as *mut libc::c_void,
                         self.size as libc::size_t);
        }
    }
}

struct Window {
    width: i32,
    height: i32,
    surface: Surface,
    frame: Option<Callback>,
    first_buffer: Box<MyBuffer>,
    second_buffer: Box<MyBuffer>,
}

impl Window {
    fn new(mut shm: Shm, mut surface: Surface, width: i32, height: i32) -> Window {
        surface.damage(0, 0, width, height);
        let mut first_buffer = MyBuffer::new(width, height, &mut shm).unwrap();
        first_buffer.connect_dispatcher();
        let mut second_buffer = MyBuffer::new(width, height, &mut shm).unwrap();
        second_buffer.connect_dispatcher();
        return Window {
            width: width,
            height: height,
            surface: surface,
            frame: None,
            first_buffer: first_buffer,
            second_buffer: second_buffer,
        };
    }

    fn paint_pixels(&mut self, use_first_buffer: bool, time: i32) {
        let padding = 20;

        let halfh = padding + (self.height - padding * 2) / 2;
        let halfw = padding + (self.width  - padding * 2) / 2;

        let or = (cmp::min(halfw, halfh) - 8).pow(2);
        let ir = (cmp::min(halfw, halfh) - 40).pow(2);

        let mut pointer = if use_first_buffer { self.first_buffer.get_pointer() }
                          else { self.second_buffer.get_pointer() };

        pointer = unsafe { pointer.offset((padding * self.width) as isize)};

        for y in (20 .. self.height - padding) {
            let y2 = (y - halfh) * (y - halfh);

            pointer = unsafe { pointer.offset(padding as isize)};
            for x in (20 .. self.width - 20) {
                let r2 = (x - halfw) * (x - halfw) + y2;

                let v = Wrapping(if r2 < ir { (r2 / 32 + time / 64) }
                                 else if r2 < or { (y + time / 32) }
                                 else { (x + time / 16) } as u32)
                        * Wrapping(0x0080401);
                let mut v2 = v.0 & 0x00ffffff;

                if (x - y).abs() > 6 && (x + y - self.height).abs() > 6 {
                    v2 |= 0xff000000;
                }

                pointer = unsafe { pointer.offset(1)};
                unsafe { *pointer = v2; }
            }
            pointer = unsafe { pointer.offset(padding as isize)};
        }
    }

    fn redraw(&mut self, time: i32) {
        let use_first_buffer = if self.first_buffer.is_not_busy() { true }
                        else if self.second_buffer.is_not_busy() { false }
                        else { panic!("no buffers free") };

        if use_first_buffer { self.first_buffer.set_busy(); }
        else { self.second_buffer.set_busy(); }

        self.paint_pixels(use_first_buffer, time);

        if use_first_buffer { self.surface.attach(Some(self.first_buffer.get_buffer()), 0, 0); }
        else { self.surface.attach(Some(self.second_buffer.get_buffer()), 0, 0); }

        self.surface.damage(20, 20, self.width - 20, self.height - 20);
        self.frame = Some(self.surface.frame().unwrap());
        self.connect_dispatcher();
        self.surface.commit();
    }
}

impl CallbackEventHandler for Window {
    fn get_callback<'a>(&'a mut self) -> &'a mut Callback {
        return self.frame.as_mut().unwrap();
    }

    fn on_done(&mut self, callback_data: u32) {
        self.frame = None;
        self.redraw(callback_data as i32);
    }
}

fn main() {
    let mut display = Display::connect(None).unwrap();
    let mut registry = MyRegistry::new(&mut display);
    registry.connect_dispatcher();
    display.roundtrip();

    let shm = registry.take_shm();
    let mut shell = registry.take_shell();
    let mut compositor = registry.take_compositor();

    let mut surface = compositor.create_surface().unwrap();
    let mut shell_surface = MyShellSurface::new(&mut shell, &mut surface);
    shell_surface.connect_dispatcher();

    let mut window = Window::new(shm, surface, 250, 250);
    window.redraw(0);

    loop { display.dispatch(); }
}
<commit_msg>Revert "examples: fix after scanner update"<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

#![feature(libc)]

extern crate wayland_client;
extern crate tempfile;
extern crate libc;

use std::{ptr, cmp};
use std::num::Wrapping;
use std::io::Result;
use std::os::unix::io::AsRawFd;

use tempfile::TempFile;

use wayland_client::client::{Display, Compositor, Shell, Shm, ShmFormat, Surface,
                             Registry, RegistryEventHandler,
                             ShellSurface, ShellSurfaceEventHandler,
                             Buffer, BufferEventHandler,
                             Callback, CallbackEventHandler};

struct MyRegistry {
    registry: Registry,
    compositor: Option<Compositor>,
    shell: Option<Shell>,
    shm: Option<Shm>,
}

impl MyRegistry {
    fn new(display: &mut Display) -> Box<MyRegistry> {
        let registry = display.get_registry().unwrap();
        return Box::new(MyRegistry {
            registry: registry,
            compositor: None,
            shell: None,
            shm: None,
        });
    }

    fn take_compositor(&mut self) -> Compositor {
        return self.compositor.take().unwrap();
    }

    fn take_shell(&mut self) -> Shell {
        return self.shell.take().unwrap();
    }

    fn take_shm(&mut self) -> Shm {
        return self.shm.take().unwrap();
    }
}

impl RegistryEventHandler for MyRegistry {
    fn get_registry(&mut self) -> &mut Registry {
        return &mut self.registry;
    }

    fn on_global(&mut self, name: u32, interface: String, version: u32) {
        if interface == "wl_compositor" {
            self.compositor = self.registry.bind(name, version).ok();
        } else if interface == "wl_shell" {
            self.shell = self.registry.bind(name, version).ok();
        } else if interface == "wl_shm" {
            self.shm = self.registry.bind(name, version).ok();
        }
    }
}

struct MyShellSurface {
    pub shell_surface: ShellSurface,
}

impl MyShellSurface {
    fn new(shell: &mut Shell, surface: &mut Surface) -> Box<MyShellSurface> {
        let mut shell_surface = shell.get_shell_surface(surface).unwrap();
        shell_surface.set_title("simple shm");
        shell_surface.set_toplevel();
        return Box::new(MyShellSurface {
            shell_surface: shell_surface,
        });
    }
}

impl ShellSurfaceEventHandler for MyShellSurface {
    fn get_shell_surface(&mut self) -> &mut ShellSurface {
        return &mut self.shell_surface;
    }

    fn on_ping(&mut self, serial: u32) {
        self.shell_surface.pong(serial);
    }
}

struct MyBuffer {
    buffer: Buffer,
    _file: TempFile,
    memory: *mut libc::c_void,
    size: i32,
    busy: bool,
}

impl MyBuffer {
    fn new(width: i32, height: i32, shm: &mut Shm) -> Result<Box<MyBuffer>> {
        let size = width * height * 4;
        let file = try!(TempFile::new());
        file.set_len(size as u64).unwrap();

        let memory = unsafe {
            libc::mmap(ptr::null_mut(), size as libc::size_t,
                       libc::PROT_WRITE | libc::PROT_READ,
                       libc::MAP_SHARED | libc::MAP_FILE,
                       file.as_raw_fd(), 0)
        };

        if memory == libc::MAP_FAILED {
            panic!("Failed to allocate the memory map");
        }

        let mut pool = shm.create_pool(file.as_raw_fd(), size).unwrap();
        let buffer = pool.create_buffer(0, width, height, width * 4,
                                        ShmFormat::Xrgb8888 as u32).unwrap();
        pool.destroy();
        return Ok(Box::new(MyBuffer {
            buffer: buffer,
            _file: file,
            memory: memory,
            size: size,
            busy: false,
        }));
    }

    fn is_not_busy(&self) -> bool {
        return !self.busy;
    }

    fn set_busy(&mut self) {
        self.busy = true;
    }

    fn get_pointer(&mut self) -> *mut u32 {
        return self.memory as *mut u32;
    }
}

impl BufferEventHandler for MyBuffer {
    fn get_buffer(&mut self) -> &mut Buffer {
        return &mut self.buffer;
    }

    fn on_release(&mut self) {
        self.busy = false;
    }
}

impl Drop for MyBuffer {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(self.memory as *mut libc::c_void,
                         self.size as libc::size_t);
        }
    }
}

struct Window {
    width: i32,
    height: i32,
    surface: Surface,
    frame: Option<Callback>,
    first_buffer: Box<MyBuffer>,
    second_buffer: Box<MyBuffer>,
}

impl Window {
    fn new(mut shm: Shm, mut surface: Surface, width: i32, height: i32) -> Window {
        surface.damage(0, 0, width, height);
        let mut first_buffer = MyBuffer::new(width, height, &mut shm).unwrap();
        first_buffer.connect_dispatcher();
        let mut second_buffer = MyBuffer::new(width, height, &mut shm).unwrap();
        second_buffer.connect_dispatcher();
        return Window {
            width: width,
            height: height,
            surface: surface,
            frame: None,
            first_buffer: first_buffer,
            second_buffer: second_buffer,
        };
    }

    fn paint_pixels(&mut self, use_first_buffer: bool, time: i32) {
        let padding = 20;

        let halfh = padding + (self.height - padding * 2) / 2;
        let halfw = padding + (self.width  - padding * 2) / 2;

        let or = (cmp::min(halfw, halfh) - 8).pow(2);
        let ir = (cmp::min(halfw, halfh) - 40).pow(2);

        let mut pointer = if use_first_buffer { self.first_buffer.get_pointer() }
                          else { self.second_buffer.get_pointer() };

        pointer = unsafe { pointer.offset((padding * self.width) as isize)};

        for y in (20 .. self.height - padding) {
            let y2 = (y - halfh) * (y - halfh);

            pointer = unsafe { pointer.offset(padding as isize)};
            for x in (20 .. self.width - 20) {
                let r2 = (x - halfw) * (x - halfw) + y2;

                let v = Wrapping(if r2 < ir { (r2 / 32 + time / 64) }
                                 else if r2 < or { (y + time / 32) }
                                 else { (x + time / 16) } as u32)
                        * Wrapping(0x0080401);
                let mut v2 = v.0 & 0x00ffffff;

                if (x - y).abs() > 6 && (x + y - self.height).abs() > 6 {
                    v2 |= 0xff000000;
                }

                pointer = unsafe { pointer.offset(1)};
                unsafe { *pointer = v2; }
            }
            pointer = unsafe { pointer.offset(padding as isize)};
        }
    }

    fn redraw(&mut self, time: i32) {
        let use_first_buffer = if self.first_buffer.is_not_busy() { true }
                        else if self.second_buffer.is_not_busy() { false }
                        else { panic!("no buffers free") };

        if use_first_buffer { self.first_buffer.set_busy(); }
        else { self.second_buffer.set_busy(); }

        self.paint_pixels(use_first_buffer, time);

        if use_first_buffer { self.surface.attach(Some(self.first_buffer.get_buffer()), 0, 0); }
        else { self.surface.attach(Some(self.second_buffer.get_buffer()), 0, 0); }

        self.surface.damage(20, 20, self.width - 20, self.height - 20);
        self.frame = Some(self.surface.frame().unwrap());
        self.connect_dispatcher();
        self.surface.commit();
    }
}

impl CallbackEventHandler for Window {
    fn get_callback<'a>(&'a mut self) -> &'a mut Callback {
        return self.frame.as_mut().unwrap();
    }

    fn on_done(&mut self, callback_data: u32) {
        self.frame = None;
        self.redraw(callback_data as i32);
    }
}

fn main() {
    let mut display = Display::connect(None).unwrap();
    let mut registry = MyRegistry::new(&mut display);
    registry.connect_dispatcher();
    display.roundtrip();

    let shm = registry.take_shm();
    let mut shell = registry.take_shell();
    let mut compositor = registry.take_compositor();

    let mut surface = compositor.create_surface().unwrap();
    let mut shell_surface = MyShellSurface::new(&mut shell, &mut surface);
    shell_surface.connect_dispatcher();

    let mut window = Window::new(shm, surface, 250, 250);
    window.redraw(0);

    loop { display.dispatch(); }
}
<|endoftext|>


<commit_before>extern crate vec_arena;

use vec_arena::VecArena;

struct Node<T> {
    parent: usize,
    children: [usize; 2],
    value: T,
}

impl<T> Node<T> {
    fn new(value: T) -> Node<T> {
        Node {
            parent: !0,
            children: [!0, !0],
            value: value,
        }
    }
}

struct Splay<T> {
    arena: VecArena<Node<T>>,
    root: usize,
}

impl<T> Splay<T> where T: Ord + Eq + Clone {
    fn new() -> Splay<T> {
        Splay {
            arena: VecArena::new(),
            root: !0,
        }
    }

    // #[inline(always)]
    fn rotate(&mut self, a: usize, b: usize) {
        let p = self.arena[a].parent;

        let dir = if self.arena[a].children[0] == b { 0 } else { 1 };
        let t = self.arena[b].children[dir ^ 1];

        self.arena[a].children[dir] = t;
        if t != !0 {
            self.arena[t].parent = a;
        }
        self.arena[b].children[dir ^ 1] = a;
        self.arena[a].parent = b;

        if p == !0 {
            self.root = b;
            self.arena[b].parent = !0;
        } else {
            let dir = if self.arena[p].children[0] == a { 0 } else { 1 };
            self.arena[p].children[dir] = b;
            self.arena[b].parent = p;
        }
    }

    fn splay(&mut self, a: usize) {
        loop {
            let b = self.arena[a].parent;
            if b == !0 {
                break;
            }

            let c = self.arena[b].parent;
            if c == !0 {
                self.rotate(b, a);
                break;
            }

            let is_l = self.arena[c].children[0] == b && self.arena[b].children[0] == a;
            let is_r = self.arena[c].children[1] == b && self.arena[b].children[1] == a;

            if is_l || is_r {
                self.rotate(c, b);
                self.rotate(b, a);
            } else {
                self.rotate(b, a);
                self.rotate(c, a);
            }
        }
    }

    fn insert(&mut self, value: T) {
        let node = self.arena.insert(Node::new(value));

        if self.root == !0 {
            self.root = node;
        } else {
            let mut curr = self.root;
            loop {
                let dir = if self.arena[node].value < self.arena[curr].value { 0 } else { 1 };
                let next = self.arena[curr].children[dir];

                if next == !0 {
                    self.arena[curr].children[dir] = node;
                    self.arena[node].parent = curr;
                    self.splay(node);
                    break;
                } else {
                    curr = next;
                }
            }
        }
    }

    fn print(&self, node: usize, depth: usize) where T: std::fmt::Display {
        if node != !0 {
            self.print(self.arena[node].children[0], depth + 1);
            println!("{:width$}{}", "", self.arena[node].value, width = depth * 3);
            self.print(self.arena[node].children[1], depth + 1);
        }
    }
}

fn main() {
    let mut splay = Splay::new();

    let mut num = 1u32;
    for _ in 0..1000000 {
        num = num.wrapping_mul(17).wrapping_add(255);
        splay.insert(num);
    }
    // splay.print(splay.root, 0);
}
<commit_msg>More comments<commit_after>extern crate vec_arena;

use vec_arena::VecArena;

struct Node<T> {
    parent: usize,
    children: [usize; 2],
    value: T,
}

impl<T> Node<T> {
    fn new(value: T) -> Node<T> {
        Node {
            parent: !0,
            children: [!0, !0],
            value: value,
        }
    }
}

struct Splay<T> {
    arena: VecArena<Node<T>>,
    root: usize,
}

impl<T> Splay<T> where T: Ord {
    /// Constructs a new, empty splay tree.
    fn new() -> Splay<T> {
        Splay {
            arena: VecArena::new(),
            root: !0,
        }
    }

    /// Links nodes `p` and `c` as parent and child with the specified direction.
    #[inline(always)]
    fn link(&mut self, p: usize, c: usize, dir: usize) {
        self.arena[p].children[dir] = c;
        if c != !0 {
            self.arena[c].parent = p;
        }
    }

    /// Performs a rotation on node `c`, whose parent is node `p`.
    #[inline(always)]
    fn rotate(&mut self, p: usize, c: usize) {
        // Variables:
        // - `c` is the child node
        // - `p` is it's parent
        // - `g` is it's grandparent

        // Find the grandparent.
        let g = self.arena[p].parent;

        // The direction of p-c relationship.
        let dir = if self.arena[p].children[0] == c { 0 } else { 1 };

        // This is the child of `c` that needs to be reassigned to `p`.
        let t = self.arena[c].children[dir ^ 1];

        self.link(p, t, dir);
        self.link(c, p, dir ^ 1);

        if g == !0 {
            // There is no grandparent, so `c` becomes the root.
            self.root = c;
            self.arena[c].parent = !0;
        } else {
            // Link `g` and `c` together.
            let dir = if self.arena[g].children[0] == p { 0 } else { 1 };
            self.link(g, c, dir);
        }
    }

    /// Splays node
    fn splay(&mut self, c: usize) {
        loop {
            // Variables:
            // - `c` is the current node
            // - `p` is it's parent
            // - `g` is it's grandparent

            // Find the parent.
            let p = self.arena[c].parent;
            if p == !0 {
                // There is no parent. That means `c` is the root.
                break;
            }

            // Find the grandparent.
            let g = self.arena[p].parent;
            if g == !0 {
                // There is no grandparent. Just one rotation is left.
                // Zig step.
                self.rotate(p, c);
                break;
            }

            if (self.arena[g].children[0] == p) == (self.arena[p].children[0] == c) {
                // Zig-zig step.
                self.rotate(g, p);
                self.rotate(p, c);
            } else {
                // Zig-zag step.
                self.rotate(p, c);
                self.rotate(g, c);
            }
        }
    }

    /// Inserts a new node with specified `value`.
    fn insert(&mut self, value: T) {
        // Variables:
        // - `n` is the new node
        // - `p` will be it's parent
        // - `c` is the present child of `p`

        let n = self.arena.insert(Node::new(value));

        if self.root == !0 {
            self.root = n;
        } else {
            let mut p = self.root;
            loop {
                // Decide whether to go left or right.
                let dir = if self.arena[n].value < self.arena[p].value { 0 } else { 1 };
                let c = self.arena[p].children[dir];

                if c == !0 {
                    self.link(p, n, dir);
                    self.splay(n);
                    break;
                }
                p = c;
            }
        }
    }

    /// Pretty-prints the subtree rooted at `node`, indented by `depth` spaces.
    fn print(&self, node: usize, depth: usize) where T: std::fmt::Display {
        if node != !0 {
            // Print the left subtree.
            self.print(self.arena[node].children[0], depth + 1);

            // Print the current node.
            println!("{:width$}{}", "", self.arena[node].value, width = depth * 3);

            // Print the right subtree.
            self.print(self.arena[node].children[1], depth + 1);
        }
    }
}

fn main() {
    let mut splay = Splay::new();

    // Insert a bunch of pseudorandom numbers.
    let mut num = 1u32;
    for _ in 0..30 {
        num = num.wrapping_mul(17).wrapping_add(255);
        splay.insert(num);
    }

    // Display the whole splay tree.
    splay.print(splay.root, 0);
}
<|endoftext|>