<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/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSAutoCompartment, JSContext, JSObject};
use js::jsapi::JS_GetArrayBufferViewBuffer;
use js::rust::CustomAutoRooterGuard;
use js::rust::wrappers::JS_DetachArrayBuffer;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

// This range is defined by the spec.
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
pub const MIN_SAMPLE_RATE: f32 = 8000.;
pub const MAX_SAMPLE_RATE: f32 = 96000.;

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(number_of_channels: u32, length: u32, sample_rate: f32) -> AudioBuffer {
        let vec = (0..number_of_channels).map(|_| Heap::default()).collect();
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(vec),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[Vec<f32>]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(number_of_channels, length, sample_rate);
        let buffer = reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap);
        buffer.set_channels(initial_data);
        buffer
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.length <= 0 ||
            options.numberOfChannels <= 0 ||
            options.numberOfChannels > MAX_CHANNEL_COUNT ||
            *options.sampleRate < MIN_SAMPLE_RATE ||
            *options.sampleRate > MAX_SAMPLE_RATE
        {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    // Initialize the underlying channels data with initial data provided by
    // the user or silence otherwise.
    #[allow(unsafe_code)]
    pub fn set_channels(&self, initial_data: Option<&[Vec<f32>]>) {
        for channel in 0..self.number_of_channels {
            (*self.shared_channels.borrow_mut()).buffers[channel as usize] = match initial_data {
                Some(data) => data[channel as usize].clone(),
                None => vec![0.; self.length as usize],
            };
        }
    }

    pub fn get_channels(&self) -> ServoMediaAudioBuffer {
        self.shared_channels.borrow().clone()
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        let global = self.global();
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                // We may have called GetChannelData, and web content may have modified
                // js_channels. So make sure that shared_channels contains the same data as
                // js_channels.
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    (*self.shared_channels.borrow_mut()).buffers[i] = array.to_vec();
                }
                continue;
            }

            // Copy the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            if Float32Array::create(cx, CreateWith::Slice(&(*self.shared_channels.borrow_mut()).buffers[i]), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let mut is_shared = false;
                    rooted!(in (cx) let view_buffer =
                        JS_GetArrayBufferViewBuffer(cx, channel.handle(), &mut is_shared));
                    // This buffer is always created unshared
                    debug_assert!(!is_shared);
                    let _ = JS_DetachArrayBuffer(cx, view_buffer.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if destination.is_shared() {
            return Err(Error::Type("Cannot copy to shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel >= self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());

        // We either copy form js_channels or shared_channels.
        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
            }
        } else if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if source.is_shared() {
            return Err(Error::Type("Cannot copy from shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let js_channel: Float32Array = js_channel);
        if let Ok(mut js_channel) = js_channel {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            unsafe {
                let data = &source.as_slice()[0..bytes_to_copy];
                // Update shared channel.
                {
                    let mut shared_channels = self.shared_channels.borrow_mut();
                    let shared_channel = shared_channels.data_chan_mut(channel_number as u8);
                    let (_, mut shared_channel) = shared_channel.split_at_mut(start_in_channel as usize);
                    shared_channel[0..bytes_to_copy].copy_from_slice(data);
                }
                // Update js channel.
                js_channel.update(self.shared_channels.borrow().buffers[channel_number as usize].as_slice());
            }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<commit_msg>Rustfmt audiobuffer.rs<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/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSAutoCompartment, JSContext, JSObject};
use js::jsapi::JS_GetArrayBufferViewBuffer;
use js::rust::CustomAutoRooterGuard;
use js::rust::wrappers::JS_DetachArrayBuffer;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

// This range is defined by the spec.
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
pub const MIN_SAMPLE_RATE: f32 = 8000.;
pub const MAX_SAMPLE_RATE: f32 = 96000.;

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(number_of_channels: u32, length: u32, sample_rate: f32) -> AudioBuffer {
        let vec = (0..number_of_channels).map(|_| Heap::default()).collect();
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(vec),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[Vec<f32>]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(number_of_channels, length, sample_rate);
        let buffer = reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap);
        buffer.set_channels(initial_data);
        buffer
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.length <= 0 ||
            options.numberOfChannels <= 0 ||
            options.numberOfChannels > MAX_CHANNEL_COUNT ||
            *options.sampleRate < MIN_SAMPLE_RATE ||
            *options.sampleRate > MAX_SAMPLE_RATE
        {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    // Initialize the underlying channels data with initial data provided by
    // the user or silence otherwise.
    #[allow(unsafe_code)]
    pub fn set_channels(&self, initial_data: Option<&[Vec<f32>]>) {
        for channel in 0..self.number_of_channels {
            (*self.shared_channels.borrow_mut()).buffers[channel as usize] = match initial_data {
                Some(data) => data[channel as usize].clone(),
                None => vec![0.; self.length as usize],
            };
        }
    }

    pub fn get_channels(&self) -> ServoMediaAudioBuffer {
        self.shared_channels.borrow().clone()
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        let global = self.global();
        let _ac = JSAutoCompartment::new(cx, global.reflector().get_jsobject().get());
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                // We may have called GetChannelData, and web content may have modified
                // js_channels. So make sure that shared_channels contains the same data as
                // js_channels.
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    (*self.shared_channels.borrow_mut()).buffers[i] = array.to_vec();
                }
                continue;
            }

            // Copy the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            if Float32Array::create(
                cx,
                CreateWith::Slice(&(*self.shared_channels.borrow_mut()).buffers[i]),
                array.handle_mut(),
            ).is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let mut is_shared = false;
                    rooted!(in (cx) let view_buffer =
                        JS_GetArrayBufferViewBuffer(cx, channel.handle(), &mut is_shared));
                    // This buffer is always created unshared
                    debug_assert!(!is_shared);
                    let _ = JS_DetachArrayBuffer(cx, view_buffer.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if destination.is_shared() {
            return Err(Error::Type("Cannot copy to shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel >= self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());

        // We either copy form js_channels or shared_channels.
        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
            }
        } else if let Some(shared_channel) =
            self.shared_channels.borrow().buffers.get(channel_number)
        {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if source.is_shared() {
            return Err(Error::Type("Cannot copy from shared buffer".to_owned()));
        }

        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let js_channel: Float32Array = js_channel);
        if let Ok(mut js_channel) = js_channel {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            unsafe {
                let data = &source.as_slice()[0..bytes_to_copy];
                // Update shared channel.
                {
                    let mut shared_channels = self.shared_channels.borrow_mut();
                    let shared_channel = shared_channels.data_chan_mut(channel_number as u8);
                    let (_, mut shared_channel) =
                        shared_channel.split_at_mut(start_in_channel as usize);
                    shared_channel[0..bytes_to_copy].copy_from_slice(data);
                }
                // Update js channel.
                js_channel.update(
                    self.shared_channels.borrow().buffers[channel_number as usize].as_slice(),
                );
            }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>#![crate_name = "tty"]
#![feature(collections, core, old_io, rustc_private, std_misc)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * Synced with http://lingrok.org/xref/coreutils/src/tty.c
 */

#![allow(dead_code)]

extern crate getopts;
extern crate libc;

use std::ffi::CStr;
use std::old_io::println;
use std::old_io::stdio::stderr;
use getopts::{optflag,getopts};

#[path = "../common/util.rs"]
#[macro_use]
mod util;

extern {
    fn ttyname(filedesc: libc::c_int) -> *const libc::c_char;
    fn isatty(filedesc: libc::c_int) -> libc::c_int;
}

static NAME: &'static str = "tty";

pub fn uumain(args: Vec<String>) -> i32 {
    let options = [
        optflag("s", "silent", "print nothing, only return an exit status")
    ];

    let silent = match getopts(args.tail(), &options) {
        Ok(m) => {
            m.opt_present("s")
        },
        Err(f) => {
            println!("{}", f);
            usage();
            return 2;
        }
    };

    let tty = unsafe {
        let ptr = ttyname(libc::STDIN_FILENO);
        if !ptr.is_null() {
            String::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).to_string()
        } else {
            "".to_string()
        }
    };

    if !silent {
        if !tty.as_slice().chars().all(|c| c.is_whitespace()) {
            println(tty.as_slice());
        } else {
            println!("not a tty");
        }
    }

    let exit_code = unsafe {
        if isatty(libc::STDIN_FILENO) == 1 {
            libc::EXIT_SUCCESS
        } else {
            libc::EXIT_FAILURE
        }
    };

    exit_code
}

fn usage () {
    safe_writeln!(&mut stderr(), "usage: tty [-s]");
}
<commit_msg>Fix tty.<commit_after>#![crate_name = "tty"]
#![feature(rustc_private)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * Synced with http://lingrok.org/xref/coreutils/src/tty.c
 */

extern crate getopts;
extern crate libc;

use std::ffi::CStr;
use getopts::{optflag,getopts};

#[path = "../common/util.rs"]
#[macro_use]
mod util;

extern {
    fn ttyname(filedesc: libc::c_int) -> *const libc::c_char;
    fn isatty(filedesc: libc::c_int) -> libc::c_int;
}

static NAME: &'static str = "tty";

pub fn uumain(args: Vec<String>) -> i32 {
    let options = [
        optflag("s", "silent", "print nothing, only return an exit status")
    ];

    let silent = match getopts(&args[1..], &options) {
        Ok(m) => {
            m.opt_present("s")
        },
        Err(f) => {
            println!("{}", f);
            usage();
            return 2;
        }
    };

    let tty = unsafe {
        let ptr = ttyname(libc::STDIN_FILENO);
        if !ptr.is_null() {
            String::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).to_string()
        } else {
            "".to_string()
        }
    };

    if !silent {
        if !tty.chars().all(|c| c.is_whitespace()) {
            println!("{}", tty);
        } else {
            println!("not a tty");
        }
    }

    let exit_code = unsafe {
        if isatty(libc::STDIN_FILENO) == 1 {
            libc::EXIT_SUCCESS
        } else {
            libc::EXIT_FAILURE
        }
    };

    exit_code
}

fn usage() {
    println!("usage: {} [-s]", NAME);
}
<|endoftext|>


<commit_before>//#![feature(trace_macros)]
#![feature(test)]
extern crate test;
#[macro_use]
extern crate cookie_factory;

use std::str;
use std::iter::repeat;
use std::collections::HashMap;

use cookie_factory::*;
use test::Bencher;

#[derive(Clone, Debug, PartialEq)]
pub enum JsonValue {
  Str(String),
  Boolean(bool),
  Num(f64),
  Array(Vec<JsonValue>),
  Object(HashMap<String, JsonValue>),
}

pub fn gen_json_value<'a>(x:(&'a mut [u8],usize), g:&JsonValue) -> Result<(&'a mut [u8],usize),GenError> {
  match g {
    JsonValue::Str(ref s) => gen_str(x, s),
    JsonValue::Boolean(b) => gen_bool(x, b),
    JsonValue::Num(ref f) => gen_num(x, f),
    JsonValue::Array(ref v) => gen_array(x, v),
    JsonValue::Object(ref o) => gen_object(x, o),
  }
}

pub fn gen_str<'a>(x:(&'a mut [u8],usize), s:&String) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(x,
    gen_slice!(&b"\""[..]) >>
    gen_slice!(s.as_bytes()) >>
    gen_slice!(&b"\""[..])
  )
}

