<commit_before>//! Manager that is called when a seat is created or destroyed.
//! Pass a struct that implements this trait to the `Compositor` during
//! initialization.

use libc;

use std::{env, panic};
use std::process::abort;

use super::{KeyboardHandler, KeyboardWrapper, PointerHandler, PointerWrapper};
use compositor::{Compositor, COMPOSITOR_PTR};
use types::{InputDevice, Keyboard, Pointer};
use utils::safe_as_cstring;

use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{wlr_input_device, wlr_input_device_type, wlr_keyboard_set_keymap,
                  xkb_context_new, xkb_context_unref, xkb_keymap_new_from_names, xkb_rule_names};
use wlroots_sys::xkb_context_flags::*;
use wlroots_sys::xkb_keymap_compile_flags::*;

/// Different type of inputs that can be acquired.
pub enum Input {
    Keyboard(Box<KeyboardWrapper>),
    Pointer(Box<PointerWrapper>)
}

impl Input {
    pub unsafe fn input_device(&self) -> *mut wlr_input_device {
        use self::Input::*;
        match *self {
            Keyboard(ref keyboard) => keyboard.input_device().as_ptr(),
            Pointer(ref pointer) => pointer.input_device().as_ptr()
        }
    }
}

/// Handles input addition and removal.
pub trait InputManagerHandler {
    /// Callback triggered when an input device is added.
    ///
    /// # Panics
    /// Any panic in this function will cause the process to abort.
    fn input_added(&mut self, &mut Compositor, &mut InputDevice) {}

    /// Callback triggered when an input device is removed.
    fn input_removed(&mut self, &mut Compositor, &mut InputDevice) {
        // TODO
    }

    /// Callback triggered when a keyboard device is added.
    ///
    /// # Panics
    /// Any panic in this function will cause the process to abort.
    fn keyboard_added(&mut self, &mut Compositor, &mut Keyboard) -> Option<Box<KeyboardHandler>> {
        None
    }

    /// Callback triggered when a pointer device is added.
    ///
    /// # Panics
    /// Any panic in this function will cause the process to abort.
    fn pointer_added(&mut self, &mut Compositor, &mut Pointer) -> Option<Box<PointerHandler>> {
        None
    }
}

wayland_listener!(InputManager, (Vec<Input>, Box<InputManagerHandler>), [
    add_listener => add_notify: |this: &mut InputManager, data: *mut libc::c_void,| unsafe {
        let data = data as *mut wlr_input_device;
        let (ref mut inputs, ref mut manager) = this.data;
        use self::wlr_input_device_type::*;
        let mut dev = InputDevice::from_ptr(data);
        let compositor = &mut *COMPOSITOR_PTR;
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
            match dev.dev_type() {
                WLR_INPUT_DEVICE_KEYBOARD => {
                    // Boring setup that we won't make the user do
                    add_keyboard(&mut dev);
                    // Get the optional user keyboard struct, add the on_key signal
                    let mut keyboard_handle = match Keyboard::new_from_input_device(data) {
                        Some(dev) => dev,
                        None => {
                            wlr_log!(L_ERROR, "Device {:#?} was not a keyboard!", dev);
                            abort()
                        }
                    };
                    keyboard_handle.set_lock(true);
                    if let Some(keyboard_handler) = manager.keyboard_added(compositor,
                                                                           &mut keyboard_handle) {
                        keyboard_handle.set_lock(false);
                        let mut keyboard = KeyboardWrapper::new((keyboard_handle,
                                                                 keyboard_handler));
                        wl_signal_add(&mut (*dev.dev_union().keyboard).events.key as *mut _ as _,
                                    keyboard.key_listener() as *mut _ as _);
                        // Forget until we need to drop it in the destroy callback
                        inputs.push(Input::Keyboard(keyboard));
                    }
                },
                WLR_INPUT_DEVICE_POINTER => {
                    // Get the optional user pointer struct, add the signals
                    let mut pointer_handle = match Pointer::new_from_input_device(data) {
                        Some(dev) => dev,
                        None => {
                            wlr_log!(L_ERROR, "Device {:#?} was not a pointer!", dev);
                            abort()
                        }
                    };
                    pointer_handle.set_lock(true);
                    if let Some(pointer) = manager.pointer_added(compositor, &mut pointer_handle) {
                        pointer_handle.set_lock(false);
                        let mut pointer = PointerWrapper::new((pointer_handle, pointer));
                        wl_signal_add(&mut (*dev.dev_union().pointer).events.motion as *mut _ as _,
                                    pointer.motion_listener() as *mut _ as _);
                        wl_signal_add(&mut (*dev.dev_union().pointer)
                                      .events.motion_absolute as *mut _ as _,
                                    pointer.motion_absolute_listener() as *mut _ as _);
                        wl_signal_add(&mut (*dev.dev_union().pointer).events.button as *mut _ as _,
                                    pointer.button_listener() as *mut _ as _);
                        wl_signal_add(&mut (*dev.dev_union().pointer).events.axis as *mut _ as _,
                                    pointer.axis_listener() as *mut _ as _);
                        // Forget until we need to drop it in the destroy callback
                        inputs.push(Input::Pointer(pointer))
                    }
                },
                _ => unimplemented!(), // TODO FIXME We _really_ shouldn't panic here
            }
            manager.input_added(compositor, &mut dev)
        }));
        match res {
            Ok(_) => {},
            // NOTE
            // Either Wayland or wlroots does not handle failure to set up input correctly.
            // Calling wl_display_terminate does not work if input is incorrectly set up.
            //
            // Instead, execution keeps going with an eventual segfault (if lucky).
            //
            // To fix this, we abort the process if there was a panic in input setup.
            Err(_) => ::std::process::abort()
        }
    };
    remove_listener => remove_notify: |this: &mut InputManager, data: *mut libc::c_void,| unsafe {
        let data = data as *mut wlr_input_device;
        let (ref mut inputs, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        manager.input_removed(compositor, &mut InputDevice::from_ptr(data));
        // Remove user output data
        let find_index = inputs.iter()
            .position(|input| input.input_device() == data);
        if let Some(index) = find_index {
            let removed_input = inputs.remove(index);
            match removed_input {
                Input::Keyboard(mut keyboard) => {
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*keyboard.key_listener()).link as *mut _ as _);
                },
                Input::Pointer(mut pointer) => {
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*pointer.button_listener()).link as *mut _ as _);
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*pointer.motion_listener()).link as *mut _ as _);
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*pointer.motion_absolute_listener()).link as *mut _ as _);
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*pointer.axis_listener()).link as *mut _ as _);
                }
            }
        }
    };
]);

pub unsafe fn add_keyboard(dev: &mut InputDevice) {
    // Set the XKB settings
    let rules = safe_as_cstring(env::var("XKB_DEFAULT_RULES").unwrap_or("".into()));
    let model = safe_as_cstring(env::var("XKB_DEFAULT_MODEL").unwrap_or("".into()));
    let layout = safe_as_cstring(env::var("XKB_DEFAULT_LAYOUT").unwrap_or("".into()));
    let variant = safe_as_cstring(env::var("XKB_DEFAULT_VARIANT").unwrap_or("".into()));
    let options = safe_as_cstring(env::var("XKB_DEFAULT_OPTIONS").unwrap_or("".into()));
    let rules = xkb_rule_names { rules: rules.into_raw(),
                                 model: model.into_raw(),
                                 layout: layout.into_raw(),
                                 variant: variant.into_raw(),
                                 options: options.into_raw() };
    let context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
    if context.is_null() {
        wlr_log!(L_ERROR, "Failed to create XKB context");
        // NOTE We don't panic here, because we have a C call stack above us
        ::std::process::exit(1)
    }
    let xkb_map = xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
    wlr_keyboard_set_keymap(dev.dev_union().keyboard, xkb_map);
    xkb_context_unref(context);
}
<commit_msg>Small fixes<commit_after>//! Manager that is called when a seat is created or destroyed.
//! Pass a struct that implements this trait to the `Compositor` during
//! initialization.

use libc;

use std::{env, panic};
use std::process::abort;

use super::{KeyboardHandler, KeyboardWrapper, PointerHandler, PointerWrapper};
use compositor::{Compositor, COMPOSITOR_PTR};
use types::{InputDevice, Keyboard, Pointer};
use utils::safe_as_cstring;

use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{wlr_input_device, wlr_input_device_type, wlr_keyboard_set_keymap,
                  xkb_context_new, xkb_context_unref, xkb_keymap_new_from_names, xkb_rule_names};
use wlroots_sys::xkb_context_flags::*;
use wlroots_sys::xkb_keymap_compile_flags::*;

/// Different type of inputs that can be acquired.
pub enum Input {
    Keyboard(Box<KeyboardWrapper>),
    Pointer(Box<PointerWrapper>)
}

impl Input {
    pub unsafe fn input_device(&self) -> *mut wlr_input_device {
        use self::Input::*;
        match *self {
            Keyboard(ref keyboard) => keyboard.input_device().as_ptr(),
            Pointer(ref pointer) => pointer.input_device().as_ptr()
        }
    }
}

/// Handles input addition and removal.
pub trait InputManagerHandler {
    /// Callback triggered when an input device is added.
    ///
    /// # Panics
    /// Any panic in this function will cause the process to abort.
    fn input_added(&mut self, &mut Compositor, &mut InputDevice) {}

    /// Callback triggered when an input device is removed.
    fn input_removed(&mut self, &mut Compositor, &mut InputDevice) {
        // TODO
    }

    /// Callback triggered when a keyboard device is added.
    ///
    /// # Panics
    /// Any panic in this function will cause the process to abort.
    fn keyboard_added(&mut self, &mut Compositor, &mut Keyboard) -> Option<Box<KeyboardHandler>> {
        None
    }

