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

//! Tracking of pending loads in a document.
//! https://html.spec.whatwg.org/multipage/#the-end

use msg::constellation_msg::{PipelineId};
use net_traits::AsyncResponseTarget;
use net_traits::{Metadata, PendingAsyncLoad, ResourceTask, load_whole_resource};
use std::sync::Arc;
use url::Url;

#[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)]
pub enum LoadType {
    Image(Url),
    Script(Url),
    Subframe(Url),
    Stylesheet(Url),
    PageSource(Url),
}

impl LoadType {
    fn url(&self) -> &Url {
        match *self {
            LoadType::Image(ref url) |
            LoadType::Script(ref url) |
            LoadType::Subframe(ref url) |
            LoadType::Stylesheet(ref url) |
            LoadType::PageSource(ref url) => url,
        }
    }
}

#[derive(JSTraceable, HeapSizeOf)]
pub struct DocumentLoader {
    /// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there
    /// are lots of iframes.
    #[ignore_heap_size_of = "channels are hard"]
    pub resource_task: Arc<ResourceTask>,
    pipeline: Option<PipelineId>,
    blocking_loads: Vec<LoadType>,
    events_inhibited: bool,
}

impl DocumentLoader {
    pub fn new(existing: &DocumentLoader) -> DocumentLoader {
        DocumentLoader::new_with_task(existing.resource_task.clone(), None, None)
    }

    /// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there
    /// are lots of iframes.
    pub fn new_with_task(resource_task: Arc<ResourceTask>,
                         pipeline: Option<PipelineId>,
                         initial_load: Option<Url>)
                         -> DocumentLoader {
        let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();

        DocumentLoader {
            resource_task: resource_task,
            pipeline: pipeline,
            blocking_loads: initial_loads,
            events_inhibited: false,
        }
    }

    /// Create a new pending network request, which can be initiated at some point in
    /// the future.
    pub fn prepare_async_load(&mut self, load: LoadType) -> PendingAsyncLoad {
        let url = load.url().clone();
        self.blocking_loads.push(load);
        PendingAsyncLoad::new((*self.resource_task).clone(), url, self.pipeline)
    }

    /// Create and initiate a new network request.
    pub fn load_async(&mut self, load: LoadType, listener: AsyncResponseTarget) {
        let pending = self.prepare_async_load(load);
        pending.load_async(listener)
    }

    /// Create, initiate, and await the response for a new network request.
    pub fn load_sync(&mut self, load: LoadType) -> Result<(Metadata, Vec<u8>), String> {
        self.blocking_loads.push(load.clone());
        let result = load_whole_resource(&self.resource_task, load.url().clone());
        self.finish_load(load);
        result
    }

    /// Mark an in-progress network request complete.
    pub fn finish_load(&mut self, load: LoadType) {
        let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == load);
        self.blocking_loads.remove(idx.expect(&format!("unknown completed load {:?}", load)));
    }

    pub fn is_blocked(&self) -> bool {
        //TODO: Ensure that we report blocked if parsing is still ongoing.
        !self.blocking_loads.is_empty()
    }

    pub fn inhibit_events(&mut self) {
        self.events_inhibited = true;
    }
    pub fn events_inhibited(&self) -> bool {
        self.events_inhibited
    }
}
<commit_msg>Remove dead load_sync function.<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/. */

//! Tracking of pending loads in a document.
//! https://html.spec.whatwg.org/multipage/#the-end

use msg::constellation_msg::{PipelineId};
use net_traits::AsyncResponseTarget;
use net_traits::{PendingAsyncLoad, ResourceTask};
use std::sync::Arc;
use url::Url;

#[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)]
pub enum LoadType {
    Image(Url),
    Script(Url),
    Subframe(Url),
    Stylesheet(Url),
    PageSource(Url),
}

impl LoadType {
    fn url(&self) -> &Url {
        match *self {
            LoadType::Image(ref url) |
            LoadType::Script(ref url) |
            LoadType::Subframe(ref url) |
            LoadType::Stylesheet(ref url) |
            LoadType::PageSource(ref url) => url,
        }
    }
}

#[derive(JSTraceable, HeapSizeOf)]
pub struct DocumentLoader {
    /// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there
    /// are lots of iframes.
    #[ignore_heap_size_of = "channels are hard"]
    pub resource_task: Arc<ResourceTask>,
    pipeline: Option<PipelineId>,
    blocking_loads: Vec<LoadType>,
    events_inhibited: bool,
}

impl DocumentLoader {
    pub fn new(existing: &DocumentLoader) -> DocumentLoader {
        DocumentLoader::new_with_task(existing.resource_task.clone(), None, None)
    }

    /// We use an `Arc<ResourceTask>` here in order to avoid file descriptor exhaustion when there
    /// are lots of iframes.
    pub fn new_with_task(resource_task: Arc<ResourceTask>,
                         pipeline: Option<PipelineId>,
                         initial_load: Option<Url>)
                         -> DocumentLoader {
        let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();

        DocumentLoader {
            resource_task: resource_task,
            pipeline: pipeline,
            blocking_loads: initial_loads,
            events_inhibited: false,
        }
    }

    /// Create a new pending network request, which can be initiated at some point in
    /// the future.
    pub fn prepare_async_load(&mut self, load: LoadType) -> PendingAsyncLoad {
        let url = load.url().clone();
        self.blocking_loads.push(load);
        PendingAsyncLoad::new((*self.resource_task).clone(), url, self.pipeline)
    }

    /// Create and initiate a new network request.
    pub fn load_async(&mut self, load: LoadType, listener: AsyncResponseTarget) {
        let pending = self.prepare_async_load(load);
        pending.load_async(listener)
    }

    /// Mark an in-progress network request complete.
    pub fn finish_load(&mut self, load: LoadType) {
        let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == load);
        self.blocking_loads.remove(idx.expect(&format!("unknown completed load {:?}", load)));
    }

    pub fn is_blocked(&self) -> bool {
        //TODO: Ensure that we report blocked if parsing is still ongoing.
        !self.blocking_loads.is_empty()
    }

    pub fn inhibit_events(&mut self) {
        self.events_inhibited = true;
    }
    pub fn events_inhibited(&self) -> bool {
        self.events_inhibited
    }
}
<|endoftext|>


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

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, JSContext, JSObject, JS_StealArrayBufferContents};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

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(global: &Window,
                         number_of_channels: u32,
                         length: u32,
                         sample_rate: f32,
                         initial_data: Option<&[f32]>) -> AudioBuffer {
        let initial_data = match initial_data {
            Some(initial_data) => {
                let mut data = vec![];
                data.extend_from_slice(initial_data);
                data
            },
            None => vec![0.; (length * number_of_channels) as usize]
        };
        let cx = global.get_cx();
        let mut js_channels: Vec<JSAudioChannel> = Vec::with_capacity(number_of_channels as usize);
        for channel in 0..number_of_channels {
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let offset = (channel * length) as usize;
            let _ = unsafe {
                Float32Array::create(
                    cx,
                    CreateWith::Slice(&initial_data.as_slice()[offset..offset + (length as usize)]),
                    array.handle_mut())
            };
            let js_channel = Heap::default();
            js_channel.set(array.get());
            js_channels.push(js_channel);
        }
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(js_channels),
            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<&[f32]>) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(global, number_of_channels, length, sample_rate, initial_data);
        reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap)
    }

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

    #[allow(unsafe_code)]
    fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Move the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = (*self.shared_channels.borrow_mut()).buffers.remove(i);
            if unsafe {
                Float32Array::create(cx, CreateWith::Slice(&shared_channel), 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 {
                    // XXX TypedArrays API does not expose a way to steal the buffer's
                    //     content.
                    let data = array.to_vec();
                    let _ = JS_StealArrayBufferContents(cx, channel.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.
        }

        self.js_channels.borrow_mut().clear();

        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 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());
        // let destination = unsafe { destination.as_mut_slice() };

        // 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]);
                return Ok(());
            }
        }

        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 channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if !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 array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe { array.update(&source.as_slice()[offset..offset + bytes_to_copy]); }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<commit_msg>Make restore_js_channel_data unsafe<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, JSContext, JSObject, JS_StealArrayBufferContents};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

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(global: &Window,
                         number_of_channels: u32,
                         length: u32,
                         sample_rate: f32,
                         initial_data: Option<&[f32]>) -> AudioBuffer {
        let initial_data = match initial_data {
            Some(initial_data) => {
                let mut data = vec![];
                data.extend_from_slice(initial_data);
                data
            },
            None => vec![0.; (length * number_of_channels) as usize]
        };
        let cx = global.get_cx();
        let mut js_channels: Vec<JSAudioChannel> = Vec::with_capacity(number_of_channels as usize);
        for channel in 0..number_of_channels {
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let offset = (channel * length) as usize;
            let _ = unsafe {
                Float32Array::create(
                    cx,
                    CreateWith::Slice(&initial_data.as_slice()[offset..offset + (length as usize)]),
                    array.handle_mut())
            };
            let js_channel = Heap::default();
            js_channel.set(array.get());
            js_channels.push(js_channel);
        }
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(js_channels),
            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<&[f32]>) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(global, number_of_channels, length, sample_rate, initial_data);
        reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap)
    }

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

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Move the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = (*self.shared_channels.borrow_mut()).buffers.remove(i);
            if Float32Array::create(cx, CreateWith::Slice(&shared_channel), 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 {
                    // XXX TypedArrays API does not expose a way to steal the buffer's
                    //     content.
                    let data = array.to_vec();
                    let _ = JS_StealArrayBufferContents(cx, channel.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.
        }

        self.js_channels.borrow_mut().clear();

        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 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());
        // let destination = unsafe { destination.as_mut_slice() };

        // 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]);
                return Ok(());
            }
        }

        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 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 array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe { array.update(&source.as_slice()[offset..offset + bytes_to_copy]); }
        } else {
            return Err(Error::IndexSize);
        }

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