pub fn gen_bool<'a>(x:(&'a mut [u8],usize), b:&bool) -> Result<(&'a mut [u8],usize),GenError> {
  let sl = match b {
    true => &b"true"[..],
    false => &b"false"[..],
  };

  gen_slice!(x, sl)
}

pub fn gen_num<'a>(x:(&'a mut [u8],usize), b:&f64) -> Result<(&'a mut [u8],usize),GenError> {
  //TODO
  gen_slice!(x, &b"1234.56"[..])
}

pub fn gen_array<'a>(x:(&'a mut [u8],usize), arr:&[JsonValue]) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = gen_slice!(x, &b"["[..])?;
  if arr.len() > 0 {
    output = gen_json_value(output, &arr[0])?;

    if arr.len() > 1 {
      output = gen_many!((output.0, output.1),
        &arr[1..],
        gen_array_element
      )?;
    }
  }
  gen_slice!(output, &b"]"[..])
}

pub fn gen_array_element<'a>(x:(&'a mut [u8],usize), val: &JsonValue) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(x,
    gen_slice!(&b","[..]) >>
    gen_call!(gen_json_value, val)
  )
}

pub fn gen_object<'a>(x:(&'a mut [u8],usize), o:&HashMap<String, JsonValue>) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = gen_slice!(x, &b"{"[..])?;
  let mut it = o.iter();

  if let Some((key, value)) = it.next() {
    output = gen_object_element(output, key, value, true)?;
  }

  for (key, value) in it {
    output = gen_object_element(output, key, value, false)?;
  }

  gen_slice!(output, &b"]"[..])
}

pub fn gen_object_element<'a>(x:(&'a mut [u8],usize), key: &String, value:&JsonValue, is_first: bool) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = x;
  if !is_first {
    output = gen_slice!(output, &b","[..])?;
  }

  do_gen!(output,
    gen_call!(gen_str, key) >>
    gen_slice!(&b":"[..]) >>
    gen_call!(gen_json_value, value)
  )
}
/*
named!(float<f32>, flat_map!(recognize_float, parse_to!(f32)));

//FIXME: verify how json strings are formatted
named!(
  string<&str>,
  delimited!(
    char!('\"'),
    map_res!(
      escaped!(call!(alphanumeric), '\\', one_of!("\"n\\")),
      str::from_utf8
    ),
    //map_res!(escaped!(take_while1!(is_alphanumeric), '\\', one_of!("\"n\\")), str::from_utf8),
    char!('\"')
  )
);

named!(
  boolean<bool>,
  alt!(value!(false, tag!("false")) | value!(true, tag!("true")))
);

named!(
  array<Vec<JsonValue>>,
  ws!(delimited!(
    char!('['),
    separated_list!(char!(','), value),
    char!(']')
  ))
);

named!(
  key_value<(&str, JsonValue)>,
  ws!(separated_pair!(string, char!(':'), value))
);

named!(
  hash<HashMap<String, JsonValue>>,
  ws!(map!(
    delimited!(
      char!('{'),
      separated_list!(char!(','), key_value),
      char!('}')
    ),
    |tuple_vec| tuple_vec
      .into_iter()
      .map(|(k, v)| (String::from(k), v))
      .collect()
  ))
);

named!(
  value<JsonValue>,
  ws!(alt!(
      hash    => { |h| JsonValue::Object(h)            } |
      array   => { |v| JsonValue::Array(v)             } |
      string  => { |s| JsonValue::Str(String::from(s)) } |
      float   => { |f| JsonValue::Num(f)               } |
      boolean => { |b| JsonValue::Boolean(b)           }
    ))
);
*/

// from https://github.com/bluss/maplit
macro_rules! hashmap {
    (@single $($x:tt)*) => (());
    (@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));

    ($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let _cap = hashmap!(@count $($key),*);
            let mut _map = ::std::collections::HashMap::with_capacity(_cap);
            $(
                let _ = _map.insert($key, $value);
            )*
            _map
        }
    };
}

#[bench]
fn json_bench(b: &mut Bencher) {
  let element = JsonValue::Object(hashmap!{
    String::from("arr") => JsonValue::Array(vec![JsonValue::Num(1.0), JsonValue::Num(12.3), JsonValue::Num(42.0)]),
    String::from("b") => JsonValue::Boolean(true),
    String::from("o") => JsonValue::Object(hashmap!{
      String::from("x") => JsonValue::Str(String::from("abcd")),
      String::from("y") => JsonValue::Str(String::from("efgh")),
      String::from("empty") => JsonValue::Array(vec![]),
    }),
  });

  let value = JsonValue::Array(repeat(element).take(10).collect::<Vec<JsonValue>>());

  let mut buffer = repeat(0).take(16384).collect::<Vec<u8>>();
  let index = {
    let (buf, index) = gen_json_value((&mut buffer, 0), &value).unwrap();

    println!("result:\n{}", str::from_utf8(buf).unwrap());
    //panic!();

    index as u64
  };

  println!("wrote {} bytes", index);
  b.bytes = index;
  b.iter(|| {
    let res = gen_json_value((&mut buffer, 0), &value).unwrap();
    res.1
  });
}

<commit_msg>add a bench for json string generation<commit_after>//#![feature(trace_macros)]
#![feature(test)]
extern crate test;
#[macro_use]
extern crate cookie_factory;

use std::str;
use std::iter::repeat;
use std::collections::HashMap;

use cookie_factory::*;
use test::Bencher;

#[derive(Clone, Debug, PartialEq)]
pub enum JsonValue {
  Str(String),
  Boolean(bool),
  Num(f64),
  Array(Vec<JsonValue>),
  Object(HashMap<String, JsonValue>),
}

pub fn gen_json_value<'a>(x:(&'a mut [u8],usize), g:&JsonValue) -> Result<(&'a mut [u8],usize),GenError> {
  match g {
    JsonValue::Str(ref s) => gen_str(x, s),
    JsonValue::Boolean(b) => gen_bool(x, b),
    JsonValue::Num(ref f) => gen_num(x, f),
    JsonValue::Array(ref v) => gen_array(x, v),
    JsonValue::Object(ref o) => gen_object(x, o),
  }
}

pub fn gen_str<'a>(x:(&'a mut [u8],usize), s:&String) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(x,
    gen_slice!(&b"\""[..]) >>
    gen_slice!(s.as_bytes()) >>
    gen_slice!(&b"\""[..])
  )
}