    /// Callback triggered when a pointer device is added.
    ///
    /// # Panics
    /// Any panic in this function will cause the process to abort.
    fn pointer_added(&mut self, &mut Compositor, &mut Pointer) -> Option<Box<PointerHandler>> {
        None
    }
}

wayland_listener!(InputManager, (Vec<Input>, Box<InputManagerHandler>), [
    add_listener => add_notify: |this: &mut InputManager, data: *mut libc::c_void,| unsafe {
        let data = data as *mut wlr_input_device;
        let (ref mut inputs, ref mut manager) = this.data;
        use self::wlr_input_device_type::*;
        let mut dev = InputDevice::from_ptr(data);
        let compositor = &mut *COMPOSITOR_PTR;
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
            match dev.dev_type() {
                WLR_INPUT_DEVICE_KEYBOARD => {
                    // Boring setup that we won't make the user do
                    add_keyboard(&mut dev);
                    // Get the optional user keyboard struct, add the on_key signal
                    let mut keyboard_handle = match Keyboard::new_from_input_device(data) {
                        Some(dev) => dev,
                        None => {
                            wlr_log!(L_ERROR, "Device {:#?} was not a keyboard!", dev);
                            abort()
                        }
                    };
                    keyboard_handle.set_lock(true);
                    if let Some(keyboard_handler) = manager.keyboard_added(compositor,
                                                                           &mut keyboard_handle) {
                        keyboard_handle.set_lock(false);
                        let mut keyboard = KeyboardWrapper::new((keyboard_handle,
                                                                 keyboard_handler));
                        wl_signal_add(&mut (*dev.dev_union().keyboard).events.key as *mut _ as _,
                                    keyboard.key_listener() as *mut _ as _);
                        // Forget until we need to drop it in the destroy callback
                        inputs.push(Input::Keyboard(keyboard));
                    }
                },
                WLR_INPUT_DEVICE_POINTER => {
                    // Get the optional user pointer struct, add the signals
                    let mut pointer_handle = match Pointer::new_from_input_device(data) {
                        Some(dev) => dev,
                        None => {
                            wlr_log!(L_ERROR, "Device {:#?} was not a pointer!", dev);
                            abort()
                        }
                    };
                    pointer_handle.set_lock(true);
                    if let Some(pointer) = manager.pointer_added(compositor, &mut pointer_handle) {
                        pointer_handle.set_lock(false);
                        let mut pointer = PointerWrapper::new((pointer_handle, pointer));
                        wl_signal_add(&mut (*dev.dev_union().pointer).events.motion as *mut _ as _,
                                    pointer.motion_listener() as *mut _ as _);
                        wl_signal_add(&mut (*dev.dev_union().pointer)
                                      .events.motion_absolute as *mut _ as _,
                                    pointer.motion_absolute_listener() as *mut _ as _);
                        wl_signal_add(&mut (*dev.dev_union().pointer).events.button as *mut _ as _,
                                    pointer.button_listener() as *mut _ as _);
                        wl_signal_add(&mut (*dev.dev_union().pointer).events.axis as *mut _ as _,
                                    pointer.axis_listener() as *mut _ as _);
                        // Forget until we need to drop it in the destroy callback
                        inputs.push(Input::Pointer(pointer))
                    }
                },
                _ => unimplemented!(),
            }
            manager.input_added(compositor, &mut dev)
        }));
        match res {
            Ok(_) => {},
            // NOTE
            // Either Wayland or wlroots does not handle failure to set up input correctly.
            // Calling wl_display_terminate does not work if input is incorrectly set up.
            //
            // Instead, execution keeps going with an eventual segfault (if lucky).
            //
            // To fix this, we abort the process if there was a panic in input setup.
            Err(_) => abort()
        }
    };
    remove_listener => remove_notify: |this: &mut InputManager, data: *mut libc::c_void,| unsafe {
        let data = data as *mut wlr_input_device;
        let (ref mut inputs, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        manager.input_removed(compositor, &mut InputDevice::from_ptr(data));
        // Remove user output data
        let find_index = inputs.iter()
            .position(|input| input.input_device() == data);
        if let Some(index) = find_index {
            let removed_input = inputs.remove(index);
            match removed_input {
                Input::Keyboard(mut keyboard) => {
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*keyboard.key_listener()).link as *mut _ as _);
                },
                Input::Pointer(mut pointer) => {
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*pointer.button_listener()).link as *mut _ as _);
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*pointer.motion_listener()).link as *mut _ as _);
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*pointer.motion_absolute_listener()).link as *mut _ as _);
                    ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                  wl_list_remove,
                                  &mut (*pointer.axis_listener()).link as *mut _ as _);
                }
            }
        }
    };
]);

pub unsafe fn add_keyboard(dev: &mut InputDevice) {
    // Set the XKB settings
    let rules = safe_as_cstring(env::var("XKB_DEFAULT_RULES").unwrap_or("".into()));
    let model = safe_as_cstring(env::var("XKB_DEFAULT_MODEL").unwrap_or("".into()));
    let layout = safe_as_cstring(env::var("XKB_DEFAULT_LAYOUT").unwrap_or("".into()));
    let variant = safe_as_cstring(env::var("XKB_DEFAULT_VARIANT").unwrap_or("".into()));
    let options = safe_as_cstring(env::var("XKB_DEFAULT_OPTIONS").unwrap_or("".into()));
    let rules = xkb_rule_names { rules: rules.into_raw(),
                                 model: model.into_raw(),
                                 layout: layout.into_raw(),
                                 variant: variant.into_raw(),
                                 options: options.into_raw() };
    let context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
    if context.is_null() {
        wlr_log!(L_ERROR, "Failed to create XKB context");
        // NOTE We don't panic here, because we have a C call stack above us
        ::std::process::exit(1)
    }
    let xkb_map = xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
    wlr_keyboard_set_keymap(dev.dev_union().keyboard, xkb_map);
    xkb_context_unref(context);
}
<|endoftext|>


<commit_before>use crate::source_map::SourceMap;
use crate::{BytePos, SourceFile, SpanData};
use rustc_data_structures::sync::Lrc;
use std::ops::Range;

#[derive(Clone)]
struct CacheEntry {
    time_stamp: usize,
    line_number: usize,
    // The line's byte position range in the `SourceMap`. This range will fail to contain a valid
    // position in certain edge cases. Spans often start/end one past something, and when that
    // something is the last character of a file (this can happen when a file doesn't end in a
    // newline, for example), we'd still like for the position to be considered within the last
    // line. However, it isn't according to the exclusive upper bound of this range. We cannot
    // change the upper bound to be inclusive, because for most lines, the upper bound is the same
    // as the lower bound of the next line, so there would be an ambiguity.
    //
    // Since the containment aspect of this range is only used to see whether or not the cache
    // entry contains a position, the only ramification of the above is that we will get cache
    // misses for these rare positions. A line lookup for the position via `SourceMap::lookup_line`
    // after a cache miss will produce the last line number, as desired.
    line: Range<BytePos>,
    file: Lrc<SourceFile>,
    file_index: usize,
}

impl CacheEntry {
    #[inline]
    fn update(
        &mut self,
        new_file_and_idx: Option<(Lrc<SourceFile>, usize)>,
        pos: BytePos,
        time_stamp: usize,
    ) {
        if let Some((file, file_idx)) = new_file_and_idx {
            self.file = file;
            self.file_index = file_idx;
        }

        let line_index = self.file.lookup_line(pos).unwrap();
        let line_bounds = self.file.line_bounds(line_index);
        self.line_number = line_index + 1;
        self.line = line_bounds;
        self.touch(time_stamp);
    }

    #[inline]
    fn touch(&mut self, time_stamp: usize) {
        self.time_stamp = time_stamp;
    }
}

#[derive(Clone)]
pub struct CachingSourceMapView<'sm> {
    source_map: &'sm SourceMap,
    line_cache: [CacheEntry; 3],
    time_stamp: usize,
}

impl<'sm> CachingSourceMapView<'sm> {
    pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> {
        let files = source_map.files();
        let first_file = files[0].clone();
        let entry = CacheEntry {
            time_stamp: 0,
            line_number: 0,
            line: BytePos(0)..BytePos(0),
            file: first_file,
            file_index: 0,
        };

        CachingSourceMapView {
            source_map,
            line_cache: [entry.clone(), entry.clone(), entry],
            time_stamp: 0,
        }
    }

    pub fn byte_pos_to_line_and_col(
        &mut self,
        pos: BytePos,
    ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
        self.time_stamp += 1;

        // Check if the position is in one of the cached lines
        let cache_idx = self.cache_entry_index(pos);
        if cache_idx != -1 {
            let cache_entry = &mut self.line_cache[cache_idx as usize];
            cache_entry.touch(self.time_stamp);

            return Some((
                cache_entry.file.clone(),
                cache_entry.line_number,
                pos - cache_entry.line.start,
            ));
        }

        // No cache hit ...
        let oldest = self.oldest_cache_entry_index();

        // If the entry doesn't point to the correct file, get the new file and index.
        let new_file_and_idx = if !file_contains(&self.line_cache[oldest].file, pos) {
            Some(self.file_for_position(pos)?)
        } else {
            None
        };

        let cache_entry = &mut self.line_cache[oldest];
        cache_entry.update(new_file_and_idx, pos, self.time_stamp);

        Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
    }