<commit_before>#![feature(phase)]
#![crate_name = "triangle"]

#[phase(plugin)]
extern crate gfx_macros;
extern crate gfx;
extern crate glfw;

#[vertex_format]
struct Vertex {
    pos: [f32, ..2],
    color: [f32, ..3],
}

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    attribute vec2 pos;
    attribute vec3 color;
    varying vec4 v_Color;
    void main() {
        v_Color = vec4(color, 1.0);
        gl_Position = vec4(pos, 0.0, 1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec2 pos;
    in vec3 color;
    out vec4 v_Color;
    void main() {
        v_Color = vec4(color, 1.0);
        gl_Position = vec4(pos, 0.0, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    varying vec4 v_Color;
    void main() {
        gl_FragColor = v_Color;
    }
"
GLSL_150: b"
    #version 150 core
    in vec4 v_Color;
    out vec4 o_Color;
    void main() {
        o_Color = v_Color;
    }
"
};

// We need to run on the main thread, so ensure we are using the `native` runtime. This is
// technically not needed, since this is the default, but it's not guaranteed.
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
     native::start(argc, argv, main)
}

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    let (mut window, events) = gfx::glfw::WindowBuilder::new(&glfw)
        .title("Welcome to gfx-rs!")
        .try_modern_context_hints()
        .create()
        .expect("Failed to create GLFW window.");

    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true); // so we can quit when Esc is pressed

    // spawn render task
    let (renderer, mut device) = {
        let (platform, provider) = gfx::glfw::Platform::new(window.render_context(), &glfw);
        gfx::start(platform, provider, 1).unwrap()
    };

    // spawn game task
    spawn(proc() {
        let mut renderer = renderer;
        let frame = gfx::Frame::new();
        let state = gfx::DrawState::new();

        let vertex_data = vec![
            Vertex { pos: [ -0.5, -0.5 ], color: [1.0, 0.0, 0.0] },
            Vertex { pos: [ 0.5, -0.5 ], color: [0.0, 1.0, 0.0]  },
            Vertex { pos: [ 0.0, 0.5 ], color: [0.0, 0.0, 1.0]  }
        ];

        let mesh = renderer.create_mesh(vertex_data);
        let program = renderer.create_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone());
        let bundle = renderer.bundle_program(program, ()).unwrap(); // no shader parameters

        let clear = gfx::ClearData {
            color: Some(gfx::Color([0.3, 0.3, 0.3, 1.0])),
            depth: None,
            stencil: None,
        };

        while !renderer.should_finish() {
            renderer.clear(clear, frame);
            renderer.draw(&mesh, gfx::VertexSlice(0, 3), frame, &bundle, state)
                .unwrap();
            renderer.end_frame();
            for err in renderer.errors() {
                println!("Renderer error: {}", err);
            }
        }
    });

    while !window.should_close() {
        glfw.poll_events();
        // quit when Esc is pressed.
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) => {
                    window.set_should_close(true);
                },
                _ => {},
            }
        }
        device.update();
    }
    device.close();
}
<commit_msg>Make triangle example compile<commit_after>#![feature(phase)]
#![crate_name = "triangle"]

#[phase(plugin)]
extern crate gfx_macros;
extern crate gfx;
extern crate glfw;
extern crate native;

#[vertex_format]
struct Vertex {
    pos: [f32, ..2],
    color: [f32, ..3],
}

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    attribute vec2 pos;
    attribute vec3 color;
    varying vec4 v_Color;
    void main() {
        v_Color = vec4(color, 1.0);
        gl_Position = vec4(pos, 0.0, 1.0);
    }
"
GLSL_150: b"
    #version 150 core
    in vec2 pos;
    in vec3 color;
    out vec4 v_Color;
    void main() {
        v_Color = vec4(color, 1.0);
        gl_Position = vec4(pos, 0.0, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120
    varying vec4 v_Color;
    void main() {
        gl_FragColor = v_Color;
    }
"
GLSL_150: b"
    #version 150 core
    in vec4 v_Color;
    out vec4 o_Color;
    void main() {
        o_Color = v_Color;
    }
"
};

// We need to run on the main thread, so ensure we are using the `native` runtime. This is
// technically not needed, since this is the default, but it's not guaranteed.
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
     native::start(argc, argv, main)
}

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    let (mut window, events) = gfx::glfw::WindowBuilder::new(&glfw)
        .title("Welcome to gfx-rs!")
        .try_modern_context_hints()
        .create()
        .expect("Failed to create GLFW window.");

    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true); // so we can quit when Esc is pressed

    // spawn render task
    let (renderer, mut device) = {
        let (platform, provider) = gfx::glfw::Platform::new(window.render_context(), &glfw);
        gfx::start(platform, provider, 1).unwrap()
    };

    // spawn game task
    spawn(proc() {
        let mut renderer = renderer;
        let frame = gfx::Frame::new();
        let state = gfx::DrawState::new();

        let vertex_data = vec![
            Vertex { pos: [ -0.5, -0.5 ], color: [1.0, 0.0, 0.0] },
            Vertex { pos: [ 0.5, -0.5 ], color: [0.0, 1.0, 0.0]  },
            Vertex { pos: [ 0.0, 0.5 ], color: [0.0, 0.0, 1.0]  }
        ];

        let mesh = renderer.create_mesh(vertex_data);
        let program = renderer.create_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone());
        let bundle = renderer.bundle_program(program, ()).unwrap(); // no shader parameters

        let clear = gfx::ClearData {
            color: Some(gfx::Color([0.3, 0.3, 0.3, 1.0])),
            depth: None,
            stencil: None,
        };

        while !renderer.should_finish() {
            renderer.clear(clear, frame);
            renderer.draw(&mesh, gfx::VertexSlice(0, 3), frame, &bundle, state)
                .unwrap();
            renderer.end_frame();
            for err in renderer.errors() {
                println!("Renderer error: {}", err);
            }
        }
    });

    while !window.should_close() {
        glfw.poll_events();
        // quit when Esc is pressed.
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) => {
                    window.set_should_close(true);
                },
                _ => {},
            }
        }
        device.update();
    }
    device.close();
}
<|endoftext|>