pub fn gen_bool<'a>(x:(&'a mut [u8],usize), b:&bool) -> Result<(&'a mut [u8],usize),GenError> {
  let sl = match b {
    true => &b"true"[..],
    false => &b"false"[..],
  };

  gen_slice!(x, sl)
}

pub fn gen_num<'a>(x:(&'a mut [u8],usize), b:&f64) -> Result<(&'a mut [u8],usize),GenError> {
  //TODO
  gen_slice!(x, &b"1234.56"[..])
}

pub fn gen_array<'a>(x:(&'a mut [u8],usize), arr:&[JsonValue]) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = gen_slice!(x, &b"["[..])?;
  if arr.len() > 0 {
    output = gen_json_value(output, &arr[0])?;

    if arr.len() > 1 {
      output = gen_many!((output.0, output.1),
        &arr[1..],
        gen_array_element
      )?;
    }
  }
  gen_slice!(output, &b"]"[..])
}

pub fn gen_array_element<'a>(x:(&'a mut [u8],usize), val: &JsonValue) -> Result<(&'a mut [u8],usize),GenError> {
  do_gen!(x,
    gen_slice!(&b","[..]) >>
    gen_call!(gen_json_value, val)
  )
}

pub fn gen_object<'a>(x:(&'a mut [u8],usize), o:&HashMap<String, JsonValue>) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = gen_slice!(x, &b"{"[..])?;
  let mut it = o.iter();

  if let Some((key, value)) = it.next() {
    output = gen_object_element(output, key, value, true)?;
  }

  for (key, value) in it {
    output = gen_object_element(output, key, value, false)?;
  }

  gen_slice!(output, &b"]"[..])
}

pub fn gen_object_element<'a>(x:(&'a mut [u8],usize), key: &String, value:&JsonValue, is_first: bool) -> Result<(&'a mut [u8],usize),GenError> {
  let mut output = x;
  if !is_first {
    output = gen_slice!(output, &b","[..])?;
  }

  do_gen!(output,
    gen_call!(gen_str, key) >>
    gen_slice!(&b":"[..]) >>
    gen_call!(gen_json_value, value)
  )
}
/*
named!(float<f32>, flat_map!(recognize_float, parse_to!(f32)));

//FIXME: verify how json strings are formatted
named!(
  string<&str>,
  delimited!(
    char!('\"'),
    map_res!(
      escaped!(call!(alphanumeric), '\\', one_of!("\"n\\")),
      str::from_utf8
    ),
    //map_res!(escaped!(take_while1!(is_alphanumeric), '\\', one_of!("\"n\\")), str::from_utf8),
    char!('\"')
  )
);

named!(
  boolean<bool>,
  alt!(value!(false, tag!("false")) | value!(true, tag!("true")))
);

named!(
  array<Vec<JsonValue>>,
  ws!(delimited!(
    char!('['),
    separated_list!(char!(','), value),
    char!(']')
  ))
);

named!(
  key_value<(&str, JsonValue)>,
  ws!(separated_pair!(string, char!(':'), value))
);

named!(
  hash<HashMap<String, JsonValue>>,
  ws!(map!(
    delimited!(
      char!('{'),
      separated_list!(char!(','), key_value),
      char!('}')
    ),
    |tuple_vec| tuple_vec
      .into_iter()
      .map(|(k, v)| (String::from(k), v))
      .collect()
  ))
);

named!(
  value<JsonValue>,
  ws!(alt!(
      hash    => { |h| JsonValue::Object(h)            } |
      array   => { |v| JsonValue::Array(v)             } |
      string  => { |s| JsonValue::Str(String::from(s)) } |
      float   => { |f| JsonValue::Num(f)               } |
      boolean => { |b| JsonValue::Boolean(b)           }
    ))
);
*/

// from https://github.com/bluss/maplit
macro_rules! hashmap {
    (@single $($x:tt)*) => (());
    (@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));

    ($($key:expr => $value:expr,)+) => { hashmap!($($key => $value),+) };
    ($($key:expr => $value:expr),*) => {
        {
            let _cap = hashmap!(@count $($key),*);
            let mut _map = ::std::collections::HashMap::with_capacity(_cap);
            $(
                let _ = _map.insert($key, $value);
            )*
            _map
        }
    };
}

#[bench]
fn json_bench(b: &mut Bencher) {
  let element = JsonValue::Object(hashmap!{
    String::from("arr") => JsonValue::Array(vec![JsonValue::Num(1.0), JsonValue::Num(12.3), JsonValue::Num(42.0)]),
    String::from("b") => JsonValue::Boolean(true),
    String::from("o") => JsonValue::Object(hashmap!{
      String::from("x") => JsonValue::Str(String::from("abcd")),
      String::from("y") => JsonValue::Str(String::from("efgh")),
      String::from("empty") => JsonValue::Array(vec![]),
    }),
  });

  let value = JsonValue::Array(repeat(element).take(10).collect::<Vec<JsonValue>>());

  let mut buffer = repeat(0).take(16384).collect::<Vec<u8>>();
  let index = {
    let (buf, index) = gen_json_value((&mut buffer, 0), &value).unwrap();

    println!("result:\n{}", str::from_utf8(buf).unwrap());
    //panic!();

    index as u64
  };

  println!("wrote {} bytes", index);
  b.bytes = index;
  b.iter(|| {
    let res = gen_json_value((&mut buffer, 0), &value).unwrap();
    res.1
  });
}

#[bench]
fn gen_str_bench(b: &mut Bencher) {

  let value = String::from("hello");
  let mut buffer = repeat(0).take(16384).collect::<Vec<u8>>();
  let index = {
    let (buf, index) = gen_str((&mut buffer, 0), &value).unwrap();

    println!("result:\n{}", str::from_utf8(buf).unwrap());
    //panic!();

    index as u64
  };

  println!("wrote {} bytes", index);
  b.bytes = index;
  b.iter(|| {
    let res = gen_str((&mut buffer, 0), &value).unwrap();
    res.1
  });
}

<|endoftext|>


<commit_before>extern crate actix;
extern crate actix_web;
extern crate futures;
extern crate http;
extern crate bytes;

use bytes::Bytes;
use futures::Stream;

use actix_web::*;
use actix::prelude::*;

struct Ws;

impl Actor for Ws {
    type Context = ws::WebsocketContext<Self>;
}

impl Handler<ws::Message> for Ws {
    type Result = ();

    fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
        match msg {
            ws::Message::Ping(msg) => ctx.pong(&msg),
            ws::Message::Text(text) => ctx.text(&text),
            ws::Message::Binary(bin) => ctx.binary(bin),
            _ => (),
        }
    }
}

#[test]
fn test_simple() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|req| ws::start(req, Ws)));
    let (reader, mut writer) = srv.ws().unwrap();

    writer.text("text");
    let (item, reader) = srv.execute(reader.into_future()).unwrap();
    assert_eq!(item, Some(ws::Message::Text("text".to_owned())));

    writer.binary(b"text".as_ref());
    let (item, reader) = srv.execute(reader.into_future()).unwrap();
    assert_eq!(item, Some(ws::Message::Binary(Bytes::from_static(b"text").into())));

    writer.ping("ping");
    let (item, _) = srv.execute(reader.into_future()).unwrap();
    assert_eq!(item, Some(ws::Message::Pong("ping".to_owned())));
}
<commit_msg>add close ws test<commit_after>extern crate actix;
extern crate actix_web;
extern crate futures;
extern crate http;
extern crate bytes;

use bytes::Bytes;
use futures::Stream;

use actix_web::*;
use actix::prelude::*;

struct Ws;

impl Actor for Ws {
    type Context = ws::WebsocketContext<Self>;
}

impl Handler<ws::Message> for Ws {
    type Result = ();

    fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
        match msg {
            ws::Message::Ping(msg) => ctx.pong(&msg),
            ws::Message::Text(text) => ctx.text(&text),
            ws::Message::Binary(bin) => ctx.binary(bin),
            _ => (),
        }
    }
}

#[test]
fn test_simple() {
    let mut srv = test::TestServer::new(
        |app| app.handler(|req| ws::start(req, Ws)));
    let (reader, mut writer) = srv.ws().unwrap();

    writer.text("text");
    let (item, reader) = srv.execute(reader.into_future()).unwrap();
    assert_eq!(item, Some(ws::Message::Text("text".to_owned())));

    writer.binary(b"text".as_ref());
    let (item, reader) = srv.execute(reader.into_future()).unwrap();
    assert_eq!(item, Some(ws::Message::Binary(Bytes::from_static(b"text").into())));

    writer.ping("ping");
    let (item, reader) = srv.execute(reader.into_future()).unwrap();
    assert_eq!(item, Some(ws::Message::Pong("ping".to_owned())));

    writer.close(ws::CloseCode::Normal, "");
    let (item, _) = srv.execute(reader.into_future()).unwrap();
    assert!(item.is_none())
}
<|endoftext|>