    pub fn span_data_to_lines_and_cols(
        &mut self,
        span_data: &SpanData,
    ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
        self.time_stamp += 1;

        // Check if lo and hi are in the cached lines.
        let lo_cache_idx = self.cache_entry_index(span_data.lo);
        let hi_cache_idx = self.cache_entry_index(span_data.hi);

        if lo_cache_idx != -1 && hi_cache_idx != -1 {
            // Cache hit for span lo and hi. Check if they belong to the same file.
            let result = {
                let lo = &self.line_cache[lo_cache_idx as usize];
                let hi = &self.line_cache[hi_cache_idx as usize];

                if lo.file_index != hi.file_index {
                    return None;
                }

                (
                    lo.file.clone(),
                    lo.line_number,
                    span_data.lo - lo.line.start,
                    hi.line_number,
                    span_data.hi - hi.line.start,
                )
            };

            self.line_cache[lo_cache_idx as usize].touch(self.time_stamp);
            self.line_cache[hi_cache_idx as usize].touch(self.time_stamp);

            return Some(result);
        }

        // No cache hit or cache hit for only one of span lo and hi.
        let oldest = if lo_cache_idx != -1 || hi_cache_idx != -1 {
            let avoid_idx = if lo_cache_idx != -1 { lo_cache_idx } else { hi_cache_idx };
            self.oldest_cache_entry_index_avoid(avoid_idx as usize)
        } else {
            self.oldest_cache_entry_index()
        };

        // If the entry doesn't point to the correct file, get the new file and index.
        // Return early if the file containing beginning of span doesn't contain end of span.
        let new_file_and_idx = if !file_contains(&self.line_cache[oldest].file, span_data.lo) {
            let new_file_and_idx = self.file_for_position(span_data.lo)?;
            if !file_contains(&new_file_and_idx.0, span_data.hi) {
                return None;
            }

            Some(new_file_and_idx)
        } else {
            let file = &self.line_cache[oldest].file;
            if !file_contains(&file, span_data.hi) {
                return None;
            }

            None
        };

        // Update the cache entries.
        let (lo_idx, hi_idx) = match (lo_cache_idx, hi_cache_idx) {
            // Oldest cache entry is for span_data.lo line.
            (-1, -1) => {
                let lo = &mut self.line_cache[oldest];
                lo.update(new_file_and_idx, span_data.lo, self.time_stamp);

                if !lo.line.contains(&span_data.hi) {
                    let new_file_and_idx = Some((lo.file.clone(), lo.file_index));
                    let next_oldest = self.oldest_cache_entry_index_avoid(oldest);
                    let hi = &mut self.line_cache[next_oldest];
                    hi.update(new_file_and_idx, span_data.hi, self.time_stamp);
                    (oldest, next_oldest)
                } else {
                    (oldest, oldest)
                }
            }
            // Oldest cache entry is for span_data.lo line.
            (-1, _) => {
                let lo = &mut self.line_cache[oldest];
                lo.update(new_file_and_idx, span_data.lo, self.time_stamp);
                let hi = &mut self.line_cache[hi_cache_idx as usize];
                hi.touch(self.time_stamp);
                (oldest, hi_cache_idx as usize)
            }
            // Oldest cache entry is for span_data.hi line.
            (_, -1) => {
                let hi = &mut self.line_cache[oldest];
                hi.update(new_file_and_idx, span_data.hi, self.time_stamp);
                let lo = &mut self.line_cache[lo_cache_idx as usize];
                lo.touch(self.time_stamp);
                (lo_cache_idx as usize, oldest)
            }
            _ => {
                panic!();
            }
        };

        let lo = &self.line_cache[lo_idx];
        let hi = &self.line_cache[hi_idx];

        // Span lo and hi may equal line end when last line doesn't
        // end in newline, hence the inclusive upper bounds below.
        debug_assert!(span_data.lo >= lo.line.start);
        debug_assert!(span_data.lo <= lo.line.end);
        debug_assert!(span_data.hi >= hi.line.start);
        debug_assert!(span_data.hi <= hi.line.end);
        debug_assert!(lo.file.contains(span_data.lo));
        debug_assert!(lo.file.contains(span_data.hi));
        debug_assert_eq!(lo.file_index, hi.file_index);

        Some((
            lo.file.clone(),
            lo.line_number,
            span_data.lo - lo.line.start,
            hi.line_number,
            span_data.hi - hi.line.start,
        ))
    }

    fn cache_entry_index(&self, pos: BytePos) -> isize {
        for (idx, cache_entry) in self.line_cache.iter().enumerate() {
            if cache_entry.line.contains(&pos) {
                return idx as isize;
            }
        }

        -1
    }

    fn oldest_cache_entry_index(&self) -> usize {
        let mut oldest = 0;

        for idx in 1..self.line_cache.len() {
            if self.line_cache[idx].time_stamp < self.line_cache[oldest].time_stamp {
                oldest = idx;
            }
        }

        oldest
    }

    fn oldest_cache_entry_index_avoid(&self, avoid_idx: usize) -> usize {
        let mut oldest = if avoid_idx != 0 { 0 } else { 1 };

        for idx in 0..self.line_cache.len() {
            if idx != avoid_idx
                && self.line_cache[idx].time_stamp < self.line_cache[oldest].time_stamp
            {
                oldest = idx;
            }
        }

        oldest
    }

    fn file_for_position(&self, pos: BytePos) -> Option<(Lrc<SourceFile>, usize)> {
        if !self.source_map.files().is_empty() {
            let file_idx = self.source_map.lookup_source_file_idx(pos);
            let file = &self.source_map.files()[file_idx];

            if file_contains(file, pos) {
                return Some((file.clone(), file_idx));
            }
        }

        None
    }
}

#[inline]
fn file_contains(file: &SourceFile, pos: BytePos) -> bool {
    // `SourceMap::lookup_source_file_idx` and `SourceFile::contains` both consider the position
    // one past the end of a file to belong to it. Normally, that's what we want. But for the
    // purposes of converting a byte position to a line and column number, we can't come up with a
    // line and column number if the file is empty, because an empty file doesn't contain any
    // lines. So for our purposes, we don't consider empty files to contain any byte position.
    file.contains(pos) && !file.is_empty()
}
<commit_msg>Convert `debug_assert` to `assert` in `CachingSourceMapView`<commit_after>use crate::source_map::SourceMap;
use crate::{BytePos, SourceFile, SpanData};
use rustc_data_structures::sync::Lrc;
use std::ops::Range;

#[derive(Clone)]
struct CacheEntry {
    time_stamp: usize,
    line_number: usize,
    // The line's byte position range in the `SourceMap`. This range will fail to contain a valid
    // position in certain edge cases. Spans often start/end one past something, and when that
    // something is the last character of a file (this can happen when a file doesn't end in a
    // newline, for example), we'd still like for the position to be considered within the last
    // line. However, it isn't according to the exclusive upper bound of this range. We cannot
    // change the upper bound to be inclusive, because for most lines, the upper bound is the same
    // as the lower bound of the next line, so there would be an ambiguity.
    //
    // Since the containment aspect of this range is only used to see whether or not the cache
    // entry contains a position, the only ramification of the above is that we will get cache
    // misses for these rare positions. A line lookup for the position via `SourceMap::lookup_line`
    // after a cache miss will produce the last line number, as desired.
    line: Range<BytePos>,
    file: Lrc<SourceFile>,
    file_index: usize,
}

impl CacheEntry {
    #[inline]
    fn update(
        &mut self,
        new_file_and_idx: Option<(Lrc<SourceFile>, usize)>,
        pos: BytePos,
        time_stamp: usize,
    ) {
        if let Some((file, file_idx)) = new_file_and_idx {
            self.file = file;
            self.file_index = file_idx;
        }

        let line_index = self.file.lookup_line(pos).unwrap();
        let line_bounds = self.file.line_bounds(line_index);
        self.line_number = line_index + 1;
        self.line = line_bounds;
        self.touch(time_stamp);
    }

    #[inline]
    fn touch(&mut self, time_stamp: usize) {
        self.time_stamp = time_stamp;
    }
}

#[derive(Clone)]
pub struct CachingSourceMapView<'sm> {
    source_map: &'sm SourceMap,
    line_cache: [CacheEntry; 3],
    time_stamp: usize,
}

impl<'sm> CachingSourceMapView<'sm> {
    pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> {
        let files = source_map.files();
        let first_file = files[0].clone();
        let entry = CacheEntry {
            time_stamp: 0,
            line_number: 0,
            line: BytePos(0)..BytePos(0),
            file: first_file,
            file_index: 0,
        };

        CachingSourceMapView {
            source_map,
            line_cache: [entry.clone(), entry.clone(), entry],
            time_stamp: 0,
        }
    }

    pub fn byte_pos_to_line_and_col(
        &mut self,
        pos: BytePos,
    ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
        self.time_stamp += 1;

        // Check if the position is in one of the cached lines
        let cache_idx = self.cache_entry_index(pos);
        if cache_idx != -1 {
            let cache_entry = &mut self.line_cache[cache_idx as usize];
            cache_entry.touch(self.time_stamp);

            return Some((
                cache_entry.file.clone(),
                cache_entry.line_number,
                pos - cache_entry.line.start,
            ));
        }

        // No cache hit ...
        let oldest = self.oldest_cache_entry_index();

        // If the entry doesn't point to the correct file, get the new file and index.
        let new_file_and_idx = if !file_contains(&self.line_cache[oldest].file, pos) {
            Some(self.file_for_position(pos)?)
        } else {
            None
        };

        let cache_entry = &mut self.line_cache[oldest];
        cache_entry.update(new_file_and_idx, pos, self.time_stamp);

        Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
    }