<commit_before>

use super::{AlwaysOkUnit, connection};
use futures::{Async, Future, Poll, Stream, future as futures, stream};
use futures::sync::{mpsc, oneshot};
use futures::unsync;

/// A hook to shut down a running server.
#[derive(Clone, Debug)]
pub struct Shutdown {
    tx: mpsc::UnboundedSender<oneshot::Sender<()>>,
}

/// A future that resolves when server shutdown completes.
#[derive(Debug)]
pub struct ShutdownFuture {
    inner: futures::Either<futures::FutureResult<(), ()>, AlwaysOkUnit<oneshot::Receiver<()>>>,
}

impl Future for ShutdownFuture {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        self.inner.poll()
    }
}

impl Shutdown {
    /// Initiates an orderly server shutdown.
    ///
    /// First, the server enters lameduck mode, in which
    /// existing connections are honored but no new connections are accepted. Then, once all
    /// connections are closed, it initates total shutdown.
    ///
    /// The returned future resolves when the server is completely shut down.
    pub fn shutdown(&self) -> ShutdownFuture {
        let (tx, rx) = oneshot::channel();
        let inner = if let Err(_) = self.tx.send(tx) {
            trace!("Server already initiated shutdown.");
            futures::Either::A(futures::ok(()))
        } else {
            futures::Either::B(AlwaysOkUnit(rx))
        };
        ShutdownFuture { inner: inner }
    }
}

#[derive(Debug)]
pub struct Watcher {
    shutdown_rx: stream::Take<mpsc::UnboundedReceiver<oneshot::Sender<()>>>,
    connections: unsync::mpsc::UnboundedReceiver<connection::Action>,
    queued_error: Option<()>,
    shutdown: Option<oneshot::Sender<()>>,
    done: bool,
    num_connections: u64,
}

impl Watcher {
    pub fn triple() -> (connection::Tracker, Shutdown, Self) {
        let (connection_tx, connections) = connection::Tracker::pair();
        let (shutdown_tx, shutdown_rx) = mpsc::unbounded();
        (
            connection_tx,
            Shutdown { tx: shutdown_tx },
            Watcher {
                shutdown_rx: shutdown_rx.take(1),
                connections: connections,
                queued_error: None,
                shutdown: None,
                done: false,
                num_connections: 0,
            },
        )
    }

    fn process_connection(&mut self, action: connection::Action) {
        match action {
            connection::Action::Increment => self.num_connections += 1,
            connection::Action::Decrement => self.num_connections -= 1,
        }
    }

    fn poll_shutdown_requests(&mut self) -> Poll<Option<()>, ()> {
        Ok(Async::Ready(match try_ready!(self.shutdown_rx.poll()) {
            Some(tx) => {
                debug!("Received shutdown request.");
                self.shutdown = Some(tx);
                Some(())
            }
            None => None,
        }))
    }

    fn poll_connections(&mut self) -> Poll<Option<()>, ()> {
        Ok(Async::Ready(match try_ready!(self.connections.poll()) {
            Some(action) => {
                self.process_connection(action);
                Some(())
            }
            None => None,
        }))
    }

    fn poll_shutdown_requests_and_connections(&mut self) -> Poll<Option<()>, ()> {
        if let Some(e) = self.queued_error.take() {
            return Err(e);
        }

        match try!(self.poll_shutdown_requests()) {
            Async::NotReady => {
                match try_ready!(self.poll_connections()) {
                    Some(()) => Ok(Async::Ready(Some(()))),
                    None => Ok(Async::NotReady),
                }
            }
            Async::Ready(None) => {
                match try_ready!(self.poll_connections()) {
                    Some(()) => Ok(Async::Ready(Some(()))),
                    None => Ok(Async::Ready(None)),
                }
            }
            Async::Ready(Some(())) => {
                match self.poll_connections() {
                    Err(e) => {
                        self.queued_error = Some(e);
                        Ok(Async::Ready(Some(())))
                    }
                    Ok(Async::NotReady) | Ok(Async::Ready(None)) | Ok(Async::Ready(Some(()))) => {
                        Ok(Async::Ready(Some(())))
                    }
                }
            }
        }
    }

    fn should_continue(&mut self) -> bool {
        match self.shutdown.take() {
            Some(shutdown) => {
                debug!("Lameduck mode: {} open connections", self.num_connections);
                if self.num_connections == 0 {
                    debug!("Shutting down.");
                    // Not required for the shutdown future to be waited on, so this
                    // can fail (which is fine).
                    let _ = shutdown.send(());
                    false
                } else {
                    self.shutdown = Some(shutdown);
                    true
                }
            }
            None => true,
        }
    }

    fn process_request(&mut self) -> Poll<Option<()>, ()> {
        if self.done {
            return Ok(Async::Ready(None));
        }
        if self.should_continue() {
            self.poll_shutdown_requests_and_connections()
        } else {
            self.done = true;
            Ok(Async::Ready(None))
        }
    }
}

impl Future for Watcher {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        loop {
            match try!(self.process_request()) {
                Async::Ready(Some(())) => continue,
                Async::Ready(None) => return Ok(Async::Ready(())),
                Async::NotReady => return Ok(Async::NotReady),
            }
        }
    }
}
<commit_msg>clippy: use .is_err() instead of destructuring Result<commit_after>

use super::{AlwaysOkUnit, connection};
use futures::{Async, Future, Poll, Stream, future as futures, stream};
use futures::sync::{mpsc, oneshot};
use futures::unsync;

/// A hook to shut down a running server.
#[derive(Clone, Debug)]
pub struct Shutdown {
    tx: mpsc::UnboundedSender<oneshot::Sender<()>>,
}

/// A future that resolves when server shutdown completes.
#[derive(Debug)]
pub struct ShutdownFuture {
    inner: futures::Either<futures::FutureResult<(), ()>, AlwaysOkUnit<oneshot::Receiver<()>>>,
}

impl Future for ShutdownFuture {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        self.inner.poll()
    }
}

impl Shutdown {
    /// Initiates an orderly server shutdown.
    ///
    /// First, the server enters lameduck mode, in which
    /// existing connections are honored but no new connections are accepted. Then, once all
    /// connections are closed, it initates total shutdown.
    ///
    /// The returned future resolves when the server is completely shut down.
    pub fn shutdown(&self) -> ShutdownFuture {
        let (tx, rx) = oneshot::channel();
        let inner = if self.tx.send(tx).is_err() {
            trace!("Server already initiated shutdown.");
            futures::Either::A(futures::ok(()))
        } else {
            futures::Either::B(AlwaysOkUnit(rx))
        };
        ShutdownFuture { inner: inner }
    }
}

#[derive(Debug)]
pub struct Watcher {
    shutdown_rx: stream::Take<mpsc::UnboundedReceiver<oneshot::Sender<()>>>,
    connections: unsync::mpsc::UnboundedReceiver<connection::Action>,
    queued_error: Option<()>,
    shutdown: Option<oneshot::Sender<()>>,
    done: bool,
    num_connections: u64,
}

impl Watcher {
    pub fn triple() -> (connection::Tracker, Shutdown, Self) {
        let (connection_tx, connections) = connection::Tracker::pair();
        let (shutdown_tx, shutdown_rx) = mpsc::unbounded();
        (
            connection_tx,
            Shutdown { tx: shutdown_tx },
            Watcher {
                shutdown_rx: shutdown_rx.take(1),
                connections: connections,
                queued_error: None,
                shutdown: None,
                done: false,
                num_connections: 0,
            },
        )
    }

    fn process_connection(&mut self, action: connection::Action) {
        match action {
            connection::Action::Increment => self.num_connections += 1,
            connection::Action::Decrement => self.num_connections -= 1,
        }
    }