<commit_before>use libc::{c_int, c_char, c_uint, size_t, ptrdiff_t};

use tree::{ParseStatus, Encoding, NodeKind};

use tree::node::CNode;
use tree::document::CDocument;
use tree::parse_result::CParseResult;

extern "C" {
    pub fn pugi_version() -> c_int;

    pub fn pugi_parse_flag_cdata() -> c_uint;
    pub fn pugi_parse_flag_comments() -> c_uint;
    pub fn pugi_parse_flag_declaration() -> c_uint;
    pub fn pugi_parse_flag_default() -> c_uint;
    pub fn pugi_parse_flag_doctype() -> c_uint;
    pub fn pugi_parse_flag_eol() -> c_uint;
    pub fn pugi_parse_flag_escapes() -> c_uint;
    pub fn pugi_parse_flag_fragment() -> c_uint;
    pub fn pugi_parse_flag_full() -> c_uint;
    pub fn pugi_parse_flag_minimal() -> c_uint;
    pub fn pugi_parse_flag_pi() -> c_uint;
    pub fn pugi_parse_flag_trim_pcdata() -> c_uint;
    pub fn pugi_parse_flag_ws_pcdata() -> c_uint;
    pub fn pugi_parse_flag_ws_pcdata_single() -> c_uint;
    pub fn pugi_parse_flag_wconv_attribute() -> c_uint;
    pub fn pugi_parse_flag_wnorm_attribute() -> c_uint;

    pub fn pugi_format_flag_default() -> c_uint;
    pub fn pugi_format_flag_indent() -> c_uint;
    pub fn pugi_format_flag_indent_attributes() -> c_uint;
    pub fn pugi_format_flag_no_empty_element_tags() -> c_uint;
    pub fn pugi_format_flag_no_declaration() -> c_uint;
    pub fn pugi_format_flag_no_escapes() -> c_uint;
    pub fn pugi_format_flag_raw() -> c_uint;
    pub fn pugi_format_flag_save_file_text() -> c_uint;
    pub fn pugi_format_flag_write_bom() -> c_uint;

    pub fn pugi_parse_result_status(parse_result: *const CParseResult) -> ParseStatus;
    pub fn pugi_parse_result_offset(parse_result: *const CParseResult) -> ptrdiff_t;
    pub fn pugi_parse_result_encoding(parse_result: *const CParseResult) -> Encoding;
    pub fn pugi_parse_result_description(parse_result: *const CParseResult) -> *const c_char;

    pub fn pugi_delete_parse_result(parse_result: *const CParseResult);

    pub fn pugi_new_document() -> *mut CDocument;
    pub fn pugi_delete_document(document: *mut CDocument);

    pub fn pugi_reset_document_with(document: *mut CDocument, proto: *mut CDocument);

    pub fn pugi_load_file(document: *mut CDocument, path: *const c_char, options: c_uint,
                      encoding: Encoding)
        -> *const CParseResult;

    pub fn pugi_load_buffer(document: *mut CDocument, contents: *const c_char, size: size_t,
                        options: c_uint, encoding: Encoding)
        -> *const CParseResult;

    pub fn pugi_save_file(document: *mut CDocument, path: *const c_char, indent: *const c_char,
                      options: c_uint, encoding: Encoding)
        -> c_int;

    pub fn pugi_delete_node(node: *mut CNode);

    pub fn pugi_node_equal(lhs: *mut CNode, rhs: *mut CNode) -> c_int;

    pub fn pugi_node_hash_value(node: *mut CNode) -> size_t;
    pub fn pugi_node_type(node: *const CNode) -> NodeKind;

    pub fn pugi_node_name(node: *mut CNode) -> *const c_char;
    pub fn pugi_node_value(node: *mut CNode) -> *const c_char;

    pub fn pugi_node_parent(node: *mut CNode) -> *mut CNode;
    pub fn pugi_node_child(node: *mut CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_first_child(node: *mut CNode) -> *mut CNode;
    pub fn pugi_node_last_child(node: *mut CNode) -> *mut CNode;
    pub fn pugi_node_next_sibling(node: *mut CNode) -> *mut CNode;
    pub fn pugi_node_previous_sibling(node: *mut CNode) -> *mut CNode;
    pub fn pugi_node_next_sibling_by_name(node: *mut CNode, name: *const c_char) -> *mut CNode;
    pub fn pugi_node_previous_sibling_by_name(node: *mut CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_find_child_by_name_and_attribute(node: *mut CNode, name: *const c_char,
                                                  attribute_name: *const c_char,
                                                  attribute_value: *const c_char)
        -> *mut CNode;
    pub fn pugi_node_find_child_by_attribute(node: *mut CNode, attribute_name: *const c_char,
                                         attribute_value: *const c_char)
        -> *mut CNode;

    pub fn pugi_node_child_value(node: *mut CNode) -> *const c_char;
    pub fn pugi_node_child_value_by_name(node: *mut CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_text(node: *mut CNode) -> *const c_char;

    // pub fn pugi_node_attribute(node: *mut CNode, name: *const c_char) -> *mut CAttribute;

    pub fn pugi_node_path(node: *mut CNode) -> *const c_char;

    pub fn pugi_node_first_element_by_path(node: *mut CNode, path: *const c_char, del: c_char)
        -> *mut CNode;

    pub fn pugi_node_root(node: *mut CNode) -> *mut CNode;

    pub fn pugi_node_set_name(node: *mut CNode, name: *const c_char) -> c_int;
    pub fn pugi_node_set_value(node: *mut CNode, name: *const c_char) -> c_int;

    pub fn pugi_node_append_attribute(node: *mut CNode, name: *const c_char, value: *const c_char)
        -> c_int;
    pub fn pugi_node_prepend_attribute(node: *mut CNode, name: *const c_char, value: *const c_char)
        -> c_int;

    pub fn pugi_node_append_child(node: *mut CNode, node_type: NodeKind) -> *mut CNode;
    pub fn pugi_node_prepend_child(node: *mut CNode, node_type: NodeKind) -> *mut CNode;

    pub fn pugi_node_append_copy(node: *mut CNode, proto: *mut CNode) -> *mut CNode;
    pub fn pugi_node_prepend_copy(node: *mut CNode, proto: *mut CNode) -> *mut CNode;

    pub fn pugi_node_remove_attribute(node: *mut CNode, name: *const c_char) -> c_int;
    pub fn pugi_node_remove_child(node: *mut CNode, to_be_removed_child: *mut CNode) -> c_int;

    // pub fn pugi_node_print(node: *mut CNode,

    // pub fn pugi_node_find_attribute_by_predicate
    // pub fn pugi_node_find_child_by_predicate
    // pub fn pugi_node_find_node_by_predicate

    // pub fn pugi_node_map_sibling
    // pub fn pugi_node_map_attributes

    // pub fn pugi_xpath_delete_xpath_node(node: *mut CXPathNode);

    // pub fn pugi_xpath_node_node(node: *mut CXPathNode) -> *mut CNode;
    // pub fn pugi_xpath_node_attribute(node: *mut CXPathNode) -> *mut CAttribute;

    // pub fn pugi_xpath_delete_xpath_node_set(node_set: *const CNodeSet);

    // pub fn pugi_xpath_node_set_size(node_set: *const CNodeSet) -> size_t;
    // pub fn pugi_xpath_node_set_is_empty(node_set: *const CNodeSet) -> c_int;

    // pub fn pugi_xpath_node_set_index(node_set: *mut CNodeSet, index: size_t) -> *mut CXPathNode;

    // pub fn pugi_xpath_node_set_map

    // pub fn pugi_xpath_delete_xpath_query(xpath: *const CXPath);

    // pub fn pugi_xpath_query_evaluate_boolean(xpath: *const CXPath, node: *mut CNode) -> c_int;
    // pub fn pugi_xpath_query_evaluate_number(xpath: *const CXPath, node: *mut CNode) -> c_double;
    // pub fn pugi_xpath_query_evaluate_string(xpath: *const CXPath, node: *mut CNode) -> *const c_char;
    // pub fn pugi_xpath_query_evaluate_node_set(xpath: *const CXPath, node: *mut CNode)
    //     -> *const CNodeSet;

    // pub fn pugi_xpath_query_return_type(xpath: *const CXPath) -> XPathValueType;

    // pub fn pugi_xpath_query_parse_is_success(xpath: *const CXPath) -> c_int;

    // pub fn pugi_xpath_select_single_node(node: *mut CNode, xpath: *const CXPath) -> *mut CXPathNode;
    // pub fn pugi_xpath_select_nodes(node: *mut CNode, xpath: *const CXPath) -> *const CNodeSet;
}
<commit_msg>Fixing wrapper mutability on some functions<commit_after>use libc::{c_int, c_char, c_uint, size_t, ptrdiff_t};

use tree::{ParseStatus, Encoding, NodeKind};

use tree::node::CNode;
use tree::document::CDocument;
use tree::parse_result::CParseResult;

extern "C" {
    pub fn pugi_version() -> c_int;

    pub fn pugi_parse_flag_cdata() -> c_uint;
    pub fn pugi_parse_flag_comments() -> c_uint;
    pub fn pugi_parse_flag_declaration() -> c_uint;
    pub fn pugi_parse_flag_default() -> c_uint;
    pub fn pugi_parse_flag_doctype() -> c_uint;
    pub fn pugi_parse_flag_eol() -> c_uint;
    pub fn pugi_parse_flag_escapes() -> c_uint;
    pub fn pugi_parse_flag_fragment() -> c_uint;
    pub fn pugi_parse_flag_full() -> c_uint;
    pub fn pugi_parse_flag_minimal() -> c_uint;
    pub fn pugi_parse_flag_pi() -> c_uint;
    pub fn pugi_parse_flag_trim_pcdata() -> c_uint;
    pub fn pugi_parse_flag_ws_pcdata() -> c_uint;
    pub fn pugi_parse_flag_ws_pcdata_single() -> c_uint;
    pub fn pugi_parse_flag_wconv_attribute() -> c_uint;
    pub fn pugi_parse_flag_wnorm_attribute() -> c_uint;

    pub fn pugi_format_flag_default() -> c_uint;
    pub fn pugi_format_flag_indent() -> c_uint;
    pub fn pugi_format_flag_indent_attributes() -> c_uint;
    pub fn pugi_format_flag_no_empty_element_tags() -> c_uint;
    pub fn pugi_format_flag_no_declaration() -> c_uint;
    pub fn pugi_format_flag_no_escapes() -> c_uint;
    pub fn pugi_format_flag_raw() -> c_uint;
    pub fn pugi_format_flag_save_file_text() -> c_uint;
    pub fn pugi_format_flag_write_bom() -> c_uint;

    pub fn pugi_parse_result_status(parse_result: *const CParseResult) -> ParseStatus;
    pub fn pugi_parse_result_offset(parse_result: *const CParseResult) -> ptrdiff_t;
    pub fn pugi_parse_result_encoding(parse_result: *const CParseResult) -> Encoding;
    pub fn pugi_parse_result_description(parse_result: *const CParseResult) -> *const c_char;

    pub fn pugi_delete_parse_result(parse_result: *const CParseResult);

    pub fn pugi_new_document() -> *mut CDocument;
    pub fn pugi_delete_document(document: *mut CDocument);

    pub fn pugi_reset_document_with(document: *mut CDocument, proto: *const CDocument);

    pub fn pugi_load_file(document: *mut CDocument, path: *const c_char, options: c_uint,
                      encoding: Encoding)
        -> *const CParseResult;

    pub fn pugi_load_buffer(document: *mut CDocument, contents: *const c_char, size: size_t,
                        options: c_uint, encoding: Encoding)
        -> *const CParseResult;

    pub fn pugi_save_file(document: *const CDocument, path: *const c_char, indent: *const c_char,
                      options: c_uint, encoding: Encoding)
        -> c_int;

    pub fn pugi_delete_node(node: *mut CNode);

    pub fn pugi_node_equal(lhs: *const CNode, rhs: *const CNode) -> c_int;

    pub fn pugi_node_hash_value(node: *mut CNode) -> size_t;
    pub fn pugi_node_type(node: *const CNode) -> NodeKind;
    pub fn pugi_node_name(node: *const CNode) -> *const c_char;
    pub fn pugi_node_value(node: *const CNode) -> *const c_char;

    pub fn pugi_node_text(node: *const CNode) -> *const c_char;

    pub fn pugi_node_parent(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_child_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_first_child(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_last_child(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_next_sibling(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_previous_sibling(node: *const CNode) -> *mut CNode;
    pub fn pugi_node_next_sibling_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;
    pub fn pugi_node_previous_sibling_by_name(node: *const CNode, name: *const c_char) -> *mut CNode;

    pub fn pugi_node_find_child_by_name_and_attribute(node: *const CNode, name: *const c_char,
                                                  attribute_name: *const c_char,
                                                  attribute_value: *const c_char)
        -> *mut CNode;
    pub fn pugi_node_find_child_by_attribute(node: *const CNode, attribute_name: *const c_char,
                                         attribute_value: *const c_char)
        -> *mut CNode;

    pub fn pugi_node_child_value(node: *mut CNode) -> *const c_char;
    pub fn pugi_node_child_value_by_name(node: *mut CNode, name: *const c_char) -> *mut CNode;

    // pub fn pugi_node_attribute(node: *mut CNode, name: *const c_char) -> *mut CAttribute;
    pub fn pugi_node_path(node: *const CNode, delimiter: c_char) -> *const c_char;

    pub fn pugi_node_first_element_by_path(node: *const CNode, path: *const c_char, delimiter: c_char)
        -> *mut CNode;

    pub fn pugi_node_root(node: *const CNode) -> *mut CNode;

    pub fn pugi_node_set_name(node: *mut CNode, name: *const c_char) -> c_int;
    pub fn pugi_node_set_value(node: *mut CNode, name: *const c_char) -> c_int;

    pub fn pugi_node_append_attribute(node: *mut CNode, name: *const c_char, value: *const c_char)
        -> c_int;
    pub fn pugi_node_prepend_attribute(node: *mut CNode, name: *const c_char, value: *const c_char)
        -> c_int;

    pub fn pugi_node_append_child(node: *mut CNode, node_type: NodeKind) -> *mut CNode;
    pub fn pugi_node_prepend_child(node: *mut CNode, node_type: NodeKind) -> *mut CNode;

    pub fn pugi_node_append_copy(node: *mut CNode, proto: *mut CNode) -> *mut CNode;
    pub fn pugi_node_prepend_copy(node: *mut CNode, proto: *mut CNode) -> *mut CNode;

    pub fn pugi_node_remove_attribute(node: *mut CNode, name: *const c_char) -> c_int;
    pub fn pugi_node_remove_child(node: *mut CNode, to_be_removed_child: *const CNode) -> c_int;

    // pub fn pugi_node_print(node: *mut CNode,

    // pub fn pugi_node_find_attribute_by_predicate
    // pub fn pugi_node_find_child_by_predicate
    // pub fn pugi_node_find_node_by_predicate

    // pub fn pugi_node_map_sibling
    // pub fn pugi_node_map_attributes

    // pub fn pugi_xpath_delete_xpath_node(node: *mut CXPathNode);

    // pub fn pugi_xpath_node_node(node: *mut CXPathNode) -> *mut CNode;
    // pub fn pugi_xpath_node_attribute(node: *mut CXPathNode) -> *mut CAttribute;

    // pub fn pugi_xpath_delete_xpath_node_set(node_set: *const CNodeSet);

    // pub fn pugi_xpath_node_set_size(node_set: *const CNodeSet) -> size_t;
    // pub fn pugi_xpath_node_set_is_empty(node_set: *const CNodeSet) -> c_int;

    // pub fn pugi_xpath_node_set_index(node_set: *mut CNodeSet, index: size_t) -> *mut CXPathNode;

    // pub fn pugi_xpath_node_set_map

    // pub fn pugi_xpath_delete_xpath_query(xpath: *const CXPath);

    // pub fn pugi_xpath_query_evaluate_boolean(xpath: *const CXPath, node: *mut CNode) -> c_int;
    // pub fn pugi_xpath_query_evaluate_number(xpath: *const CXPath, node: *mut CNode) -> c_double;
    // pub fn pugi_xpath_query_evaluate_string(xpath: *const CXPath, node: *mut CNode) -> *const c_char;
    // pub fn pugi_xpath_query_evaluate_node_set(xpath: *const CXPath, node: *mut CNode)
    //     -> *const CNodeSet;

    // pub fn pugi_xpath_query_return_type(xpath: *const CXPath) -> XPathValueType;

    // pub fn pugi_xpath_query_parse_is_success(xpath: *const CXPath) -> c_int;

    // pub fn pugi_xpath_select_single_node(node: *mut CNode, xpath: *const CXPath) -> *mut CXPathNode;
    // pub fn pugi_xpath_select_nodes(node: *mut CNode, xpath: *const CXPath) -> *const CNodeSet;
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 Gilad Naaman, Ralf Jung
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// `addr_of!`, or just ref-then-cast when that is not available.
#[cfg(raw_ref_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__addr_of {
    ($path:expr) => {{
        $crate::__priv::ptr::addr_of!($path)
    }};
}
#[cfg(not(raw_ref_macros))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__addr_of {
    ($path:expr) => {{
        // This is UB because we create an intermediate reference to uninitialized memory.
        // Nothing we can do about that without `addr_of!` though.
        &$path as *const _
    }};
}

/// Deref-coercion protection macro.
#[cfg(allow_clippy)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check {
    ($type:path, $field:tt) => {
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        #[allow(clippy::unneeded_field_pattern)]
        let $type { $field: _, .. };
    };
}
#[cfg(not(allow_clippy))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check {
    ($type:path, $field:tt) => {
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        let $type { $field: _, .. };
    };
}

/// Deref-coercion protection macro.
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check_tuple {
    ($type:ty, $field:tt) => {
        // Make sure the type argument is a tuple
        let (_, ..): $type;
    };
}

/// Computes a const raw pointer to the given field of the given base pointer
/// to the given parent type.
///
/// The `base` pointer *must not* be dangling, but it *may* point to
/// uninitialized memory.
#[macro_export(local_inner_macros)]
macro_rules! raw_field {
    ($base:expr, $parent:path, $field:tt) => {{
        _memoffset__field_check!($parent, $field);
        let base = $base; // evaluate $base outside the `unsafe` block

        // Get the field address.
        // Crucially, we know that this will not trigger a deref coercion because
        // of the field check we did above.
        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
        unsafe {
            _memoffset__addr_of!((*(base as *const $parent)).$field)
        }
    }};
}

/// Computes a const raw pointer to the given field of the given base pointer
/// to the given parent tuple typle.
///
/// The `base` pointer *must not* be dangling, but it *may* point to
/// uninitialized memory.
#[cfg(tuple_ty)]
#[macro_export(local_inner_macros)]
macro_rules! raw_field_tuple {
    ($base:expr, $parent:ty, $field:tt) => {{
        _memoffset__field_check_tuple!($parent, $field);
        let base = $base; // evaluate $base outside the `unsafe` block

        // Get the field address.
        // Crucially, we know that this will not trigger a deref coercion because
        // of the field check we did above.
        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
        unsafe {
            _memoffset__addr_of!((*(base as *const $parent)).$field)
        }
    }};
}
<commit_msg>Suppress `clippy::unneeded_wildcard_pattern` (#64)<commit_after>// Copyright (c) 2020 Gilad Naaman, Ralf Jung
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// `addr_of!`, or just ref-then-cast when that is not available.
#[cfg(raw_ref_macros)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__addr_of {
    ($path:expr) => {{
        $crate::__priv::ptr::addr_of!($path)
    }};
}
#[cfg(not(raw_ref_macros))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__addr_of {
    ($path:expr) => {{
        // This is UB because we create an intermediate reference to uninitialized memory.
        // Nothing we can do about that without `addr_of!` though.
        &$path as *const _
    }};
}

/// Deref-coercion protection macro.
#[cfg(allow_clippy)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check {
    ($type:path, $field:tt) => {
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        #[allow(clippy::unneeded_field_pattern)]
        let $type { $field: _, .. };
    };
}
#[cfg(not(allow_clippy))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check {
    ($type:path, $field:tt) => {
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        let $type { $field: _, .. };
    };
}

/// Deref-coercion protection macro.
#[cfg(allow_clippy)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check_tuple {
    ($type:ty, $field:tt) => {
        // Make sure the type argument is a tuple
        #[allow(clippy::unneeded_wildcard_pattern)]
        let (_, ..): $type;
    };
}
#[cfg(not(allow_clippy))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check_tuple {
    ($type:ty, $field:tt) => {
        // Make sure the type argument is a tuple
        let (_, ..): $type;
    };
}