    pub fn span_data_to_lines_and_cols(
        &mut self,
        span_data: &SpanData,
    ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
        self.time_stamp += 1;

        // Check if lo and hi are in the cached lines.
        let lo_cache_idx = self.cache_entry_index(span_data.lo);
        let hi_cache_idx = self.cache_entry_index(span_data.hi);

        if lo_cache_idx != -1 && hi_cache_idx != -1 {
            // Cache hit for span lo and hi. Check if they belong to the same file.
            let result = {
                let lo = &self.line_cache[lo_cache_idx as usize];
                let hi = &self.line_cache[hi_cache_idx as usize];

                if lo.file_index != hi.file_index {
                    return None;
                }

                (
                    lo.file.clone(),
                    lo.line_number,
                    span_data.lo - lo.line.start,
                    hi.line_number,
                    span_data.hi - hi.line.start,
                )
            };

            self.line_cache[lo_cache_idx as usize].touch(self.time_stamp);
            self.line_cache[hi_cache_idx as usize].touch(self.time_stamp);

            return Some(result);
        }

        // No cache hit or cache hit for only one of span lo and hi.
        let oldest = if lo_cache_idx != -1 || hi_cache_idx != -1 {
            let avoid_idx = if lo_cache_idx != -1 { lo_cache_idx } else { hi_cache_idx };
            self.oldest_cache_entry_index_avoid(avoid_idx as usize)
        } else {
            self.oldest_cache_entry_index()
        };

        // If the entry doesn't point to the correct file, get the new file and index.
        // Return early if the file containing beginning of span doesn't contain end of span.
        let new_file_and_idx = if !file_contains(&self.line_cache[oldest].file, span_data.lo) {
            let new_file_and_idx = self.file_for_position(span_data.lo)?;
            if !file_contains(&new_file_and_idx.0, span_data.hi) {
                return None;
            }

            Some(new_file_and_idx)
        } else {
            let file = &self.line_cache[oldest].file;
            if !file_contains(&file, span_data.hi) {
                return None;
            }

            None
        };

        // Update the cache entries.
        let (lo_idx, hi_idx) = match (lo_cache_idx, hi_cache_idx) {
            // Oldest cache entry is for span_data.lo line.
            (-1, -1) => {
                let lo = &mut self.line_cache[oldest];
                lo.update(new_file_and_idx, span_data.lo, self.time_stamp);

                if !lo.line.contains(&span_data.hi) {
                    let new_file_and_idx = Some((lo.file.clone(), lo.file_index));
                    let next_oldest = self.oldest_cache_entry_index_avoid(oldest);
                    let hi = &mut self.line_cache[next_oldest];
                    hi.update(new_file_and_idx, span_data.hi, self.time_stamp);
                    (oldest, next_oldest)
                } else {
                    (oldest, oldest)
                }
            }
            // Oldest cache entry is for span_data.lo line.
            (-1, _) => {
                let lo = &mut self.line_cache[oldest];
                lo.update(new_file_and_idx, span_data.lo, self.time_stamp);
                let hi = &mut self.line_cache[hi_cache_idx as usize];
                hi.touch(self.time_stamp);
                (oldest, hi_cache_idx as usize)
            }
            // Oldest cache entry is for span_data.hi line.
            (_, -1) => {
                let hi = &mut self.line_cache[oldest];
                hi.update(new_file_and_idx, span_data.hi, self.time_stamp);
                let lo = &mut self.line_cache[lo_cache_idx as usize];
                lo.touch(self.time_stamp);
                (lo_cache_idx as usize, oldest)
            }
            _ => {
                panic!();
            }
        };

        let lo = &self.line_cache[lo_idx];
        let hi = &self.line_cache[hi_idx];

        // Span lo and hi may equal line end when last line doesn't
        // end in newline, hence the inclusive upper bounds below.
        assert!(span_data.lo >= lo.line.start);
        assert!(span_data.lo <= lo.line.end);
        assert!(span_data.hi >= hi.line.start);
        assert!(span_data.hi <= hi.line.end);
        assert!(lo.file.contains(span_data.lo));
        assert!(lo.file.contains(span_data.hi));
        assert_eq!(lo.file_index, hi.file_index);

        Some((
            lo.file.clone(),
            lo.line_number,
            span_data.lo - lo.line.start,
            hi.line_number,
            span_data.hi - hi.line.start,
        ))
    }

    fn cache_entry_index(&self, pos: BytePos) -> isize {
        for (idx, cache_entry) in self.line_cache.iter().enumerate() {
            if cache_entry.line.contains(&pos) {
                return idx as isize;
            }
        }

        -1
    }

    fn oldest_cache_entry_index(&self) -> usize {
        let mut oldest = 0;

        for idx in 1..self.line_cache.len() {
            if self.line_cache[idx].time_stamp < self.line_cache[oldest].time_stamp {
                oldest = idx;
            }
        }

        oldest
    }

    fn oldest_cache_entry_index_avoid(&self, avoid_idx: usize) -> usize {
        let mut oldest = if avoid_idx != 0 { 0 } else { 1 };

        for idx in 0..self.line_cache.len() {
            if idx != avoid_idx
                && self.line_cache[idx].time_stamp < self.line_cache[oldest].time_stamp
            {
                oldest = idx;
            }
        }

        oldest
    }

    fn file_for_position(&self, pos: BytePos) -> Option<(Lrc<SourceFile>, usize)> {
        if !self.source_map.files().is_empty() {
            let file_idx = self.source_map.lookup_source_file_idx(pos);
            let file = &self.source_map.files()[file_idx];

            if file_contains(file, pos) {
                return Some((file.clone(), file_idx));
            }
        }

        None
    }
}

#[inline]
fn file_contains(file: &SourceFile, pos: BytePos) -> bool {
    // `SourceMap::lookup_source_file_idx` and `SourceFile::contains` both consider the position
    // one past the end of a file to belong to it. Normally, that's what we want. But for the
    // purposes of converting a byte position to a line and column number, we can't come up with a
    // line and column number if the file is empty, because an empty file doesn't contain any
    // lines. So for our purposes, we don't consider empty files to contain any byte position.
    file.contains(pos) && !file.is_empty()
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::dsl::AsExprOf;
use crate::expression::subselect::ValidSubselect;
use crate::expression::*;
use crate::insertable::Insertable;
use crate::query_builder::distinct_clause::DistinctClause;
use crate::query_builder::group_by_clause::GroupByClause;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::limit_clause::LimitClause;
use crate::query_builder::offset_clause::OffsetClause;
use crate::query_builder::order_clause::OrderClause;
use crate::query_builder::where_clause::*;
use crate::query_builder::*;
use crate::query_dsl::methods::*;
use crate::query_dsl::*;
use crate::query_source::joins::*;
use crate::query_source::{QuerySource, Table};
use crate::result::QueryResult;
use crate::sql_types::{BigInt, Bool, NotNull, Nullable};

#[allow(missing_debug_implementations)]
pub struct BoxedSelectStatement<'a, ST, QS, DB> {
    select: Box<dyn QueryFragment<DB> + Send + 'a>,
    from: QS,
    distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
    where_clause: BoxedWhereClause<'a, DB>,
    order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
    limit: Box<dyn QueryFragment<DB> + Send + 'a>,
    offset: Box<dyn QueryFragment<DB> + Send + 'a>,
    group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    _marker: PhantomData<ST>,
}

impl<'a, ST, QS, DB> BoxedSelectStatement<'a, ST, QS, DB> {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        select: Box<dyn QueryFragment<DB> + Send + 'a>,
        from: QS,
        distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
        where_clause: BoxedWhereClause<'a, DB>,
        order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
        limit: Box<dyn QueryFragment<DB> + Send + 'a>,
        offset: Box<dyn QueryFragment<DB> + Send + 'a>,
        group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    ) -> Self {
        BoxedSelectStatement {
            select: select,
            from: from,
            distinct: distinct,
            where_clause: where_clause,
            order: order,
            limit: limit,
            offset: offset,
            group_by: group_by,
            _marker: PhantomData,
        }
    }
}

impl<'a, ST, QS, DB> Query for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, DB> SelectQuery for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, QS2, DB> ValidSubselect<QS2> for BoxedSelectStatement<'a, ST, QS, DB> where
    Self: Query<SqlType = ST>
{
}

impl<'a, ST, QS, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    QS: QuerySource,
    QS::FromClause: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        out.push_sql(" FROM ");
        self.from.from_clause().walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;

        if let Some(ref order) = self.order {
            out.push_sql(" ORDER BY ");
            order.walk_ast(out.reborrow())?;
        }

        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, (), DB>