    fn poll_shutdown_requests(&mut self) -> Poll<Option<()>, ()> {
        Ok(Async::Ready(match try_ready!(self.shutdown_rx.poll()) {
            Some(tx) => {
                debug!("Received shutdown request.");
                self.shutdown = Some(tx);
                Some(())
            }
            None => None,
        }))
    }

    fn poll_connections(&mut self) -> Poll<Option<()>, ()> {
        Ok(Async::Ready(match try_ready!(self.connections.poll()) {
            Some(action) => {
                self.process_connection(action);
                Some(())
            }
            None => None,
        }))
    }

    fn poll_shutdown_requests_and_connections(&mut self) -> Poll<Option<()>, ()> {
        if let Some(e) = self.queued_error.take() {
            return Err(e);
        }

        match try!(self.poll_shutdown_requests()) {
            Async::NotReady => {
                match try_ready!(self.poll_connections()) {
                    Some(()) => Ok(Async::Ready(Some(()))),
                    None => Ok(Async::NotReady),
                }
            }
            Async::Ready(None) => {
                match try_ready!(self.poll_connections()) {
                    Some(()) => Ok(Async::Ready(Some(()))),
                    None => Ok(Async::Ready(None)),
                }
            }
            Async::Ready(Some(())) => {
                match self.poll_connections() {
                    Err(e) => {
                        self.queued_error = Some(e);
                        Ok(Async::Ready(Some(())))
                    }
                    Ok(Async::NotReady) | Ok(Async::Ready(None)) | Ok(Async::Ready(Some(()))) => {
                        Ok(Async::Ready(Some(())))
                    }
                }
            }
        }
    }

    fn should_continue(&mut self) -> bool {
        match self.shutdown.take() {
            Some(shutdown) => {
                debug!("Lameduck mode: {} open connections", self.num_connections);
                if self.num_connections == 0 {
                    debug!("Shutting down.");
                    // Not required for the shutdown future to be waited on, so this
                    // can fail (which is fine).
                    let _ = shutdown.send(());
                    false
                } else {
                    self.shutdown = Some(shutdown);
                    true
                }
            }
            None => true,
        }
    }

    fn process_request(&mut self) -> Poll<Option<()>, ()> {
        if self.done {
            return Ok(Async::Ready(None));
        }
        if self.should_continue() {
            self.poll_shutdown_requests_and_connections()
        } else {
            self.done = true;
            Ok(Async::Ready(None))
        }
    }
}

impl Future for Watcher {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        loop {
            match try!(self.process_request()) {
                Async::Ready(Some(())) => continue,
                Async::Ready(None) => return Ok(Async::Ready(())),
                Async::NotReady => return Ok(Async::NotReady),
            }
        }
    }
}
<|endoftext|>


<commit_before>use petgraph::graph::NodeIndex;
use uuid::Uuid;
use rustwlc::{Geometry, Point};
use super::super::LayoutTree;
use super::super::core::container::{Container, ContainerType};

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.active_ix_of(ContainerType::Output)
            .or_else(|| {
                self.tree.follow_path_until(self.tree.root_ix(), ContainerType::Output).ok()
            })
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let size = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output").size;
        let worksp = Container::new_workspace(name.to_string(), size.clone());

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let geometry = Geometry {
            size: size, origin: Point { x: 0, y: 0 }
        };
        let container_ix = self.tree.add_child(worksp_ix,
                                               Container::new_container(geometry), false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        // Set the old one to invisible
        self.tree.set_family_visible(old_worksp_ix, false);
        // Set the new one to visible
        self.tree.set_family_visible(workspace_ix, true);
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                   .expect("Workspace had no name"));
            self.remove_container(old_worksp_ix);
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { ref handle, ..} => {
                        trace!("View found, focusing on {:?}", handle);
                        handle.focus();
                    },
                    _ => unreachable!()
                }
                self.active_container = Some(active_ix);
                if !self.tree[active_ix].floating() {
                    self.tree.set_ancestor_paths_active(active_ix);
                } else {
                    let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                        .expect("The workspace we are switching to had no root container");
                    self.tree.set_ancestor_paths_active(root_c_ix);
                }
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree.descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { floating, .. } => {
                        if !floating {
                            self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                        } else {
                            let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                            .expect("The workspace we are switching to had no root container");
                            self.tree.set_ancestor_paths_active(root_c_ix);
                        }
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.tree.set_family_visible(curr_work_ix, false);

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            info!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    self.remove_view_or_container(parent_ix);
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }

            self.tree.set_family_visible(curr_work_ix, true);

            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix);
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
    }
}
<commit_msg>Fixed new active path bug from switching wrkspaces<commit_after>use petgraph::graph::NodeIndex;
use uuid::Uuid;
use rustwlc::{Geometry, Point};
use super::super::LayoutTree;
use super::super::core::container::{Container, ContainerType};

// TODO This module needs to be updated like the other modules...
// Need to add some errors for this (such as when trying to move a non-container/view,
// or when trying to grab a workspace whos name already exists)
//
// Also the code is generally pretty crap, cause it's pretty old (mid-2016)

impl LayoutTree {
    /// Gets a workspace by name or creates it
    fn get_or_make_workspace(&mut self, name: &str) -> NodeIndex {
        let active_index = self.active_ix_of(ContainerType::Output)
            .or_else(|| {
                self.tree.follow_path_until(self.tree.root_ix(), ContainerType::Output).ok()
            })
            .expect("get_or_make_wksp: Couldn't get output");
        let workspace_ix = self.tree.workspace_ix_by_name(name).unwrap_or_else(|| {
            let root_ix = self.init_workspace(name.to_string(), active_index);
            self.tree.parent_of(root_ix)
                .expect("Workspace was not properly initialized with a root container")
        });
        self.validate();
        workspace_ix
    }

    /// Initializes a workspace and gets the index of the root container
    pub fn init_workspace(&mut self, name: String, output_ix: NodeIndex)
                      -> NodeIndex {
        let size = self.tree.get(output_ix)
            .expect("init_workspace: invalid output").get_geometry()
            .expect("init_workspace: no geometry for output").size;
        let worksp = Container::new_workspace(name.to_string(), size.clone());

        trace!("Adding workspace {:?}", worksp);
        let worksp_ix = self.tree.add_child(output_ix, worksp, false);
        let geometry = Geometry {
            size: size, origin: Point { x: 0, y: 0 }
        };
        let container_ix = self.tree.add_child(worksp_ix,
                                               Container::new_container(geometry), false);
        self.tree.set_ancestor_paths_active(container_ix);
        self.validate();
        container_ix
    }