/// Computes a const raw pointer to the given field of the given base pointer
/// to the given parent type.
///
/// The `base` pointer *must not* be dangling, but it *may* point to
/// uninitialized memory.
#[macro_export(local_inner_macros)]
macro_rules! raw_field {
    ($base:expr, $parent:path, $field:tt) => {{
        _memoffset__field_check!($parent, $field);
        let base = $base; // evaluate $base outside the `unsafe` block

        // Get the field address.
        // Crucially, we know that this will not trigger a deref coercion because
        // of the field check we did above.
        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
        unsafe {
            _memoffset__addr_of!((*(base as *const $parent)).$field)
        }
    }};
}

/// Computes a const raw pointer to the given field of the given base pointer
/// to the given parent tuple typle.
///
/// The `base` pointer *must not* be dangling, but it *may* point to
/// uninitialized memory.
#[cfg(tuple_ty)]
#[macro_export(local_inner_macros)]
macro_rules! raw_field_tuple {
    ($base:expr, $parent:ty, $field:tt) => {{
        _memoffset__field_check_tuple!($parent, $field);
        let base = $base; // evaluate $base outside the `unsafe` block

        // Get the field address.
        // Crucially, we know that this will not trigger a deref coercion because
        // of the field check we did above.
        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
        unsafe {
            _memoffset__addr_of!((*(base as *const $parent)).$field)
        }
    }};
}
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