where
    DB: Backend,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, QS, DB> QueryId for BoxedSelectStatement<'a, ST, QS, DB> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, ST, QS, DB, Rhs, Kind, On> InternalJoinDsl<Rhs, Kind, On>
    for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>: AsQuery,
{
    type Output = BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>;

    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
        BoxedSelectStatement::new(
            self.select,
            Join::new(self.from, rhs, kind).on(on),
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB> DistinctDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    DistinctClause: QueryFragment<DB>,
{
    type Output = Self;

    fn distinct(mut self) -> Self::Output {
        self.distinct = Box::new(DistinctClause);
        self
    }
}

impl<'a, ST, QS, DB, Selection> SelectDsl<Selection> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Selection: SelectableExpression<QS> + QueryFragment<DB> + Send + 'a,
{
    type Output = BoxedSelectStatement<'a, Selection::SqlType, QS, DB>;

    fn select(self, selection: Selection) -> Self::Output {
        BoxedSelectStatement::new(
            Box::new(selection),
            self.from,
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB, Predicate> FilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.and(predicate);
        self
    }
}

impl<'a, ST, QS, DB, Predicate> OrFilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn or_filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.or(predicate);
        self
    }
}

impl<'a, ST, QS, DB> LimitDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn limit(mut self, limit: i64) -> Self::Output {
        self.limit = Box::new(LimitClause(limit.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB> OffsetDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn offset(mut self, offset: i64) -> Self::Output {
        self.offset = Box::new(OffsetClause(offset.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB, Order> OrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn order(mut self, order: Order) -> Self::Output {
        self.order = OrderClause(order).into();
        self
    }
}

impl<'a, ST, QS, DB, Order> ThenOrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend + 'a,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn then_order_by(mut self, order: Order) -> Self::Output {
        self.order = match self.order {
            Some(old) => Some(Box::new((old, order))),
            None => Some(Box::new(order)),
        };
        self
    }
}

impl<'a, ST, QS, DB, Expr> GroupByDsl<Expr> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Expr: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
    Self: Query,
{
    type Output = Self;

    fn group_by(mut self, group_by: Expr) -> Self::Output {
        self.group_by = Box::new(GroupByClause(group_by));
        self
    }
}

// FIXME: Should we disable joining when `.group_by` has been called? Are there
// any other query methods where a join no longer has the same semantics as
// joining on just the table?
impl<'a, ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedSelectStatement<'a, ST, QS, DB>
where
    QS: JoinTo<Rhs>,
{
    type FromClause = QS::FromClause;
    type OnClause = QS::OnClause;

    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
        QS::join_target(rhs)
    }
}

impl<'a, ST, QS, DB> QueryDsl for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, Conn> RunQueryDsl<Conn> for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, T> Insertable<T> for BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, 'b, ST, QS, DB, T> Insertable<T> for &'b BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, ST, QS, DB> SelectNullableDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    ST: NotNull,
{
    type Output = BoxedSelectStatement<'a, Nullable<ST>, QS, DB>;

    fn nullable(self) -> Self::Output {
        BoxedSelectStatement {
            select: self.select,
            from: self.from,
            distinct: self.distinct,
            where_clause: self.where_clause,
            order: self.order,
            limit: self.limit,
            offset: self.offset,
            group_by: self.group_by,
            _marker: PhantomData,
        }
    }
}
<commit_msg>Run rustfmt<commit_after>use std::marker::PhantomData;

use crate::backend::Backend;
use crate::dsl::AsExprOf;
use crate::expression::subselect::ValidSubselect;
use crate::expression::*;
use crate::insertable::Insertable;
use crate::query_builder::distinct_clause::DistinctClause;
use crate::query_builder::group_by_clause::GroupByClause;
use crate::query_builder::insert_statement::InsertFromSelect;
use crate::query_builder::limit_clause::LimitClause;
use crate::query_builder::offset_clause::OffsetClause;
use crate::query_builder::order_clause::OrderClause;
use crate::query_builder::where_clause::*;
use crate::query_builder::*;
use crate::query_dsl::methods::*;
use crate::query_dsl::*;
use crate::query_source::joins::*;
use crate::query_source::{QuerySource, Table};
use crate::result::QueryResult;
use crate::sql_types::{BigInt, Bool, NotNull, Nullable};

#[allow(missing_debug_implementations)]
pub struct BoxedSelectStatement<'a, ST, QS, DB> {
    select: Box<dyn QueryFragment<DB> + Send + 'a>,
    from: QS,
    distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
    where_clause: BoxedWhereClause<'a, DB>,
    order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
    limit: Box<dyn QueryFragment<DB> + Send + 'a>,
    offset: Box<dyn QueryFragment<DB> + Send + 'a>,
    group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
    _marker: PhantomData<ST>,
}

impl<'a, ST, QS, DB> BoxedSelectStatement<'a, ST, QS, DB> {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        select: Box<dyn QueryFragment<DB> + Send + 'a>,
        from: QS,
        distinct: Box<dyn QueryFragment<DB> + Send + 'a>,
        where_clause: BoxedWhereClause<'a, DB>,
<<<<<<< HEAD
        order: Option<Box<dyn QueryFragment<DB> + Send + 'a>>,
        limit: Box<dyn QueryFragment<DB> + Send + 'a>,
        offset: Box<dyn QueryFragment<DB> + Send + 'a>,
        group_by: Box<dyn QueryFragment<DB> + Send + 'a>,
=======
        order: Option<Box<QueryFragment<DB> + Send + 'a>>,
        limit: Box<QueryFragment<DB> + Send + 'a>,
        offset: Box<QueryFragment<DB> + Send + 'a>,
        group_by: Box<QueryFragment<DB> + Send + 'a>,
>>>>>>> Run rustfmt
    ) -> Self {
        BoxedSelectStatement {
            select: select,
            from: from,
            distinct: distinct,
            where_clause: where_clause,
            order: order,
            limit: limit,
            offset: offset,
            group_by: group_by,
            _marker: PhantomData,
        }
    }
}

impl<'a, ST, QS, DB> Query for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, DB> SelectQuery for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
{
    type SqlType = ST;
}

impl<'a, ST, QS, QS2, DB> ValidSubselect<QS2> for BoxedSelectStatement<'a, ST, QS, DB> where
    Self: Query<SqlType = ST>
{
}

impl<'a, ST, QS, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    QS: QuerySource,
    QS::FromClause: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        out.push_sql(" FROM ");
        self.from.from_clause().walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;

        if let Some(ref order) = self.order {
            out.push_sql(" ORDER BY ");
            order.walk_ast(out.reborrow())?;
        }

        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, DB> QueryFragment<DB> for BoxedSelectStatement<'a, ST, (), DB>
where
    DB: Backend,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<'a, ST, QS, DB> QueryId for BoxedSelectStatement<'a, ST, QS, DB> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<'a, ST, QS, DB, Rhs, Kind, On> InternalJoinDsl<Rhs, Kind, On>
    for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>: AsQuery,
{
    type Output = BoxedSelectStatement<'a, ST, JoinOn<Join<QS, Rhs, Kind>, On>, DB>;

    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
        BoxedSelectStatement::new(
            self.select,
            Join::new(self.from, rhs, kind).on(on),
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB> DistinctDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    DistinctClause: QueryFragment<DB>,
{
    type Output = Self;

    fn distinct(mut self) -> Self::Output {
        self.distinct = Box::new(DistinctClause);
        self
    }
}

impl<'a, ST, QS, DB, Selection> SelectDsl<Selection> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Selection: SelectableExpression<QS> + QueryFragment<DB> + Send + 'a,
{
    type Output = BoxedSelectStatement<'a, Selection::SqlType, QS, DB>;

    fn select(self, selection: Selection) -> Self::Output {
        BoxedSelectStatement::new(
            Box::new(selection),
            self.from,
            self.distinct,
            self.where_clause,
            self.order,
            self.limit,
            self.offset,
            self.group_by,
        )
    }
}

impl<'a, ST, QS, DB, Predicate> FilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.and(predicate);
        self
    }
}

impl<'a, ST, QS, DB, Predicate> OrFilterDsl<Predicate> for BoxedSelectStatement<'a, ST, QS, DB>
where
    BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
    Predicate: AppearsOnTable<QS, SqlType = Bool> + NonAggregate,
{
    type Output = Self;

    fn or_filter(mut self, predicate: Predicate) -> Self::Output {
        self.where_clause = self.where_clause.or(predicate);
        self
    }
}

impl<'a, ST, QS, DB> LimitDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn limit(mut self, limit: i64) -> Self::Output {
        self.limit = Box::new(LimitClause(limit.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB> OffsetDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
{
    type Output = Self;

    fn offset(mut self, offset: i64) -> Self::Output {
        self.offset = Box::new(OffsetClause(offset.into_sql::<BigInt>()));
        self
    }
}

impl<'a, ST, QS, DB, Order> OrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn order(mut self, order: Order) -> Self::Output {
        self.order = OrderClause(order).into();
        self
    }
}

impl<'a, ST, QS, DB, Order> ThenOrderDsl<Order> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend + 'a,
    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
{
    type Output = Self;

    fn then_order_by(mut self, order: Order) -> Self::Output {
        self.order = match self.order {
            Some(old) => Some(Box::new((old, order))),
            None => Some(Box::new(order)),
        };
        self
    }
}

impl<'a, ST, QS, DB, Expr> GroupByDsl<Expr> for BoxedSelectStatement<'a, ST, QS, DB>
where
    DB: Backend,
    Expr: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
    Self: Query,
{
    type Output = Self;

    fn group_by(mut self, group_by: Expr) -> Self::Output {
        self.group_by = Box::new(GroupByClause(group_by));
        self
    }
}

// FIXME: Should we disable joining when `.group_by` has been called? Are there
// any other query methods where a join no longer has the same semantics as
// joining on just the table?
impl<'a, ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedSelectStatement<'a, ST, QS, DB>
where
    QS: JoinTo<Rhs>,
{
    type FromClause = QS::FromClause;
    type OnClause = QS::OnClause;

    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
        QS::join_target(rhs)
    }
}

impl<'a, ST, QS, DB> QueryDsl for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, Conn> RunQueryDsl<Conn> for BoxedSelectStatement<'a, ST, QS, DB> {}

impl<'a, ST, QS, DB, T> Insertable<T> for BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, 'b, ST, QS, DB, T> Insertable<T> for &'b BoxedSelectStatement<'a, ST, QS, DB>
where
    T: Table,
    Self: Query,
{
    type Values = InsertFromSelect<Self, T::AllColumns>;

    fn values(self) -> Self::Values {
        InsertFromSelect::new(self)
    }
}