    /// Switch to the specified workspace
    pub fn switch_to_workspace(&mut self, name: &str) {
        let maybe_active_ix = self.active_container
            .or_else(|| {
                let new_active = self.tree.follow_path(self.tree.root_ix());
                match self.tree[new_active].get_type() {
                    ContainerType::View | ContainerType::Container => {
                        Some(new_active)
                    },
                    // else try and get the root container
                    _ => self.tree.descendant_of_type(new_active, ContainerType::Container).ok()
                }
            });
        if maybe_active_ix.is_none() {
            warn!("{:#?}", self);
            warn!("No active container, cannot switch");
            return;
        }
        let active_ix = maybe_active_ix.unwrap();
        // Get the old (current) workspace
        let old_worksp_ix: NodeIndex;
        if let Ok(index) = self.tree.ancestor_of_type(active_ix, ContainerType::Workspace) {
            old_worksp_ix = index;
            trace!("Switching to workspace {}", name);
        } else {
            match self.tree[active_ix].get_type() {
                ContainerType::Workspace => {
                    old_worksp_ix = active_ix;
                    trace!("Switching to workspace {}", name);
                },
                _ => {
                    warn!("Could not find old workspace, could not set invisible");
                    return;
                }
            }
        }
        // Get the new workspace, or create one if it doesn't work
        let mut workspace_ix = self.get_or_make_workspace(name);
        if old_worksp_ix == workspace_ix {
            return;
        }
        // Set the old one to invisible
        self.tree.set_family_visible(old_worksp_ix, false);
        // Set the new one to visible
        self.tree.set_family_visible(workspace_ix, true);
        // Delete the old workspace if it has no views on it
        self.active_container = None;
        if self.tree.descendant_of_type(old_worksp_ix, ContainerType::View).is_err() {
            trace!("Removing workspace: {:?}", self.tree[old_worksp_ix].get_name()
                   .expect("Workspace had no name"));
            self.remove_container(old_worksp_ix);
        }
        workspace_ix = self.tree.workspace_ix_by_name(name)
            .expect("Workspace we just made was deleted!");
        let active_ix = self.tree.follow_path(workspace_ix);
        match self.tree[active_ix].get_type() {
            ContainerType::View  => {
                match self.tree[active_ix] {
                    Container::View { ref handle, ..} => {
                        trace!("View found, focusing on {:?}", handle);
                        handle.focus();
                    },
                    _ => unreachable!()
                }
                self.active_container = Some(active_ix);
                if !self.tree[active_ix].floating() {
                    self.tree.set_ancestor_paths_active(active_ix);
                } else {
                    let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                        .expect("The workspace we are switching to had no root container");
                    self.tree.set_ancestor_paths_active(root_c_ix);
                }
                self.validate();
                self.validate_path();
                return;
            },
            _ => {
                self.active_container = self.tree.descendant_of_type(active_ix, ContainerType::View)
                    .or_else(|_| self.tree.descendant_of_type(active_ix,
                                                              ContainerType::Container)).ok();
                match self.tree[self.active_container.expect("Workspace had NO children!")] {
                    Container::View { floating, .. } => {
                        if !floating {
                            self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                        } else {
                            let root_c_ix = *self.tree.children_of(workspace_ix).get(0)
                            .expect("The workspace we are switching to had no root container");
                            self.tree.set_ancestor_paths_active(root_c_ix);
                        }
                    },
                    Container::Container { .. } => {
                        self.tree.set_ancestor_paths_active(self.active_container.unwrap());
                    }
                    _ => unreachable!()
                };
            }
        }
        trace!("Focusing on next container");
        self.focus_on_next_container(workspace_ix);
        self.validate();
        self.validate_path();
    }

    /// Moves the active container to a new workspace.
    pub fn send_active_to_workspace(&mut self, name: &str) {
        if let Some(active_ix) = self.active_container {
            let id = self.tree[active_ix].get_id();
            self.send_to_workspace(id, name);
        }
    }
    /// Moves a container to a new workspace
    pub fn send_to_workspace(&mut self, id: Uuid, name: &str) {
        let node_ix = self.tree.lookup_id(id);
        // Ensure focus
        if let Some(active_ix) = node_ix.or(self.active_container) {
            let curr_work_ix = self.active_ix_of(ContainerType::Workspace)
                .expect("send_active: Not currently in a workspace!");
            if active_ix == self.tree.children_of(curr_work_ix)[0] {
                warn!("Tried to move the root container of a workspace, aborting move");
                return;
            }
            let next_work_ix = self.get_or_make_workspace(name);

            // Check if the workspaces are the same
            if next_work_ix == curr_work_ix {
                trace!("Attempted to move a view to the same workspace {}!", name);
                return;
            }
            self.tree.set_family_visible(curr_work_ix, false);

            // Save the parent of this view for focusing
            let maybe_active_parent = self.tree.parent_of(active_ix);

            // Get the root container of the next workspace
            let next_work_children = self.tree.children_of(next_work_ix);
            if cfg!(debug_assertions) {
                assert!(next_work_children.len() == 1,
                        "Next workspace has multiple roots!");
            }
            let next_work_root_ix = next_work_children[0];

            // Move the container
            info!("Moving container {:?} to workspace {}",
                self.get_active_container(), name);
            self.tree.move_node(active_ix, next_work_root_ix);

            // Update the active container
            if let Ok(parent_ix) = maybe_active_parent {
                self.tree.set_ancestor_paths_active(parent_ix);
                let ctype = self.tree.node_type(parent_ix).unwrap_or(ContainerType::Root);
                if ctype == ContainerType::Container {
                    self.focus_on_next_container(parent_ix);
                } else {
                    trace!("Send to container invalidated a NodeIndex: {:?} to {:?}",
                    parent_ix, ctype);
                }
                if self.tree.can_remove_empty_parent(parent_ix) {
                    self.remove_view_or_container(parent_ix);
                }
            }
            else {
                self.focus_on_next_container(curr_work_ix);
            }

            self.tree.set_family_visible(curr_work_ix, true);

            if !self.tree[active_ix].floating() {
                self.normalize_container(active_ix);
            }
        }
        let root_ix = self.tree.root_ix();
        self.layout(root_ix);
        self.validate();
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Closed and bounded generic interval set.
//!
//! It stores intervals in a set. The main advantage is the exact representation of an interval by allowing "holes". For example `[1..2] U [5..6]` is stored as `{[1..2], [5..6]}`. This structure is more space-efficient than a classic set collection (such as `BTreeSet`) if the data stored are mostly contiguous. Of course, it is less light-weight than [interval](../interval/index.html), but we keep the list of interval as small as possible by merging overlapping intervals.
//!
//! # See also
//! [interval](../interval/index.html)

use interval::Interval;
use ncollections::ops::*;
use ops::*;

use std::num::Int;

pub struct IntervalSet<Bound> {
  intervals: Vec<Interval<Bound>>,
  size: Bound
}

impl<Bound: Int> IntervalSet<Bound>
{
  fn front<'a>(&'a self) -> &'a Interval<Bound> {
    assert!(!self.intervals.is_empty(), "Cannot access the first interval of an empty set.");
    &self.intervals[0]
  }

  fn back<'a>(&'a self) -> &'a Interval<Bound> {
    assert!(!self.intervals.is_empty(), "Cannot access the last interval of an empty set.");
    &self.intervals[self.intervals.len() - 1]
  }

  fn span(&self) -> Interval<Bound> {
    if self.is_empty() {
      Interval::empty()
    }
    else {
      Interval::new(
        self.front().lower(),
        self.back().upper()
      )
    }
  }
}

impl<Bound: Int> Eq for IntervalSet<Bound> {}

impl<Bound: Int> PartialEq<IntervalSet<Bound>> for IntervalSet<Bound>
{
  fn eq(&self, other: &IntervalSet<Bound>) -> bool {
    if self.size() != other.size() { false }
    else {
      self.intervals == other.intervals
    }
  }
}

impl<Bound: Int> Range<Bound> for IntervalSet<Bound>
{
  fn new(lb: Bound, ub: Bound) -> IntervalSet<Bound> {
    assert!(lb <= ub, "Cannot build empty interval set with an invalid range. Use IntervalSet::empty().");
    let i = Interval::new(lb, ub);
    IntervalSet {
      intervals: vec![i],
      size: i.size()
    }
  }
}

impl<Bound: Int> Bounded for IntervalSet<Bound>
{
  type Bound = Bound;

  fn lower(&self) -> Bound {
    assert!(!self.intervals.is_empty(), "Cannot access lower bound on empty interval.");
    self.front().lower()
  }

  fn upper(&self) -> Bound {
    assert!(!self.intervals.is_empty(), "Cannot access upper bound on empty interval.");
    self.back().upper()
  }
}

impl <Bound: Int> Singleton<Bound> for IntervalSet<Bound>
{
  fn singleton(x: Bound) -> IntervalSet<Bound> {
    IntervalSet::new(x, x)
  }
}

impl<Bound: Int> Empty for IntervalSet<Bound>
{
  fn empty() -> IntervalSet<Bound> {
    IntervalSet {
      intervals: vec![],
      size: <Bound as Int>::zero()
    }
  }
}

impl<Bound: Int> Cardinality for IntervalSet<Bound>
{
  type Size = Bound;

  fn size(&self) -> Bound {
    self.size
  }