#![allow(dead_code)]

use term::*;
use term::Term::*;
/*
use self::Closure::*;
use self::Expression::*;
use std::collections::VecDeque;

#[derive(Debug, PartialEq, Clone)]
enum Closure {
    Depth(usize),
    TermInEnv(Term, Environment)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Evaluation(Closure),
    Application(Box<Expression>, Term, Environment)
}

type Environment = VecDeque<Closure>;

fn whnf(term: Term, mut env: Environment) -> Expression {
    match term {
        Var(i) => match env.remove(i - 1) {
            Some(Depth(i)) => Evaluation(Depth(i)),
            Some(TermInEnv(t, e)) => whnf(t, e),
            None => unreachable!()
        },
        Abs(t) => Evaluation(TermInEnv(Abs(t), env)),
        App(lhs, rhs) => match whnf(*lhs, env.clone()) { // TODO: try to remove this clone()
            Evaluation(TermInEnv(Abs(lhs2), mut env2)) => {
                env2.push_front(TermInEnv(*rhs, env));
                whnf(*lhs2, env2)
            },
            expr => Application(Box::new(expr), *rhs, env)
        }
    }
}

fn reduce(depth: usize, exp: Expression) -> Term {
    match exp {
        Application(lhs, rhs, env) => app(reduce(depth, *lhs), nf(depth, rhs, env)),
        Evaluation(TermInEnv(Abs(term), mut env)) => {
            env.push_front(Depth(depth));
            abs(nf(depth + 1, *term, env))
        },
        Evaluation(TermInEnv(term, _)) => term,
        Evaluation(Depth(i)) => Var(depth - i)
    }
}

fn nf(depth: usize, term: Term, env: Environment) -> Term {
    reduce(depth, whnf(term, env))
}

/// Returns a term reduced to its normal form. Consumes its argument.
///
/// # Example
///
/// ```
/// use lambda_calculus::booleans::{if_else, tru};
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// assert_eq!(normalize(if_else().app(tru()).app(one()).app(zero())), one());
/// ```
fn normalize(term: Term) -> Term {
    nf(0, term, VecDeque::new())
}
*/
/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(abs(abs(Var(1)))));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(&*format!("{}", succ_one), "λλ2((λλ21)21)");
    /// ```
    pub fn beta_once(&mut self) {
        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap().beta_once(),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", self) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", self) }
                } else {
                    self.lhs_ref_mut().unwrap().beta_once();
                    self.rhs_ref_mut().unwrap().beta_once()
                }
            }
        }
    }

    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full normal-order β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single normal-order β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(&*format!("{}", beta_once(succ_one)), "λλ2((λλ21)21)");
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

#[cfg(test)]
mod test {

}
<commit_msg>significantly optimize normal β-reduction<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

#![allow(dead_code)]

use term::*;
use term::Term::*;
/*
use self::Closure::*;
use self::Expression::*;
use std::collections::VecDeque;

#[derive(Debug, PartialEq, Clone)]
enum Closure {
    Depth(usize),
    TermInEnv(Term, Environment)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Evaluation(Closure),
    Application(Box<Expression>, Term, Environment)
}

type Environment = VecDeque<Closure>;

fn whnf(term: Term, mut env: Environment) -> Expression {
    match term {
        Var(i) => match env.remove(i - 1) {
            Some(Depth(i)) => Evaluation(Depth(i)),
            Some(TermInEnv(t, e)) => whnf(t, e),
            None => unreachable!()
        },
        Abs(t) => Evaluation(TermInEnv(Abs(t), env)),
        App(lhs, rhs) => match whnf(*lhs, env.clone()) { // TODO: try to remove this clone()
            Evaluation(TermInEnv(Abs(lhs2), mut env2)) => {
                env2.push_front(TermInEnv(*rhs, env));
                whnf(*lhs2, env2)
            },
            expr => Application(Box::new(expr), *rhs, env)
        }
    }
}

fn reduce(depth: usize, exp: Expression) -> Term {
    match exp {
        Application(lhs, rhs, env) => app(reduce(depth, *lhs), nf(depth, rhs, env)),
        Evaluation(TermInEnv(Abs(term), mut env)) => {
            env.push_front(Depth(depth));
            abs(nf(depth + 1, *term, env))
        },
        Evaluation(TermInEnv(term, _)) => term,
        Evaluation(Depth(i)) => Var(depth - i)
    }
}

fn nf(depth: usize, term: Term, env: Environment) -> Term {
    reduce(depth, whnf(term, env))
}

/// Returns a term reduced to its normal form. Consumes its argument.
///
/// # Example
///
/// ```
/// use lambda_calculus::booleans::{if_else, tru};
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// assert_eq!(normalize(if_else().app(tru()).app(one()).app(zero())), one());
/// ```
fn normalize(term: Term) -> Term {
    nf(0, term, VecDeque::new())
}
*/
/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(abs(abs(Var(1)))));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(&*format!("{}", succ_one), "λλ2((λλ21)21)");
    /// ```
    pub fn beta_once(&mut self) {
        let mut done = false;
        self._beta_once(&mut done);
    }

    fn _beta_once(&mut self, done: &mut bool) {
        if *done { return }

        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once(done),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", self) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", self) }
                    *done = true;
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once(done);
                    self.rhs_ref_mut().unwrap()._beta_once(done)
                }
            }
        }
    }

    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full normal-order β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single normal-order β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(&*format!("{}", beta_once(succ_one)), "λλ2((λλ21)21)");
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