impl<'a, ST, QS, DB> SelectNullableDsl for BoxedSelectStatement<'a, ST, QS, DB>
where
    ST: NotNull,
{
    type Output = BoxedSelectStatement<'a, Nullable<ST>, QS, DB>;

    fn nullable(self) -> Self::Output {
        BoxedSelectStatement {
            select: self.select,
            from: self.from,
            distinct: self.distinct,
            where_clause: self.where_clause,
            order: self.order,
            limit: self.limit,
            offset: self.offset,
            group_by: self.group_by,
            _marker: PhantomData,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_envlogger;
extern crate slog_json;
#[macro_use]
extern crate slog_scope;
extern crate slog_stdlog;
extern crate slog_term;

extern crate chrono;
extern crate geo;
extern crate geojson;
extern crate hyper;
extern crate rs_es;

pub mod objects;
pub mod rubber;

pub use objects::*;
use std::env;

use slog::Drain;
use slog::Never;

pub fn logger_init() -> (slog_scope::GlobalLoggerGuard, ()) {
    if let Ok(s) = env::var("RUST_LOG_JSON") {
        let mut drain = slog_json::Json::new(std::io::stdout()).add_default_keys();
        if s == "pretty" {
            drain = drain.set_pretty(true);
        }
        configure_logger(drain.build().fuse())
    } else {
        configure_logger(
            slog_term::CompactFormat::new(slog_term::TermDecorator::new().stderr().build())
                .build()
                .fuse(),
        )
    }
}

fn configure_logger<T>(drain: T) -> (slog_scope::GlobalLoggerGuard, ())
where
    T: Drain<Ok = (), Err = Never> + Send + 'static,
{
    //by default we log for info
    let builder = slog_envlogger::LogBuilder::new(drain).filter(None, slog::FilterLevel::Info);
    let builder = if let Ok(s) = env::var("RUST_LOG") {
        builder.parse(&s)
    } else {
        builder
    };
    let drain = slog_async::Async::default(builder.build());

    let log = slog::Logger::root(drain.fuse(), slog_o!());
    let _scope_guard = slog_scope::set_global_logger(log);
    let _log_guard = slog_stdlog::init().unwrap();
    (_scope_guard, _log_guard)
}
<commit_msg>Increase channel size to prevent loss of log<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_envlogger;
extern crate slog_json;
#[macro_use]
extern crate slog_scope;
extern crate slog_stdlog;
extern crate slog_term;

extern crate chrono;
extern crate geo;
extern crate geojson;
extern crate hyper;
extern crate rs_es;

pub mod objects;
pub mod rubber;

pub use objects::*;
use std::env;

use slog::Drain;
use slog::Never;

pub fn logger_init() -> (slog_scope::GlobalLoggerGuard, ()) {
    if let Ok(s) = env::var("RUST_LOG_JSON") {
        let mut drain = slog_json::Json::new(std::io::stdout()).add_default_keys();
        if s == "pretty" {
            drain = drain.set_pretty(true);
        }
        configure_logger(drain.build().fuse())
    } else {
        configure_logger(
            slog_term::CompactFormat::new(slog_term::TermDecorator::new().stderr().build())
                .build()
                .fuse(),
        )
    }
}

fn configure_logger<T>(drain: T) -> (slog_scope::GlobalLoggerGuard, ())
where
    T: Drain<Ok = (), Err = Never> + Send + 'static,
{
    //by default we log for info
    let builder = slog_envlogger::LogBuilder::new(drain).filter(None, slog::FilterLevel::Info);
    let builder = if let Ok(s) = env::var("RUST_LOG") {
        builder.parse(&s)
    } else {
        builder
    };
    let drain = slog_async::Async::new(builder.build())
        .chan_size(100 * 1024)
        .build();

    let log = slog::Logger::root(drain.fuse(), slog_o!());
    let _scope_guard = slog_scope::set_global_logger(log);
    let _log_guard = slog_stdlog::init().unwrap();
    (_scope_guard, _log_guard)
}
<|endoftext|>


<commit_before>use crate::sync::atomic::AtomicI32;
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
use crate::time::Duration;

const PARKED: i32 = -1;
const EMPTY: i32 = 0;
const NOTIFIED: i32 = 1;

pub struct Parker {
    state: AtomicI32,
}

impl Parker {
    #[inline]
    pub const fn new() -> Self {
        Parker { state: AtomicI32::new(EMPTY) }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park(&self) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }
        loop {
            // Wait for something to happen, assuming it's still set to PARKED.
            futex_wait(&self.state, PARKED, None);
            // Change NOTIFIED=>EMPTY and return in that case.
            if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
                return;
            } else {
                // Spurious wake up. We loop to try again.
            }
        }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park_timeout(&self, timeout: Duration) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }
        // Wait for something to happen, assuming it's still set to PARKED.
        futex_wait(&self.state, PARKED, Some(timeout));
        // This is not just a store, because we need to establish a
        // release-acquire ordering with unpark().
        if self.state.swap(EMPTY, Acquire) == NOTIFIED {
            // Woke up because of unpark().
        } else {
            // Timeout or spurious wake up.
            // We return either way, because we can't easily tell if it was the
            // timeout or not.
        }
    }

    #[inline]
    pub fn unpark(&self) {
        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
        // wake the thread in the first case.
        //
        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
        // purpose, to make sure every unpark() has a release-acquire ordering
        // with park().
        if self.state.swap(NOTIFIED, Release) == PARKED {
            futex_wake(&self.state);
        }
    }
}

fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
    let timespec;
    let timespec_ptr = match timeout {
        Some(timeout) => {
            timespec = libc::timespec {
                tv_sec: timeout.as_secs() as _,
                tv_nsec: timeout.subsec_nanos() as _,
            };
            &timespec as *const libc::timespec
        }
        None => crate::ptr::null(),
    };
    unsafe {
        libc::syscall(
            libc::SYS_futex,
            futex as *const AtomicI32,
            libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG,
            expected,
            timespec_ptr,
        );
    }
}

fn futex_wake(futex: &AtomicI32) {
    unsafe {
        libc::syscall(
            libc::SYS_futex,
            futex as *const AtomicI32,
            libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
            1,
        );
    }
}
<commit_msg>Fix warning.<commit_after>use crate::sync::atomic::AtomicI32;
use crate::sync::atomic::Ordering::{Acquire, Release};
use crate::time::Duration;

const PARKED: i32 = -1;
const EMPTY: i32 = 0;
const NOTIFIED: i32 = 1;

pub struct Parker {
    state: AtomicI32,
}

impl Parker {
    #[inline]
    pub const fn new() -> Self {
        Parker { state: AtomicI32::new(EMPTY) }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park(&self) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }
        loop {
            // Wait for something to happen, assuming it's still set to PARKED.
            futex_wait(&self.state, PARKED, None);
            // Change NOTIFIED=>EMPTY and return in that case.
            if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
                return;
            } else {
                // Spurious wake up. We loop to try again.
            }
        }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park_timeout(&self, timeout: Duration) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }
        // Wait for something to happen, assuming it's still set to PARKED.
        futex_wait(&self.state, PARKED, Some(timeout));
        // This is not just a store, because we need to establish a
        // release-acquire ordering with unpark().
        if self.state.swap(EMPTY, Acquire) == NOTIFIED {
            // Woke up because of unpark().
        } else {
            // Timeout or spurious wake up.
            // We return either way, because we can't easily tell if it was the
            // timeout or not.
        }
    }

    #[inline]
    pub fn unpark(&self) {
        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
        // wake the thread in the first case.
        //
        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
        // purpose, to make sure every unpark() has a release-acquire ordering
        // with park().
        if self.state.swap(NOTIFIED, Release) == PARKED {
            futex_wake(&self.state);
        }
    }
}

fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
    let timespec;
    let timespec_ptr = match timeout {
        Some(timeout) => {
            timespec = libc::timespec {
                tv_sec: timeout.as_secs() as _,
                tv_nsec: timeout.subsec_nanos() as _,
            };
            &timespec as *const libc::timespec
        }
        None => crate::ptr::null(),
    };
    unsafe {
        libc::syscall(
            libc::SYS_futex,
            futex as *const AtomicI32,
            libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG,
            expected,
            timespec_ptr,
        );
    }
}