  fn is_singleton(&self) -> bool {
    self.intervals.len() == 1 && self.intervals[0].is_singleton()
  }

  fn is_empty(&self) -> bool {
    self.intervals.is_empty()
  }
}

impl<Bound: Int> Contains<Bound> for IntervalSet<Bound>
{
  fn contains(&self, value: &Bound) -> bool {
    if !self.span().contains(value) {
      false
    }
    else {
      let value = *value;
      let mut left = 0;
      let mut right = self.intervals.len() - 1;
      while left <= right {
        let mid_idx = (left + right) / 2;
        let mid = self.intervals[mid_idx];
        if mid.lower() > value {
          right = mid_idx - 1;
        }
        else if mid.upper() < value {
          left = mid_idx + 1;
        }
        else {
          return true;
        }
      }
      false
    }
  }
}

#[allow(non_upper_case_globals)]
#[cfg(test)]
mod tests {
  use super::*;
  use ncollections::ops::*;
  use interval::*;
  use ops::*;

  #[test]
  fn test_contains() {
    let i1_2 = IntervalSet::new(1i32, 2i32);
    let i1_2u5_8 = IntervalSet {
      intervals: vec![
        Interval::new(1,2),
        Interval::new(5,8)
      ],
      size: 6
    };

    assert!(i1_2.contains(&1));
    assert!(i1_2.contains(&2));
    assert!(!i1_2.contains(&0));
    assert!(!i1_2.contains(&3));

    assert!(!i1_2u5_8.contains(&0));
    for i in 1..3 {
      assert!(i1_2u5_8.contains(&i));
    }
    for i in 3..5 {
      assert!(!i1_2u5_8.contains(&i));
    }
    for i in 5..9 {
      assert!(i1_2u5_8.contains(&i));
    }
    for i in 9..13 {
      assert!(!i1_2u5_8.contains(&i));
    }
  }
}<commit_msg>Add support for union and tests. Related to #3.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Closed and bounded generic interval set.
//!
//! It stores intervals in a set. The main advantage is the exact representation of an interval by allowing "holes". For example `[1..2] U [5..6]` is stored as `{[1..2], [5..6]}`. This structure is more space-efficient than a classic set collection (such as `BTreeSet`) if the data stored are mostly contiguous. Of course, it is less light-weight than [interval](../interval/index.html), but we keep the list of interval as small as possible by merging overlapping intervals.
//!
//! # See also
//! [interval](../interval/index.html)

use interval::Interval;
use ncollections::ops::*;
use ops::*;
use std::iter::{Peekable, IntoIterator};

use std::num::Int;

#[derive(Debug, Clone)]
pub struct IntervalSet<Bound> {
  intervals: Vec<Interval<Bound>>,
  size: Bound
}

impl<Bound: Int> IntervalSet<Bound>
{
  fn from_interval(i: Interval<Bound>) -> IntervalSet<Bound> {
    IntervalSet {
      intervals: vec![i],
      size: i.size()
    }
  }

  fn front<'a>(&'a self) -> &'a Interval<Bound> {
    assert!(!self.is_empty(), "Cannot access the first interval of an empty set.");
    &self.intervals[0]
  }

  fn back<'a>(&'a self) -> &'a Interval<Bound> {
    assert!(!self.is_empty(), "Cannot access the last interval of an empty set.");
    &self.intervals[self.intervals.len() - 1]
  }

  fn span(&self) -> Interval<Bound> {
    if self.is_empty() {
      Interval::empty()
    }
    else {
      Interval::new(
        self.front().lower(),
        self.back().upper()
      )
    }
  }

  fn push(&mut self, x: Interval<Bound>) {
    assert!(!x.is_empty(), "Cannot push empty interval.");
    assert!(self.is_empty() || !joinable(self.back(), &x),
      "The intervals array must be ordered and intervals must not be joinable. For a safe push, use the union operation.");

    self.size = self.size + x.size();
    self.intervals.push(x);
  }

  fn pop(&mut self) -> Option<Interval<Bound>> {
    if let Some(x) = self.intervals.pop() {
      self.size = self.size - x.size();
      Some(x)
    } else {
      None
    }
  }

  fn join_or_push(&mut self, x: Interval<Bound>) {
    if self.is_empty() {
      self.push(x);
    }
    else {
      assert!(!x.is_empty(), "Cannot push empty interval.");
      assert!(self.back().lower() <= x.lower(),
        "This operation is only for pushing interval to the back of the array, possibly overlapping with the last element.");

      let joint =
        if joinable(self.back(), &x) {
          self.pop().unwrap().hull(&x)
        }
        else {
          x
        };
      self.push(joint);
    }
  }

  fn interval_count(&self) -> usize {
    self.intervals.len()
  }
}

fn joinable<Bound: Int>(first: &Interval<Bound>, second: &Interval<Bound>) -> bool {
  first.upper() + Bound::one() >= second.lower()
}

impl<Bound: Int> Extend<Interval<Bound>> for IntervalSet<Bound>
{
  fn extend<I>(&mut self, iterable: I) where
   I: IntoIterator<Item=Interval<Bound>>
  {
    for interval in iterable {
      self.join_or_push(interval);
    }
  }
}

impl<Bound: Int> Eq for IntervalSet<Bound> {}

impl<Bound: Int> PartialEq<IntervalSet<Bound>> for IntervalSet<Bound>
{
  fn eq(&self, other: &IntervalSet<Bound>) -> bool {
    if self.size() != other.size() { false }
    else {
      self.intervals == other.intervals
    }
  }
}

impl<Bound: Int> Range<Bound> for IntervalSet<Bound>
{
  fn new(lb: Bound, ub: Bound) -> IntervalSet<Bound> {
    assert!(lb <= ub, "Cannot build empty interval set with an invalid range. Use IntervalSet::empty().");
    let i = Interval::new(lb, ub);
    IntervalSet::from_interval(i)
  }
}

impl<Bound: Int> Bounded for IntervalSet<Bound>
{
  type Bound = Bound;

  fn lower(&self) -> Bound {
    assert!(!self.intervals.is_empty(), "Cannot access lower bound on empty interval.");
    self.front().lower()
  }

  fn upper(&self) -> Bound {
    assert!(!self.intervals.is_empty(), "Cannot access upper bound on empty interval.");
    self.back().upper()
  }
}

impl <Bound: Int> Singleton<Bound> for IntervalSet<Bound>
{
  fn singleton(x: Bound) -> IntervalSet<Bound> {
    IntervalSet::new(x, x)
  }
}

impl<Bound: Int> Empty for IntervalSet<Bound>
{
  fn empty() -> IntervalSet<Bound> {
    IntervalSet {
      intervals: vec![],
      size: <Bound as Int>::zero()
    }
  }
}

impl<Bound: Int> Cardinality for IntervalSet<Bound>
{
  type Size = Bound;

  fn size(&self) -> Bound {
    self.size
  }

  fn is_singleton(&self) -> bool {
    self.intervals.len() == 1 && self.intervals[0].is_singleton()
  }

  fn is_empty(&self) -> bool {
    self.intervals.is_empty()
  }
}

impl<Bound: Int> Contains<Bound> for IntervalSet<Bound>
{
  fn contains(&self, value: &Bound) -> bool {
    if !self.span().contains(value) {
      false
    }
    else {
      let value = *value;
      let mut left = 0;
      let mut right = self.intervals.len() - 1;
      while left <= right {
        let mid_idx = (left + right) / 2;
        let mid = self.intervals[mid_idx];
        if mid.lower() > value {
          right = mid_idx - 1;
        }
        else if mid.upper() < value {
          left = mid_idx + 1;
        }
        else {
          return true;
        }
      }
      false
    }
  }
}

fn advance_lower<I, Item>(a : &mut Peekable<I>, b: &mut Peekable<I>) -> Item where
 I: Iterator<Item=Item>,
 Item: Bounded
{
  assert!(!a.is_empty() && !b.is_empty());
  let who_advance = {
    let i = a.peek().unwrap();
    let j = b.peek().unwrap();
    i.lower() < j.lower()
  };
  let to_advance = if who_advance { a } else { b };
  to_advance.next().unwrap()
}