#[cfg(test)]
mod test {

}
<|endoftext|>


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

use target::Target;

pub fn target() -> Target {
    Target {
        data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
        llvm_target: "i686-unknown-linux-gnu".to_string(),
        target_endian: "little".to_string(),
        target_word_size: "32".to_string(),
        arch: "x86".to_string(),
        target_os: "linux".to_string(),
        options: super::linux_base::opts()
    }
}
<commit_msg>Use -m32 on 32bit Linux<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use target::Target;

pub fn target() -> Target {
    let mut base = super::linux_base::opts();
    base.pre_link_args.push("-m32".to_string());

    Target {
        data_layout: "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32".to_string(),
        llvm_target: "i686-unknown-linux-gnu".to_string(),
        target_endian: "little".to_string(),
        target_word_size: "32".to_string(),
        arch: "x86".to_string(),
        target_os: "linux".to_string(),
        options: base,
    }
}
<|endoftext|>


<commit_before>use event::Event;
use sass::selector::SassSelector;
use sass::output_style::SassOutputStyle;
use error::Result;

use std::fmt;
use std::io::Write;

#[derive(Clone)]
pub struct SassRule<'a> {
    pub selectors: Vec<SassSelector<'a>>,
    pub children: Vec<Event<'a>>,
}

impl<'a> SassRule<'a> {
    pub fn new() -> SassRule<'a> {
        SassRule {
            selectors: Vec::new(),
            children: Vec::new(),
        }
    }

    fn selector_distribution(&self, parents: &str, separator: &str) -> String {
        match parents.len() {
            0 => self.selectors.iter().map(|s| (*s.name).to_string()).collect::<Vec<_>>().join(separator),
            _ => parents.split(",").map(|p| {
                self.selectors.iter().map(|s| {
                    if s.name.contains("&") {
                        s.name.replace("&", p.trim())
                    } else {
                        format!("{} {}", p.trim(), s.name)
                    }
                }).collect::<Vec<_>>().join(separator)
            }).collect::<Vec<_>>().join(separator),
        }
    }

    pub fn stream<W: Write>(&self, output: &mut W, style: SassOutputStyle) -> Result<()> {
        try!(self.recursive_stream(output, style, "", ""));
        Ok(try!(write!(output, "{}", style.rule_separator())))
    }

    pub fn recursive_stream<W: Write>(&self, output: &mut W, style: SassOutputStyle, parents: &str, nesting: &str) -> Result<()> {
        let mut selector_string = self.selector_distribution(parents, &style.selector_separator());
        if style == SassOutputStyle::Compressed {
            selector_string = compress_selectors(selector_string);
        }

        let mut properties = self.children.iter().filter(|c| !c.is_child_rule() ).map(|c| {
            c.to_string(style)
        });
        let mut has_properties = false;

        // TODO: peek?
        if let Some(prop) = properties.next() {
            has_properties = true;
            try!(write!(output, "{}{}{{{}{}",
              selector_string,
              style.selector_brace_separator(),
              style.brace_property_separator(),
              prop,
            ));
            for prop in properties {
                try!(write!(output, "{}{}", style.property_separator(nesting), prop));
            }
            try!(write!(output, "{}}}", style.property_brace_separator()));
        }

        let mut child_rules = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::Rule(ref rule) => rule,
                _ => unreachable!(),
            }
        });

        if let Some(child_rule) = child_rules.next() {
            if has_properties {
                try!(write!(output, "{}", style.rule_and_child_rules_separator()));
            }
            try!(child_rule.recursive_stream(output, style, &selector_string, &format!("  {}", nesting)));
            for child_rule in child_rules {
                try!(write!(output, "{}", style.child_rule_separator(has_properties)));
                try!(child_rule.recursive_stream(output, style, &selector_string, &format!("  {}", nesting)));
            }
        }
        Ok(())
    }
}

fn compress_selectors(selector_string: String) -> String {
    selector_string.replace(" > ", ">").replace(" + ", "+")
}

impl<'a> fmt::Debug for SassRule<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let children = self.children.iter().map(|c| format!("{:?}", c)).collect::<Vec<_>>().join("\n");
        let indented_children = children.split("\n").collect::<Vec<_>>().join("\n  ");
        write!(f, "{:?} {{\n  {}\n}}", self.selectors, indented_children)
    }
}
<commit_msg>Comments don't appear in compressed mode; don't put separators for them<commit_after>use event::Event;
use sass::selector::SassSelector;
use sass::output_style::SassOutputStyle;
use error::Result;

use std::fmt;
use std::io::Write;

#[derive(Clone)]
pub struct SassRule<'a> {
    pub selectors: Vec<SassSelector<'a>>,
    pub children: Vec<Event<'a>>,
}

impl<'a> SassRule<'a> {
    pub fn new() -> SassRule<'a> {
        SassRule {
            selectors: Vec::new(),
            children: Vec::new(),
        }
    }

    fn selector_distribution(&self, parents: &str, separator: &str) -> String {
        match parents.len() {
            0 => self.selectors.iter().map(|s| (*s.name).to_string()).collect::<Vec<_>>().join(separator),
            _ => parents.split(",").map(|p| {
                self.selectors.iter().map(|s| {
                    if s.name.contains("&") {
                        s.name.replace("&", p.trim())
                    } else {
                        format!("{} {}", p.trim(), s.name)
                    }
                }).collect::<Vec<_>>().join(separator)
            }).collect::<Vec<_>>().join(separator),
        }
    }

    pub fn stream<W: Write>(&self, output: &mut W, style: SassOutputStyle) -> Result<()> {
        try!(self.recursive_stream(output, style, "", ""));
        Ok(try!(write!(output, "{}", style.rule_separator())))
    }

    pub fn recursive_stream<W: Write>(&self, output: &mut W, style: SassOutputStyle, parents: &str, nesting: &str) -> Result<()> {
        let mut selector_string = self.selector_distribution(parents, &style.selector_separator());
        if style == SassOutputStyle::Compressed {
            selector_string = compress_selectors(selector_string);
        }

        let mut properties = self.children.iter().filter(|c| !c.is_child_rule() ).filter_map(|c| {
            let s = c.to_string(style);
            if s.len() > 0 { Some(s) } else { None }
        });
        let mut has_properties = false;

        // TODO: peek?
        if let Some(prop) = properties.next() {
            has_properties = true;
            try!(write!(output, "{}{}{{{}{}",
              selector_string,
              style.selector_brace_separator(),
              style.brace_property_separator(),
              prop,
            ));
            for prop in properties {
                try!(write!(output, "{}{}", style.property_separator(nesting), prop));
            }
            try!(write!(output, "{}}}", style.property_brace_separator()));
        }

        let mut child_rules = self.children.iter().filter(|c| c.is_child_rule() ).map(|c| {
            match c {
                &Event::Rule(ref rule) => rule,
                _ => unreachable!(),
            }
        });

        if let Some(child_rule) = child_rules.next() {
            if has_properties {
                try!(write!(output, "{}", style.rule_and_child_rules_separator()));
            }
            try!(child_rule.recursive_stream(output, style, &selector_string, &format!("  {}", nesting)));
            for child_rule in child_rules {
                try!(write!(output, "{}", style.child_rule_separator(has_properties)));
                try!(child_rule.recursive_stream(output, style, &selector_string, &format!("  {}", nesting)));
            }
        }
        Ok(())
    }
}

fn compress_selectors(selector_string: String) -> String {
    selector_string.replace(" > ", ">").replace(" + ", "+")
}