fn futex_wake(futex: &AtomicI32) {
    unsafe {
        libc::syscall(
            libc::SYS_futex,
            futex as *const AtomicI32,
            libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
            1,
        );
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::render::Renderer as SdlRenderer;
use sdl2::render::Texture as SdlTexture;
use sdl2_image::LoadTexture;
use std::path::Path;
use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use sdl2::rect;

trait Renderer {
    type Texture;
    fn load_texture(&self, path: &Path) -> Result<Self::Texture, String>;

    fn clear(&mut self);
    fn present(&mut self);
    fn draw(&mut self,
            texture: Rc<Self::Texture>,
            src: Option<rect::Rect>,
            dst: Option<rect::Rect>)
            -> Result<(), String>;
}

impl<'a> Renderer for SdlRenderer<'a> {
    type Texture = SdlTexture;

    fn load_texture(&self, path: &Path) -> Result<SdlTexture, String> {
        LoadTexture::load_texture(self, path)
    }

    fn draw(&mut self,
            texture: Rc<SdlTexture>,
            src: Option<rect::Rect>,
            dst: Option<rect::Rect>)
            -> Result<(), String> {
        self.copy(&*texture, src, dst)
    }

    fn clear(&mut self) {
        self.clear();
    }

    fn present(&mut self) {
        self.present();
    }
}

struct ResourceManager<'a, I: Renderer> {
    texture_cache: RefCell<HashMap<&'a str, Rc<I::Texture>>>,
    image_loader: I,
}

impl<'a, I: Renderer> ResourceManager<'a, I> {
    pub fn new(image_loader: I) -> Self {
        ResourceManager {
            texture_cache: RefCell::new(HashMap::new()),
            image_loader: image_loader,
        }
    }

    pub fn load_texture(&self, path: &'a str) -> Result<Rc<I::Texture>, String> {
        {
            let cache = self.texture_cache.borrow();
            let image = cache.get(path);
            if let Some(x) = image {
                return Ok(x.clone());
            }
        }
        let mut cache = self.texture_cache.borrow_mut();
        let image_path = Path::new(path);
        let image = Rc::new(try!(self.image_loader.load_texture(image_path)));
        cache.insert(path, image.clone());
        Ok(image.clone())
    }
}

#[cfg(test)]
mod test {
    use std::path::Path;
    use std::cell::RefCell;
    use std::rc::Rc;
    use sdl2::rect;
    use super::Renderer;
    use super::ResourceManager;

    #[derive(Debug)]
    struct MockTexture {
        path: String,
    }

    struct RendererTracker {
        load_count: u16,
        last_img: Rc<MockTexture>,
        last_src: Option<rect::Rect>,
        last_dst: Option<rect::Rect>,
    }

    impl RendererTracker {
        fn new() -> Self {
            RendererTracker {
                load_count: 0,
                last_img: Rc::new(MockTexture { path: "NULL".into() }),
                last_dst: None,
                last_src: None,
            }
        }
    }

    struct MockRenderer {
        error: Option<String>,
        tracker: Rc<RefCell<RendererTracker>>,
    }

    impl Renderer for MockRenderer {
        type Texture = MockTexture;

        fn load_texture(&self, path: &Path) -> Result<MockTexture, String> {
            self.tracker.borrow_mut().load_count += 1;
            match self.error {
                None => Ok(MockTexture { path: path.to_str().unwrap_or("").into() }),
                Some(ref e) => Err(e.clone()),
            }
        }

        fn draw(&mut self,
                image: Rc<MockTexture>,
                src: Option<rect::Rect>,
                dst: Option<rect::Rect>)
                -> Result<(), String> {
            match self.error {
                None => {
                    let mut tracker = self.tracker.borrow_mut();
                    tracker.last_img = image;
                    tracker.last_src = src;
                    tracker.last_dst = dst;
                    Ok(())
                }
                Some(ref e) => Err(e.clone()),
            }
        }
    }

    fn new_subject<'a>(error: Option<String>)
                       -> (ResourceManager<'a, MockRenderer>, Rc<RefCell<RendererTracker>>) {
        let tracker = Rc::new(RefCell::new(RendererTracker::new()));
        let image_loader = MockRenderer {
            error: error,
            tracker: tracker.clone(),
        };

        let subject = ResourceManager::new(image_loader);
        (subject, tracker)
    }

    #[test]
    fn loads_image() {
        let (subject, tracker) = new_subject(None);
        let image = subject.load_texture("mypath/").unwrap();
        assert_eq!(image.path, String::from("mypath/"));
        assert_eq!(tracker.borrow().load_count, 1);
    }

    #[test]
    fn returns_error() {
        let (subject, tracker) = new_subject(Some("FAIL".into()));
        let image = subject.load_texture("mypath/");
        assert_eq!(image.err(), Some("FAIL".into()));
        assert_eq!(tracker.borrow().load_count, 1);
    }

    #[test]
    fn caches_images() {
        let (subject, tracker) = new_subject(None);

        // get a new image - number of calls is 1
        let image1 = subject.load_texture("mypath/1").unwrap();
        assert_eq!(image1.path, String::from("mypath/1"));
        assert_eq!(tracker.borrow().load_count, 1);

        // load the same image - number of calls should still be 1
        let image2 = subject.load_texture("mypath/1").unwrap();
        assert_eq!(image2.path, String::from("mypath/1"));
        assert_eq!(tracker.borrow().load_count, 1);

        // load a different image - number of calls should increase
        let image3 = subject.load_texture("mypath/2").unwrap();
        assert_eq!(image3.path, String::from("mypath/2"));
        assert_eq!(tracker.borrow().load_count, 2);
    }

    #[test]
    fn draws_images() {
        let (subject, tracker) = new_subject(None);
        let image = subject.load_texture("mypath/").unwrap();
    }
}
<commit_msg>adding other methods to renderer trait<commit_after>extern crate sdl2;

use sdl2::render::Renderer as SdlRenderer;
use sdl2::render::Texture as SdlTexture;
use sdl2_image::LoadTexture;
use std::path::Path;
use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use sdl2::rect;

trait Renderer {
    type Texture;
    fn load_texture(&self, path: &Path) -> Result<Self::Texture, String>;
    fn output_size(&self) -> Result<(u32, u32), String>;

    fn clear(&mut self);
    fn present(&mut self);
    fn copy(&mut self,
            texture: Rc<Self::Texture>,
            src: Option<rect::Rect>,
            dst: Option<rect::Rect>)
            -> Result<(), String>;
}

impl<'a> Renderer for SdlRenderer<'a> {
    type Texture = SdlTexture;

    fn load_texture(&self, path: &Path) -> Result<SdlTexture, String> {
        LoadTexture::load_texture(self, path)
    }

    fn output_size(&self) -> Result<(u32, u32), String> {
        self.output_size()
    }

    fn copy(&mut self,
            texture: Rc<SdlTexture>,
            src: Option<rect::Rect>,
            dst: Option<rect::Rect>)
            -> Result<(), String> {
        self.copy(&*texture, src, dst)
    }

    fn clear(&mut self) {
        self.clear();
    }

    fn present(&mut self) {
        self.present();
    }
}

struct ResourceManager<'a, I: Renderer> {
    texture_cache: RefCell<HashMap<&'a str, Rc<I::Texture>>>,
    renderer: I,
}

impl<'a, I: Renderer> ResourceManager<'a, I> {
    pub fn new(renderer: I) -> Self {
        ResourceManager {
            texture_cache: RefCell::new(HashMap::new()),
            renderer: renderer,
        }
    }

    pub fn load_texture(&self, path: &'a str) -> Result<Rc<I::Texture>, String> {
        {
            let cache = self.texture_cache.borrow();
            let image = cache.get(path);
            if let Some(x) = image {
                return Ok(x.clone());
            }
        }
        let mut cache = self.texture_cache.borrow_mut();
        let image_path = Path::new(path);
        let image = Rc::new(try!(self.renderer.load_texture(image_path)));
        cache.insert(path, image.clone());
        Ok(image.clone())
    }
}

#[cfg(test)]
mod test {
    use std::path::Path;
    use std::cell::RefCell;
    use std::rc::Rc;
    use sdl2::rect;
    use super::Renderer;
    use super::ResourceManager;

    #[test]
    fn loads_image() {
        let (subject, tracker) = new_subject(None);
        let image = subject.load_texture("mypath/").unwrap();
        assert_eq!(image.path, String::from("mypath/"));
        assert_eq!(tracker.borrow().load_count, 1);
    }

    #[test]
    fn returns_error() {
        let (subject, tracker) = new_subject(Some("FAIL".into()));
        let image = subject.load_texture("mypath/");
        assert_eq!(image.err(), Some("FAIL".into()));
        assert_eq!(tracker.borrow().load_count, 1);
    }

    #[test]
    fn caches_images() {
        let (subject, tracker) = new_subject(None);

        // get a new image - number of calls is 1
        let image1 = subject.load_texture("mypath/1").unwrap();
        assert_eq!(image1.path, String::from("mypath/1"));
        assert_eq!(tracker.borrow().load_count, 1);

        // load the same image - number of calls should still be 1
        let image2 = subject.load_texture("mypath/1").unwrap();
        assert_eq!(image2.path, String::from("mypath/1"));
        assert_eq!(tracker.borrow().load_count, 1);

        // load a different image - number of calls should increase
        let image3 = subject.load_texture("mypath/2").unwrap();
        assert_eq!(image3.path, String::from("mypath/2"));
        assert_eq!(tracker.borrow().load_count, 2);
    }

    #[test]
    fn draws_images() {
        let (subject, tracker) = new_subject(None);
        let image = subject.load_texture("mypath/").unwrap();
    }

    #[derive(Debug)]
    struct MockTexture {
        path: String,
    }

    struct RendererTracker {
        load_count: u16,
        last_img: Rc<MockTexture>,
        last_src: Option<rect::Rect>,
        last_dst: Option<rect::Rect>,
    }

    impl RendererTracker {
        fn new() -> Self {
            RendererTracker {
                load_count: 0,
                last_img: Rc::new(MockTexture { path: "NULL".into() }),
                last_dst: None,
                last_src: None,
            }
        }
    }

    struct MockRenderer {
        error: Option<String>,
        tracker: Rc<RefCell<RendererTracker>>,
    }

    impl Renderer for MockRenderer {
        type Texture = MockTexture;

        fn load_texture(&self, path: &Path) -> Result<MockTexture, String> {
            self.tracker.borrow_mut().load_count += 1;
            match self.error {
                None => Ok(MockTexture { path: path.to_str().unwrap_or("").into() }),
                Some(ref e) => Err(e.clone()),
            }
        }

        fn copy(&mut self,
                image: Rc<MockTexture>,
                src: Option<rect::Rect>,
                dst: Option<rect::Rect>)
                -> Result<(), String> {
            match self.error {
                None => {
                    let mut tracker = self.tracker.borrow_mut();
                    tracker.last_img = image;
                    tracker.last_src = src;
                    tracker.last_dst = dst;
                    Ok(())
                }
                Some(ref e) => Err(e.clone()),
            }
        }

        fn clear(&mut self) {}

        fn present(&mut self) {}

        fn output_size(&self) -> Result<(u32, u32), String> {
            Ok((0, 0))
        }
    }