fn from_lower_iterator<I, Bound>(a : &mut Peekable<I>, b: &mut Peekable<I>) -> IntervalSet<Bound> where
 I: Iterator<Item=Interval<Bound>>,
 Bound: Int
{
  if a.is_empty() || b.is_empty() {
    IntervalSet::empty()
  } else {
    let first = advance_lower(a, b);
    IntervalSet::from_interval(first)
  }
}

impl<Bound: Int> Union for IntervalSet<Bound>
{
  type Output = IntervalSet<Bound>;

  fn union(&self, rhs: &IntervalSet<Bound>) -> IntervalSet<Bound> {
    let mut a = &mut self.intervals.iter().cloned().peekable();
    let mut b = &mut rhs.intervals.iter().cloned().peekable();
    let mut res = from_lower_iterator(a, b);
    while !a.is_empty() && !b.is_empty() {
      let lower = advance_lower(a, b);
      res.join_or_push(lower);
    }
    res.extend(a);
    res.extend(b);
    res
  }
}

#[allow(non_upper_case_globals)]
#[cfg(test)]
mod tests {
  use super::*;
  use ncollections::ops::*;
  use interval::*;
  use ops::*;

  fn test_inside_outside(is: IntervalSet<i32>, inside: Vec<i32>, outside: Vec<i32>) {
    for i in &inside {
      assert!(is.contains(i),
        format!("{} is not contained inside {:?}, but it should.", i, is));
    }
    for i in &outside {
      assert!(!is.contains(i),
        format!("{} is contained inside {:?}, but it should not.", i, is));
    }
  }

  // precondition: `intervals` must be a valid intern representation of the interval set.
  fn make_interval_set(intervals: Vec<(i32, i32)>) -> IntervalSet<i32> {
    let intervals: Vec<Interval<i32>> =
       intervals.into_iter()
      .map(|i| i.to_interval())
      .collect();
    let size = intervals.iter().fold(0, |a, i| a + i.size());
    IntervalSet {
      intervals: intervals,
      size: size
    }
  }

  #[test]
  fn test_contains() {
    let cases = vec![
      (vec![], vec![], vec![-2,-1,0,1,2]),
      (vec![(1,2)], vec![1,2], vec![-1,0,3,4]),
      (vec![(1,2),(7,9)], vec![1,2,7,8,9], vec![-1,0,3,4,5,6,10,11]),
      (vec![(1,2),(4,5),(7,9)], vec![1,2,4,5,7,8,9], vec![-1,0,3,6,10,11])
    ];

    for (is, inside, outside) in cases {
      let is = make_interval_set(is);
      test_inside_outside(is, inside, outside);
    }
  }

  #[test]
  fn test_union() {
    // Note: the first number is the test id, so it should be easy to identify which test has failed.
    let sym_cases = vec![
      // identity tests
      (1, vec![], vec![], vec![]),
      (2, vec![], vec![(1,2)], vec![(1,2)]),
      (3, vec![], vec![(1,2),(7,9)], vec![(1,2),(7,9)]),
      (4, vec![(1,2),(7,9)], vec![(1,2)], vec![(1,2),(7,9)]),
      (5, vec![(1,2),(7,9)], vec![(1,2),(7,9)], vec![(1,2),(7,9)]),
      // front tests
      (6, vec![(-3,-1)], vec![(1,2),(7,9)], vec![(-3,-1),(1,2),(7,9)]),
      (7, vec![(-3,0)], vec![(1,2),(7,9)], vec![(-3,2),(7,9)]),
      (8, vec![(-3,1)], vec![(1,2),(7,9)], vec![(-3,2),(7,9)]),
      // middle tests
      (9, vec![(2,7)], vec![(1,2),(7,9)], vec![(1,9)]),
      (10, vec![(3,7)], vec![(1,2),(7,9)], vec![(1,9)]),
      (11, vec![(4,5)], vec![(1,2),(7,9)], vec![(1,2),(4,5),(7,9)]),
      (12, vec![(2,8)], vec![(1,2),(7,9)], vec![(1,9)]),
      (13, vec![(2,6)], vec![(1,2),(7,9)], vec![(1,9)]),
      (14, vec![(3,6)], vec![(1,2),(7,9)], vec![(1,9)]),
      // back tests
      (15, vec![(8,9)], vec![(1,2),(7,9)], vec![(1,2),(7,9)]),
      (16, vec![(8,10)], vec![(1,2),(7,9)], vec![(1,2),(7,10)]),
      (17, vec![(9,10)], vec![(1,2),(7,9)], vec![(1,2),(7,10)]),
      (18, vec![(6,10)], vec![(1,2),(7,9)], vec![(1,2),(6,10)]),
      (19, vec![(10,11)], vec![(1,2),(7,9)], vec![(1,2),(7,11)]),
      (20, vec![(11,12)], vec![(1,2),(7,9)], vec![(1,2),(7,9),(11,12)]),
      // mixed tests
      (21, vec![(-3,-1),(4,5),(11,12)], vec![(1,2),(7,9)], vec![(-3,-1),(1,2),(4,5),(7,9),(11,12)]),
      (22, vec![(-3,0),(3,6),(10,11)], vec![(1,2),(7,9)], vec![(-3,11)]),
      (23, vec![(-3,1),(3,7),(9,11)], vec![(1,2),(7,9)], vec![(-3,11)]),
      (24, vec![(-3,5),(7,11)], vec![(1,2),(7,9)], vec![(-3,5),(7,11)]),
      (25, vec![(-3,5),(7,8),(12,12)], vec![(1,2),(7,9)], vec![(-3,5),(7,9),(12,12)]),
      // englobing tests
      (26, vec![(-1,11)], vec![(1,2),(7,9)], vec![(-1,11)]),
    ];

    for (id, a, b, expected) in sym_cases {
      test_op_sym(format!("test #{} of union",id), a, b, |x,y| x.union(y), expected);
    }
  }

  fn test_op_sym<F>(test_id: String, a: Vec<(i32,i32)>, b: Vec<(i32,i32)>, op: F, expected: Vec<(i32,i32)>) where
    F: Fn(&IntervalSet<i32>, &IntervalSet<i32>) -> IntervalSet<i32>
  {
    let a = make_interval_set(a);
    let b = make_interval_set(b);
    let expected = make_interval_set(expected);
    let result = op(&a, &b);
    assert!(result.size() == expected.size(),
      format!("{} | {:?} has a cardinality of {} instead of {}.", test_id, result, result.size(), expected.size()));
    assert!(result.interval_count() == expected.interval_count(),
      format!("{} | {:?} has {} intervals instead of {}.", test_id, result, result.interval_count(), expected.interval_count()));
    assert!(result.intervals == expected.intervals,
      format!("{} | {:?} is different from the expected value: {:?}.", test_id, result, expected));
  }
}<|endoftext|>


<commit_before>// Copyright (c) 2017 Anatoly Ikorsky
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use crate::error;
use tokio::prelude::*;

use std::future::Future;
use std::marker::Unpin;
use std::pin::Pin;
use std::{fmt, sync::Arc};

pub mod builtin;