impl<'a> fmt::Debug for SassRule<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let children = self.children.iter().map(|c| format!("{:?}", c)).collect::<Vec<_>>().join("\n");
        let indented_children = children.split("\n").collect::<Vec<_>>().join("\n  ");
        write!(f, "{:?} {{\n  {}\n}}", self.selectors, indented_children)
    }
}
<|endoftext|>


<commit_before><commit_msg>Basic download functionality completed<commit_after><|endoftext|>


<commit_before><commit_msg>Remove iter call<commit_after><|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Don't forget to run this benchmark with AES-NI enable.
//! You can do this by building with the following flags:
//! `RUSTFLAGS="-Ctarget-cpu=skylake -Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"`.
//!

#[macro_use]
extern crate criterion;

use criterion::{Criterion, Throughput};
use rand::SeedableRng;
use std::convert::TryFrom as _;

use aptos_crypto::{
    noise::{handshake_init_msg_len, handshake_resp_msg_len, NoiseConfig, AES_GCM_TAGLEN},
    test_utils::TEST_SEED,
    x25519, Uniform as _, ValidCryptoMaterial as _,
};

const MSG_SIZE: usize = 4096;

fn benchmarks(c: &mut Criterion) {
    // bench the handshake
    let mut group = c.benchmark_group("handshake");
    group.throughput(Throughput::Elements(1));
    group.bench_function("xx", |b| {
        // setup keys first
        let mut rng = ::rand::rngs::StdRng::from_seed(TEST_SEED);
        let initiator_static = x25519::PrivateKey::generate(&mut rng);
        let initiator_static = initiator_static.to_bytes();
        let responder_static = x25519::PrivateKey::generate(&mut rng);
        let responder_public = responder_static.public_key();
        let responder_static = responder_static.to_bytes();

        let mut first_message = [0u8; handshake_init_msg_len(0)];
        let mut second_message = [0u8; handshake_init_msg_len(0)];

        b.iter(|| {
            let initiator_static =
                x25519::PrivateKey::try_from(initiator_static.clone().as_slice()).unwrap();
            let responder_static =
                x25519::PrivateKey::try_from(responder_static.clone().as_slice()).unwrap();

            let initiator = NoiseConfig::new(initiator_static);
            let responder = NoiseConfig::new(responder_static);

            let initiator_state = initiator
                .initiate_connection(
                    &mut rng,
                    b"prologue",
                    responder_public,
                    None,
                    &mut first_message,
                )
                .unwrap();

            let _ = responder
                .respond_to_client_and_finalize(
                    &mut rng,
                    b"prologue",
                    &first_message,
                    None,
                    &mut second_message,
                )
                .unwrap();
            let _ = initiator
                .finalize_connection(initiator_state, &second_message)
                .unwrap();
        })
    });
    group.finish();

    let mut transport_group = c.benchmark_group("transport");
    transport_group.throughput(Throughput::Bytes(MSG_SIZE as u64 * 2));
    transport_group.bench_function("AES-GCM throughput", |b| {
        let mut buffer_msg = [0u8; MSG_SIZE * 2];

        // setup keys first
        let mut rng = ::rand::rngs::StdRng::from_seed(TEST_SEED);
        let initiator_static = x25519::PrivateKey::generate(&mut rng);
        let responder_static = x25519::PrivateKey::generate(&mut rng);
        let responder_public = responder_static.public_key();

        // handshake first
        let initiator = NoiseConfig::new(initiator_static);
        let responder = NoiseConfig::new(responder_static);

        let mut first_message = [0u8; handshake_init_msg_len(0)];
        let mut second_message = [0u8; handshake_resp_msg_len(0)];

        let initiator_state = initiator
            .initiate_connection(
                &mut rng,
                b"prologue",
                responder_public,
                None,
                &mut first_message,
            )
            .unwrap();
        let (_, mut responder_session) = responder
            .respond_to_client_and_finalize(
                &mut rng,
                b"prologue",
                &first_message,
                None,
                &mut second_message,
            )
            .unwrap();
        let (_, mut initiator_session) = initiator
            .finalize_connection(initiator_state, &second_message)
            .unwrap();

        // bench throughput post-handshake
        b.iter(move || {
            let auth_tag = initiator_session
                .write_message_in_place(&mut buffer_msg[..MSG_SIZE])
                .expect("session should not be closed");

            buffer_msg[MSG_SIZE..MSG_SIZE + AES_GCM_TAGLEN].copy_from_slice(&auth_tag);

            let _plaintext = responder_session
                .read_message_in_place(&mut buffer_msg[..MSG_SIZE + AES_GCM_TAGLEN])
                .expect("session should not be closed");
        })
    });
    transport_group.finish();
}

criterion_group!(benches, benchmarks);
criterion_main!(benches);
<commit_msg>[crypto] fix noise benchmark<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Don't forget to run this benchmark with AES-NI enable.
//! You can do this by building with the following flags:
//! `RUSTFLAGS="-Ctarget-cpu=skylake -Ctarget-feature=+aes,+sse2,+sse4.1,+ssse3"`.
//!

#[macro_use]
extern crate criterion;

use criterion::{Criterion, Throughput};
use rand::SeedableRng;
use std::convert::TryFrom as _;

use aptos_crypto::{
    noise::{handshake_init_msg_len, handshake_resp_msg_len, NoiseConfig, AES_GCM_TAGLEN},
    test_utils::TEST_SEED,
    x25519, Uniform as _, ValidCryptoMaterial as _,
};

const MSG_SIZE: usize = 4096;

fn benchmarks(c: &mut Criterion) {
    // bench the handshake
    let mut group = c.benchmark_group("handshake");
    group.throughput(Throughput::Elements(1));
    group.bench_function("xx", |b| {
        // setup keys first
        let mut rng = ::rand::rngs::StdRng::from_seed(TEST_SEED);
        let initiator_static = x25519::PrivateKey::generate(&mut rng);
        let initiator_static = initiator_static.to_bytes();
        let responder_static = x25519::PrivateKey::generate(&mut rng);
        let responder_public = responder_static.public_key();
        let responder_static = responder_static.to_bytes();

        let mut first_message = [0u8; handshake_init_msg_len(0)];
        let mut second_message = [0u8; handshake_resp_msg_len(0)];

        b.iter(|| {
            let initiator_static =
                x25519::PrivateKey::try_from(initiator_static.clone().as_slice()).unwrap();
            let responder_static =
                x25519::PrivateKey::try_from(responder_static.clone().as_slice()).unwrap();

            let initiator = NoiseConfig::new(initiator_static);
            let responder = NoiseConfig::new(responder_static);

            let initiator_state = initiator
                .initiate_connection(
                    &mut rng,
                    b"prologue",
                    responder_public,
                    None,
                    &mut first_message,
                )
                .unwrap();

            let _ = responder
                .respond_to_client_and_finalize(
                    &mut rng,
                    b"prologue",
                    &first_message,
                    None,
                    &mut second_message,
                )
                .unwrap();
            let _ = initiator
                .finalize_connection(initiator_state, &second_message)
                .unwrap();
        })
    });
    group.finish();

    let mut transport_group = c.benchmark_group("transport");
    transport_group.throughput(Throughput::Bytes(MSG_SIZE as u64 * 2));
    transport_group.bench_function("AES-GCM throughput", |b| {
        let mut buffer_msg = [0u8; MSG_SIZE * 2];

        // setup keys first
        let mut rng = ::rand::rngs::StdRng::from_seed(TEST_SEED);
        let initiator_static = x25519::PrivateKey::generate(&mut rng);
        let responder_static = x25519::PrivateKey::generate(&mut rng);
        let responder_public = responder_static.public_key();

        // handshake first
        let initiator = NoiseConfig::new(initiator_static);
        let responder = NoiseConfig::new(responder_static);

        let mut first_message = [0u8; handshake_init_msg_len(0)];
        let mut second_message = [0u8; handshake_resp_msg_len(0)];

        let initiator_state = initiator
            .initiate_connection(
                &mut rng,
                b"prologue",
                responder_public,
                None,
                &mut first_message,
            )
            .unwrap();
        let (_, mut responder_session) = responder
            .respond_to_client_and_finalize(
                &mut rng,
                b"prologue",
                &first_message,
                None,
                &mut second_message,
            )
            .unwrap();
        let (_, mut initiator_session) = initiator
            .finalize_connection(initiator_state, &second_message)
            .unwrap();

        // bench throughput post-handshake
        b.iter(move || {
            let auth_tag = initiator_session
                .write_message_in_place(&mut buffer_msg[..MSG_SIZE])
                .expect("session should not be closed");

            buffer_msg[MSG_SIZE..MSG_SIZE + AES_GCM_TAGLEN].copy_from_slice(&auth_tag);

            let _plaintext = responder_session
                .read_message_in_place(&mut buffer_msg[..MSG_SIZE + AES_GCM_TAGLEN])
                .expect("session should not be closed");
        })
    });
    transport_group.finish();
}

criterion_group!(benches, benchmarks);
criterion_main!(benches);
<|endoftext|>