    fn new_subject<'a>(error: Option<String>)
                       -> (ResourceManager<'a, MockRenderer>, Rc<RefCell<RendererTracker>>) {
        let tracker = Rc::new(RefCell::new(RendererTracker::new()));
        let renderer = MockRenderer {
            error: error,
            tracker: tracker.clone(),
        };

        let subject = ResourceManager::new(renderer);
        (subject, tracker)
    }
}
<|endoftext|>


<commit_before>use super::dim::{self, DimFlags};
use super::{Dimensions, EdgeSizes, Rect};
use uil_shared::properties::PropertyName;
use state::StateData;

/// Reexport
pub use self::buffer::LayoutBuffer;
pub use self::buffer::LayoutNode;

mod buffer;

// The layout box kids are unsorted (defined by the markup)
// except the one declared with absolute positioning. They will
// end up at the end sorted by z-index.
#[derive(Default)]
pub struct LayoutBox {
    dim: Dimensions,
    // Stores auto/fixed behaviors
    flags: DimFlags,
}

// TODO:
pub struct LayoutBoxRepeat {
    dim: Dimensions,
    flags: DimFlags,
    // repeater: TemplateSomething,
    // Vec<DataPerTemplateRequired>
}

// ======================================== //
//                 INTERFACE                //
// ======================================== //

impl LayoutBox {

    #[inline]
    pub fn dim(&self) -> Dimensions {
        self.dim
    }

    pub fn update_from_state(&mut self, state: &StateData) {
        let mut flags = DimFlags::empty();

        if state.has_property_auto(PropertyName::MARGIN_LEFT) {
            flags = flags | dim::MARGIN_LEFT_AUTO;
        }

        if state.has_property_auto(PropertyName::MARGIN_RIGHT) {
            flags = flags | dim::MARGIN_RIGHT_AUTO;
        }

        if state.has_property_auto(PropertyName::MARGIN_TOP) {
            flags = flags | dim::MARGIN_TOP_AUTO;
        }

        if state.has_property_auto(PropertyName::MARGIN_BOTTOM) {
            flags = flags | dim::MARGIN_BOT_AUTO;
        }

        if state.has_property_auto(PropertyName::WIDTH) {
            flags = flags | dim::WIDTH_AUTO;
        }

        if state.has_property_expand(PropertyName::WIDTH) {
            flags = flags | dim::WIDTH_EXPAND;
        }

        if state.has_property_expand(PropertyName::MARGIN_LEFT) {
            flags = flags | dim::MARGIN_LEFT_EXPAND;
        }

        if state.has_property_expand(PropertyName::MARGIN_RIGHT) {
            flags = flags | dim::MARGIN_RIGHT_EXPAND;
        }

        let padding_left = state.size_of_prop(PropertyName::PADDING_LEFT);
        let padding_right = state.size_of_prop(PropertyName::PADDING_RIGHT);
        let padding_top = state.size_of_prop(PropertyName::PADDING_TOP);
        let padding_bottom = state.size_of_prop(PropertyName::PADDING_BOTTOM);

        let margin_left = state.size_of_prop(PropertyName::MARGIN_LEFT);
        let margin_right = state.size_of_prop(PropertyName::MARGIN_RIGHT);
        let margin_top = state.size_of_prop(PropertyName::MARGIN_TOP);
        let margin_bottom = state.size_of_prop(PropertyName::MARGIN_BOTTOM);

        let border_left = state.size_of_prop(PropertyName::BORDER_LEFT);
        let border_right = state.size_of_prop(PropertyName::BORDER_RIGHT);
        let border_top = state.size_of_prop(PropertyName::BORDER_TOP);
        let border_bottom = state.size_of_prop(PropertyName::BORDER_BOTTOM);

        let width = match state.size_prop_as_opt(PropertyName::WIDTH) {
            Some(w) => {
                flags = flags | dim::WIDTH_FIXED;
                w
            }
            None => 0f32
        };

        let height = match state.size_prop_as_opt(PropertyName::HEIGHT) {
            Some(h) => {
                flags = flags | dim::HEIGHT_FIXED;
                h
            }
            None => 0f32
        };

        // TODO: Missing bit for left / right / top / bottom
        //       We also need at some point the relative information
        self.dim.content = Rect {
            x: 0f32,
            y: 0f32,
            width: width,
            height: height,
        };
        self.dim.padding = EdgeSizes {
            left: padding_left,
            right: padding_right,
            top: padding_top,
            bottom: padding_bottom,
        };
        self.dim.border = EdgeSizes {
            left: border_left,
            right: border_right,
            top: border_top,
            bottom: border_bottom
        };
        self.dim.margin = EdgeSizes {
            left: margin_left,
            right: margin_right,
            top: margin_top,
            bottom: margin_bottom
        };
        self.flags = flags;
    }
}
<commit_msg>Fixed expand and auto behavior on margin keyword.<commit_after>use super::dim::{self, DimFlags};
use super::{Dimensions, EdgeSizes, Rect};
use uil_shared::properties::PropertyName;
use state::StateData;

/// Reexport
pub use self::buffer::LayoutBuffer;
pub use self::buffer::LayoutNode;

mod buffer;

// The layout box kids are unsorted (defined by the markup)
// except the one declared with absolute positioning. They will
// end up at the end sorted by z-index.
#[derive(Default)]
pub struct LayoutBox {
    dim: Dimensions,
    // Stores auto/fixed behaviors
    flags: DimFlags,
}

// TODO:
pub struct LayoutBoxRepeat {
    dim: Dimensions,
    flags: DimFlags,
    // repeater: TemplateSomething,
    // Vec<DataPerTemplateRequired>
}

// ======================================== //
//                 INTERFACE                //
// ======================================== //

impl LayoutBox {

    #[inline]
    pub fn dim(&self) -> Dimensions {
        self.dim
    }

    pub fn update_from_state(&mut self, state: &StateData) {
        let mut flags = DimFlags::empty();

        // Auto states
        if state.has_property_auto(PropertyName::MARGIN) {

            flags = flags | dim::MARGIN_LEFT_AUTO;
            flags = flags | dim::MARGIN_RIGHT_AUTO;
            flags = flags | dim::MARGIN_TOP_AUTO;
            flags = flags | dim::MARGIN_BOT_AUTO;

        } else {

            if state.has_property_auto(PropertyName::MARGIN_LEFT) {
                flags = flags | dim::MARGIN_LEFT_AUTO;
            }

            if state.has_property_auto(PropertyName::MARGIN_RIGHT) {
                flags = flags | dim::MARGIN_RIGHT_AUTO;
            }

            if state.has_property_auto(PropertyName::MARGIN_TOP) {
                flags = flags | dim::MARGIN_TOP_AUTO;
            }

            if state.has_property_auto(PropertyName::MARGIN_BOTTOM) {
                flags = flags | dim::MARGIN_BOT_AUTO;
            }
        }

        // Expands
        if state.has_property_expand(PropertyName::MARGIN) {

            flags = flags | dim::MARGIN_LEFT_EXPAND;
            flags = flags | dim::MARGIN_RIGHT_EXPAND;

        } else {

            if state.has_property_expand(PropertyName::MARGIN_LEFT) {
                flags = flags | dim::MARGIN_LEFT_EXPAND;
            }

            if state.has_property_expand(PropertyName::MARGIN_RIGHT) {
                flags = flags | dim::MARGIN_RIGHT_EXPAND;
            }
        }

        if state.has_property_auto(PropertyName::WIDTH) {
            flags = flags | dim::WIDTH_AUTO;
        }

        if state.has_property_expand(PropertyName::WIDTH) {
            flags = flags | dim::WIDTH_EXPAND;
        }

        // Sizes
        let padding_left = state.size_of_prop(PropertyName::PADDING_LEFT);
        let padding_right = state.size_of_prop(PropertyName::PADDING_RIGHT);
        let padding_top = state.size_of_prop(PropertyName::PADDING_TOP);
        let padding_bottom = state.size_of_prop(PropertyName::PADDING_BOTTOM);

        let margin_left = state.size_of_prop(PropertyName::MARGIN_LEFT);
        let margin_right = state.size_of_prop(PropertyName::MARGIN_RIGHT);
        let margin_top = state.size_of_prop(PropertyName::MARGIN_TOP);
        let margin_bottom = state.size_of_prop(PropertyName::MARGIN_BOTTOM);

        let border_left = state.size_of_prop(PropertyName::BORDER_LEFT);
        let border_right = state.size_of_prop(PropertyName::BORDER_RIGHT);
        let border_top = state.size_of_prop(PropertyName::BORDER_TOP);
        let border_bottom = state.size_of_prop(PropertyName::BORDER_BOTTOM);

        let width = match state.size_prop_as_opt(PropertyName::WIDTH) {
            Some(w) => {
                flags = flags | dim::WIDTH_FIXED;
                w
            }
            None => 0f32
        };

        let height = match state.size_prop_as_opt(PropertyName::HEIGHT) {
            Some(h) => {
                flags = flags | dim::HEIGHT_FIXED;
                h
            }
            None => 0f32
        };

        // TODO: Missing bit for left / right / top / bottom
        //       We also need at some point the relative information
        self.dim.content = Rect {
            x: 0f32,
            y: 0f32,
            width: width,
            height: height,
        };
        self.dim.padding = EdgeSizes {
            left: padding_left,
            right: padding_right,
            top: padding_top,
            bottom: padding_bottom,
        };
        self.dim.border = EdgeSizes {
            left: border_left,
            right: border_right,
            top: border_top,
            bottom: border_bottom
        };
        self.dim.margin = EdgeSizes {
            left: margin_left,
            right: margin_right,
            top: margin_top,
            bottom: margin_bottom
        };
        self.flags = flags;
    }
}
<|endoftext|>