/// Trait used to handle local infile requests.
///
/// Be aware of security issues with [LOAD DATA LOCAL](https://dev.mysql.com/doc/refman/8.0/en/load-data-local.html).
/// Using [`crate::WhiteListFsLocalInfileHandler`] is advised.
///
/// Simple handler example:
///
/// ```rust
/// # use mysql_async::prelude::*;
/// # use tokio::prelude::*;
/// # use std::env;
/// # #[tokio::main]
/// # async fn main() -> Result<(), mysql_async::error::Error> {
/// #
/// struct ExampleHandler(&'static [u8]);
///
/// impl LocalInfileHandler for ExampleHandler {
///     fn handle(&self, _: &[u8]) -> mysql_async::InfileHandlerFuture {
///         let handler = Box::new(self.0) as Box<_>;
///         Box::pin(async move { Ok(handler) })
///     }
/// }
///
/// # let database_url: String = if let Ok(url) = env::var("DATABASE_URL") {
/// #     let opts = mysql_async::Opts::from_url(&url).expect("DATABASE_URL invalid");
/// #     if opts.get_db_name().expect("a database name is required").is_empty() {
/// #         panic!("database name is empty");
/// #     }
/// #     url
/// # } else {
/// #     "mysql://root:password@127.0.0.1:3307/mysql".into()
/// # };
///
/// let mut opts = mysql_async::OptsBuilder::from_opts(&*database_url);
/// opts.local_infile_handler(Some(ExampleHandler(b"foobar")));
///
/// let pool = mysql_async::Pool::new(opts);
///
/// let conn = pool.get_conn().await?;
/// let conn = conn.drop_query("CREATE TEMPORARY TABLE tmp (a TEXT);").await?;
/// let conn = match conn.drop_query("LOAD DATA LOCAL INFILE 'baz' INTO TABLE tmp;").await {
///     Ok(conn) => conn,
///     Err(mysql_async::error::Error::Server(ref err)) if err.code == 1148 => {
///         // The used command is not allowed with this MySQL version
///         return Ok(());
///     },
///     Err(super::Error::Server(ref err)) if err.code == 3948 => {
///         // Loading local data is disabled;
///         // this must be enabled on both the client and server sides
///         return Ok(());
///     }
///     e@Err(_) => e.unwrap(),
/// };
/// let result = conn.prep_exec("SELECT * FROM tmp;", ()).await?;
/// let (_ /* conn */, result) = result.map_and_drop(|row| {
///     mysql_async::from_row::<(String,)>(row).0
/// }).await?;
///
/// assert_eq!(result.len(), 1);
/// assert_eq!(result[0], "foobar");
/// pool.disconnect().await?;
/// # Ok(())
/// # }
/// ```
///
pub trait LocalInfileHandler: Sync + Send {
    /// `file_name` is the file name in `LOAD DATA LOCAL INFILE '<file name>' INTO TABLE ...;`
    /// query.
    fn handle(&self, file_name: &[u8]) -> InfileHandlerFuture;
}

pub type InfileHandlerFuture = Pin<
    Box<
        dyn Future<Output = Result<Box<dyn AsyncRead + Send + Unpin + 'static>, error::Error>>
            + Send
            + 'static,
    >,
>;

/// Object used to wrap `T: LocalInfileHandler` inside of Opts.
#[derive(Clone)]
pub struct LocalInfileHandlerObject(Arc<dyn LocalInfileHandler>);

impl LocalInfileHandlerObject {
    pub fn new<T: LocalInfileHandler + 'static>(handler: T) -> Self {
        LocalInfileHandlerObject(Arc::new(handler))
    }

    pub fn clone_inner(&self) -> Arc<dyn LocalInfileHandler> {
        self.0.clone()
    }
}

impl PartialEq for LocalInfileHandlerObject {
    fn eq(&self, other: &LocalInfileHandlerObject) -> bool {
        self.0.as_ref() as *const dyn LocalInfileHandler
            == other.0.as_ref() as *const dyn LocalInfileHandler
    }
}

impl Eq for LocalInfileHandlerObject {}

impl fmt::Debug for LocalInfileHandlerObject {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Local infile handler object")
    }
}
<commit_msg>Fix local-infile test error in doctest<commit_after>// Copyright (c) 2017 Anatoly Ikorsky
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use crate::error;
use tokio::prelude::*;

use std::future::Future;
use std::marker::Unpin;
use std::pin::Pin;
use std::{fmt, sync::Arc};

pub mod builtin;

/// Trait used to handle local infile requests.
///
/// Be aware of security issues with [LOAD DATA LOCAL](https://dev.mysql.com/doc/refman/8.0/en/load-data-local.html).
/// Using [`crate::WhiteListFsLocalInfileHandler`] is advised.
///
/// Simple handler example:
///
/// ```rust
/// # use mysql_async::prelude::*;
/// # use tokio::prelude::*;
/// # use std::env;
/// # #[tokio::main]
/// # async fn main() -> Result<(), mysql_async::error::Error> {
/// #
/// struct ExampleHandler(&'static [u8]);
///
/// impl LocalInfileHandler for ExampleHandler {
///     fn handle(&self, _: &[u8]) -> mysql_async::InfileHandlerFuture {
///         let handler = Box::new(self.0) as Box<_>;
///         Box::pin(async move { Ok(handler) })
///     }
/// }
///
/// # let database_url: String = if let Ok(url) = env::var("DATABASE_URL") {
/// #     let opts = mysql_async::Opts::from_url(&url).expect("DATABASE_URL invalid");
/// #     if opts.get_db_name().expect("a database name is required").is_empty() {
/// #         panic!("database name is empty");
/// #     }
/// #     url
/// # } else {
/// #     "mysql://root:password@127.0.0.1:3307/mysql".into()
/// # };
///
/// let mut opts = mysql_async::OptsBuilder::from_opts(&*database_url);
/// opts.local_infile_handler(Some(ExampleHandler(b"foobar")));
///
/// let pool = mysql_async::Pool::new(opts);
///
/// let conn = pool.get_conn().await?;
/// let conn = conn.drop_query("CREATE TEMPORARY TABLE tmp (a TEXT);").await?;
/// let conn = match conn.drop_query("LOAD DATA LOCAL INFILE 'baz' INTO TABLE tmp;").await {
///     Ok(conn) => conn,
///     Err(mysql_async::error::Error::Server(ref err)) if err.code == 1148 => {
///         // The used command is not allowed with this MySQL version
///         return Ok(());
///     },
///     Err(mysql_async::error::Error::Server(ref err)) if err.code == 3948 => {
///         // Loading local data is disabled;
///         // this must be enabled on both the client and server sides
///         return Ok(());
///     }
///     e@Err(_) => e.unwrap(),
/// };
/// let result = conn.prep_exec("SELECT * FROM tmp;", ()).await?;
/// let (_ /* conn */, result) = result.map_and_drop(|row| {
///     mysql_async::from_row::<(String,)>(row).0
/// }).await?;
///
/// assert_eq!(result.len(), 1);
/// assert_eq!(result[0], "foobar");
/// pool.disconnect().await?;
/// # Ok(())
/// # }
/// ```
///
pub trait LocalInfileHandler: Sync + Send {
    /// `file_name` is the file name in `LOAD DATA LOCAL INFILE '<file name>' INTO TABLE ...;`
    /// query.
    fn handle(&self, file_name: &[u8]) -> InfileHandlerFuture;
}

pub type InfileHandlerFuture = Pin<
    Box<
        dyn Future<Output = Result<Box<dyn AsyncRead + Send + Unpin + 'static>, error::Error>>
            + Send
            + 'static,
    >,
>;

/// Object used to wrap `T: LocalInfileHandler` inside of Opts.
#[derive(Clone)]
pub struct LocalInfileHandlerObject(Arc<dyn LocalInfileHandler>);

impl LocalInfileHandlerObject {
    pub fn new<T: LocalInfileHandler + 'static>(handler: T) -> Self {
        LocalInfileHandlerObject(Arc::new(handler))
    }

    pub fn clone_inner(&self) -> Arc<dyn LocalInfileHandler> {
        self.0.clone()
    }
}

impl PartialEq for LocalInfileHandlerObject {
    fn eq(&self, other: &LocalInfileHandlerObject) -> bool {
        self.0.as_ref() as *const dyn LocalInfileHandler
            == other.0.as_ref() as *const dyn LocalInfileHandler
    }
}

impl Eq for LocalInfileHandlerObject {}

impl fmt::Debug for LocalInfileHandlerObject {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Local infile handler object")
    }
}
<|endoftext|>