<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use std::vec_ng::Vec;
use capability::ClientHook;
use common::*;
use common::ptr_sub;
use message;

pub type SegmentId = u32;

pub struct SegmentReader {
    arena : ArenaPtr,
    ptr : *Word,
    size : WordCount
}

impl SegmentReader {

    #[inline]
    pub unsafe fn get_start_ptr(&self) -> *Word {
        self.ptr.offset(0)
    }

    #[inline]
    pub fn contains_interval(&self, from : *Word, to : *Word) -> bool {
        let thisBegin : uint = self.ptr.to_uint();
        let thisEnd : uint = unsafe { self.ptr.offset(self.size as int).to_uint() };
        return from.to_uint() >= thisBegin && to.to_uint() <= thisEnd && from.to_uint() <= to.to_uint();
        // TODO readLimiter
    }
}

pub struct SegmentBuilder {
    reader : SegmentReader,
    id : SegmentId,
    pos : *mut Word,
}

impl SegmentBuilder {

    pub fn new(arena : *mut BuilderArena,
                   id : SegmentId,
                   ptr : *mut Word,
                   size : WordCount) -> SegmentBuilder {
        SegmentBuilder {
            reader : SegmentReader {
                arena : BuilderArenaPtr(arena),
                ptr : unsafe {std::cast::transmute(ptr)},
                size : size
            },
            id : id,
            pos : ptr,
        }
    }

    pub fn get_word_offset_to(&mut self, ptr : *mut Word) -> WordCount {
        let thisAddr : uint = self.reader.ptr.to_uint();
        let ptrAddr : uint = ptr.to_uint();
        assert!(ptrAddr >= thisAddr);
        let result = (ptrAddr - thisAddr) / BYTES_PER_WORD;
        return result;
    }

    #[inline]
    pub fn current_size(&self) -> WordCount {
        ptr_sub(self.pos, self.reader.ptr)
    }

    #[inline]
    pub fn allocate(&mut self, amount : WordCount) -> Option<*mut Word> {
        if amount > self.reader.size - self.current_size() {
            return None;
        } else {
            let result = self.pos;
            self.pos = unsafe { self.pos.offset(amount as int) };
            return Some(result);
        }
    }

    #[inline]
    pub fn get_ptr_unchecked(&self, offset : WordCount) -> *mut Word {
        unsafe {
            std::cast::transmute_mut_unsafe(self.reader.ptr.offset(offset as int))
        }
    }

    #[inline]
    pub fn get_segment_id(&self) -> SegmentId { self.id }

    #[inline]
    pub fn get_arena(&self) -> *mut BuilderArena {
        match self.reader.arena {
            BuilderArenaPtr(b) => b,
            _ => unreachable!()
        }
    }
}

pub struct ReaderArena {
    //    message : *message::MessageReader<'a>,
    segment0 : SegmentReader,

    more_segments : Option<~[SegmentReader]>,
        //XXX should this be a map as in capnproto-c++?

    cap_table : Vec<Option<~ClientHook>>,
}

impl ReaderArena {
    pub fn new(segments : &[&[Word]]) -> ~ReaderArena {
        assert!(segments.len() > 0);
        let mut arena = ~ReaderArena {
            segment0 : SegmentReader {
                arena : Null,
                ptr : unsafe { segments[0].unsafe_ref(0) },
                size : segments[0].len()
            },
            more_segments : None,
            cap_table : Vec::new()
        };

        let arena_ptr = ReaderArenaPtr (&*arena);

        arena.segment0.arena = arena_ptr;

        if segments.len() > 1 {
            let mut moreSegmentReaders = ~[];
            for segment in segments.slice_from(1).iter() {
                let segmentReader = SegmentReader {
                    arena : arena_ptr,
                    ptr : unsafe { segment.unsafe_ref(0) },
                    size : segment.len()
                };
                moreSegmentReaders.push(segmentReader);
            }
            arena.more_segments = Some(moreSegmentReaders);
        }

        arena
    }

    pub fn try_get_segment(&self, id : SegmentId) -> *SegmentReader {
        if id == 0 {
            return &self.segment0 as *SegmentReader;
        } else {
            match self.more_segments {
                None => {fail!("no segments!")}
                Some(ref segs) => {
                    unsafe { segs.unsafe_ref(id as uint - 1) as *SegmentReader }
                }
            }
        }
    }

    #[inline]
    pub fn init_cap_table(&mut self, cap_table : Vec<Option<~ClientHook>>) {
        self.cap_table = cap_table;
    }

}

pub struct BuilderArena {
    segment0 : SegmentBuilder,
    more_segments : Option<~[~SegmentBuilder]>,
    allocation_strategy : message::AllocationStrategy,
    owned_memory : Option<~[*mut Word]>,
    nextSize : uint,
    cap_table : ~[Option<~ClientHook>],
}

impl Drop for BuilderArena {
    fn drop(&mut self) {
        match self.owned_memory {
            None => {},
            Some(ref mut segs) => {
                for &segment_ptr in segs.iter() {
                    unsafe { std::libc::free(std::cast::transmute(segment_ptr)); }
                }
            }
        }
    }
}

pub enum FirstSegment<'a> {
    NumWords(uint),
    ZeroedWords(&'a mut [Word])
}

impl BuilderArena {

    pub fn new(allocationStrategy : message::AllocationStrategy,
               first_segment : FirstSegment) -> ~BuilderArena {

        let (first_segment, num_words, owned_memory) : (*mut Word, uint, Option<~[*mut Word]>) = unsafe {
            match first_segment {
                NumWords(n) => {
                    let ptr = std::cast::transmute(
                        std::libc::calloc(n as std::libc::size_t,
                                          BYTES_PER_WORD as std::libc::size_t));
                    (ptr, n, Some(~[ptr]))
                }
                ZeroedWords(w) => (w.as_mut_ptr(), w.len(), None)
            }};

        let mut result = ~BuilderArena {
            segment0 : SegmentBuilder {
                reader : SegmentReader {
                    ptr : first_segment as * Word,
                    size : num_words,
                    arena : Null },
                id : 0,
                pos : first_segment,
            },
            more_segments : None,
            allocation_strategy : allocationStrategy,
            owned_memory : owned_memory,
            nextSize : num_words,
            cap_table : box [],
        };

        let arena_ptr = { let ref mut ptr = *result; ptr as *mut BuilderArena};
        result.segment0.reader.arena = BuilderArenaPtr(arena_ptr);

        result
    }

    pub fn allocate_owned_memory(&mut self, minimumSize : WordCount) -> (*mut Word, WordCount) {
        let size = std::cmp::max(minimumSize, self.nextSize);
        let new_words : *mut Word = unsafe {
            std::cast::transmute(std::libc::calloc(size as std::libc::size_t,
                                                   BYTES_PER_WORD as std::libc::size_t)) };

        match self.owned_memory {
            None => self.owned_memory = Some(~[new_words]),
            Some(ref mut segs) => segs.push(new_words)
        }

        match self.allocation_strategy {
            message::GrowHeuristically => { self.nextSize += size; }
            _ => { }
        }
        (new_words, size)
    }

    #[inline]
    pub fn allocate(&mut self, amount : WordCount) -> (*mut SegmentBuilder, *mut Word) {
        unsafe {
            match self.segment0.allocate(amount) {
                Some(result) => { return ((&mut self.segment0) as *mut SegmentBuilder, result) }
                None => {}
            }

            //# Need to fall back to additional segments.

            let id = match self.more_segments {
                None => {
                    self.more_segments = Some(~[]);
                    1
                }
                Some(ref mut msegs) => {
                    let len = msegs.len();
                    let result_ptr = &mut *msegs[len-1] as *mut SegmentBuilder;
                    match msegs[len - 1].allocate(amount) {
                        Some(result) => { return (result_ptr, result) }
                        None => { len + 1 }
                    }
                }
            };

            let (words, size) = self.allocate_owned_memory(amount);
            let mut new_builder = ~SegmentBuilder::new(self, id as u32, words, size);
            let builder_ptr = &mut *new_builder as *mut SegmentBuilder;

            match self.more_segments {
                None => fail!("impossible"),
                Some(ref mut msegs) => {
                    msegs.push(new_builder);
                }
            }

            (builder_ptr, (*builder_ptr).allocate(amount).unwrap() )
        }
    }

    pub fn get_segment(&mut self, id : SegmentId) -> *mut SegmentBuilder {
        if id == 0 {
            &mut self.segment0 as *mut SegmentBuilder
        } else {
            match self.more_segments {
                None => fail!("invalid segment id {}", id),
                Some(ref mut msegs) => {
                    &mut *msegs[id - 1] as *mut SegmentBuilder
                }
            }
        }
    }

    pub fn get_segments_for_output<T>(&self, cont : |&[&[Word]]| -> T) -> T {
        unsafe {
            match self.more_segments {
                None => {
                    std::vec::raw::buf_as_slice::<Word, T>(
                        self.segment0.reader.ptr,
                        self.segment0.current_size(),
                        |v| cont([v]) )
                }
                Some(ref msegs) => {
                    let mut result = ~[];
                    result.push(std::cast::transmute(
                            std::raw::Slice { data : self.segment0.reader.ptr,
                                                       len : self.segment0.current_size()}));

                    for seg in msegs.iter() {
                        result.push(std::cast::transmute(
                            std::raw::Slice { data : seg.reader.ptr,
                                                        len : seg.current_size()}));
                    }
                    cont(result)
                }
            }
        }
    }

    pub fn get_cap_table<'a>(&'a self) -> &'a [Option<~ClientHook>] {
        self.cap_table.as_slice()
    }

    pub fn inject_cap(&mut self, cap : ~ClientHook) -> u32 {
        self.cap_table.push(Some(cap));
        self.cap_table.len() as u32 - 1
    }
}

pub enum ArenaPtr {
    ReaderArenaPtr(*ReaderArena),
    BuilderArenaPtr(*mut BuilderArena),
    Null
}

impl ArenaPtr {
    pub fn try_get_segment(&self, id : SegmentId) -> *SegmentReader {
        unsafe {
            match self {
                &ReaderArenaPtr(reader) => {
                    (&*reader).try_get_segment(id)
                }
                &BuilderArenaPtr(builder) => {
                    if id == 0 {
                        &(*builder).segment0.reader as *SegmentReader
                    } else {
                        match (*builder).more_segments {
                            None => {fail!("no more segments!")}
                            Some(ref segs) => {
                               &segs[id as uint - 1].reader as *SegmentReader
                            }
                        }
                    }
                }
                &Null => {
                    fail!()
                }
            }
        }
    }

    pub fn extract_cap(&self, index : uint) -> Option<~ClientHook> {
        unsafe {
            match self {
                &ReaderArenaPtr(reader) => {
                    if index < (*reader).cap_table.len() {
                        match (*reader).cap_table.as_slice()[index] {
                            Some( ref hook ) => { Some(hook.copy()) }
                            None => {
                                None
                            }
                        }
                    } else {
                        None
                    }
                }
                &BuilderArenaPtr(builder) => {
                    if index < (*builder).cap_table.len() {
                        match (*builder).cap_table.as_slice()[index] {
                            Some( ref hook ) => { Some(hook.copy()) }
                            None => {
                                None
                            }
                        }
                    } else {
                        None
                    }
                }
                &Null => {
                    fail!();
                }
            }
        }
    }
}
<commit_msg>yet more Vec<T><commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use std::vec_ng::Vec;
use capability::ClientHook;
use common::*;
use common::ptr_sub;
use message;

pub type SegmentId = u32;

pub struct SegmentReader {
    arena : ArenaPtr,
    ptr : *Word,
    size : WordCount
}

impl SegmentReader {

    #[inline]
    pub unsafe fn get_start_ptr(&self) -> *Word {
        self.ptr.offset(0)
    }

    #[inline]
    pub fn contains_interval(&self, from : *Word, to : *Word) -> bool {
        let thisBegin : uint = self.ptr.to_uint();
        let thisEnd : uint = unsafe { self.ptr.offset(self.size as int).to_uint() };
        return from.to_uint() >= thisBegin && to.to_uint() <= thisEnd && from.to_uint() <= to.to_uint();
        // TODO readLimiter
    }
}

pub struct SegmentBuilder {
    reader : SegmentReader,
    id : SegmentId,
    pos : *mut Word,
}

impl SegmentBuilder {

    pub fn new(arena : *mut BuilderArena,
                   id : SegmentId,
                   ptr : *mut Word,
                   size : WordCount) -> SegmentBuilder {
        SegmentBuilder {
            reader : SegmentReader {
                arena : BuilderArenaPtr(arena),
                ptr : unsafe {std::cast::transmute(ptr)},
                size : size
            },
            id : id,
            pos : ptr,
        }
    }

    pub fn get_word_offset_to(&mut self, ptr : *mut Word) -> WordCount {
        let thisAddr : uint = self.reader.ptr.to_uint();
        let ptrAddr : uint = ptr.to_uint();
        assert!(ptrAddr >= thisAddr);
        let result = (ptrAddr - thisAddr) / BYTES_PER_WORD;
        return result;
    }

    #[inline]
    pub fn current_size(&self) -> WordCount {
        ptr_sub(self.pos, self.reader.ptr)
    }

    #[inline]
    pub fn allocate(&mut self, amount : WordCount) -> Option<*mut Word> {
        if amount > self.reader.size - self.current_size() {
            return None;
        } else {
            let result = self.pos;
            self.pos = unsafe { self.pos.offset(amount as int) };
            return Some(result);
        }
    }

    #[inline]
    pub fn get_ptr_unchecked(&self, offset : WordCount) -> *mut Word {
        unsafe {
            std::cast::transmute_mut_unsafe(self.reader.ptr.offset(offset as int))
        }
    }

    #[inline]
    pub fn get_segment_id(&self) -> SegmentId { self.id }

    #[inline]
    pub fn get_arena(&self) -> *mut BuilderArena {
        match self.reader.arena {
            BuilderArenaPtr(b) => b,
            _ => unreachable!()
        }
    }
}

pub struct ReaderArena {
    //    message : *message::MessageReader<'a>,
    segment0 : SegmentReader,

    more_segments : Option<Vec<SegmentReader>>,
        //XXX should this be a map as in capnproto-c++?

    cap_table : Vec<Option<~ClientHook>>,
}

impl ReaderArena {
    pub fn new(segments : &[&[Word]]) -> ~ReaderArena {
        assert!(segments.len() > 0);
        let mut arena = ~ReaderArena {
            segment0 : SegmentReader {
                arena : Null,
                ptr : unsafe { segments[0].unsafe_ref(0) },
                size : segments[0].len()
            },
            more_segments : None,
            cap_table : Vec::new()
        };

        let arena_ptr = ReaderArenaPtr (&*arena);

        arena.segment0.arena = arena_ptr;

        if segments.len() > 1 {
            let mut moreSegmentReaders = Vec::new();
            for segment in segments.slice_from(1).iter() {
                let segmentReader = SegmentReader {
                    arena : arena_ptr,
                    ptr : unsafe { segment.unsafe_ref(0) },
                    size : segment.len()
                };
                moreSegmentReaders.push(segmentReader);
            }
            arena.more_segments = Some(moreSegmentReaders);
        }

        arena
    }

    pub fn try_get_segment(&self, id : SegmentId) -> *SegmentReader {
        if id == 0 {
            return &self.segment0 as *SegmentReader;
        } else {
            match self.more_segments {
                None => {fail!("no segments!")}
                Some(ref segs) => {
                    unsafe { segs.as_slice().unsafe_ref(id as uint - 1) as *SegmentReader }
                }
            }
        }
    }

    #[inline]
    pub fn init_cap_table(&mut self, cap_table : Vec<Option<~ClientHook>>) {
        self.cap_table = cap_table;
    }

}

pub struct BuilderArena {
    segment0 : SegmentBuilder,
    more_segments : Option<Vec<~SegmentBuilder>>,
    allocation_strategy : message::AllocationStrategy,
    owned_memory : Option<Vec<*mut Word>>,
    nextSize : uint,
    cap_table : Vec<Option<~ClientHook>>,
}

impl Drop for BuilderArena {
    fn drop(&mut self) {
        match self.owned_memory {
            None => {},
            Some(ref mut segs) => {
                for &segment_ptr in segs.iter() {
                    unsafe { std::libc::free(std::cast::transmute(segment_ptr)); }
                }
            }
        }
    }
}

pub enum FirstSegment<'a> {
    NumWords(uint),
    ZeroedWords(&'a mut [Word])
}

impl BuilderArena {

    pub fn new(allocationStrategy : message::AllocationStrategy,
               first_segment : FirstSegment) -> ~BuilderArena {

        let (first_segment, num_words, owned_memory) : (*mut Word, uint, Option<Vec<*mut Word>>) = unsafe {
            match first_segment {
                NumWords(n) => {
                    let ptr = std::cast::transmute(
                        std::libc::calloc(n as std::libc::size_t,
                                          BYTES_PER_WORD as std::libc::size_t));
                    (ptr, n, Some(vec!(ptr)))
                }
                ZeroedWords(w) => (w.as_mut_ptr(), w.len(), None)
            }};

        let mut result = ~BuilderArena {
            segment0 : SegmentBuilder {
                reader : SegmentReader {
                    ptr : first_segment as * Word,
                    size : num_words,
                    arena : Null },
                id : 0,
                pos : first_segment,
            },
            more_segments : None,
            allocation_strategy : allocationStrategy,
            owned_memory : owned_memory,
            nextSize : num_words,
            cap_table : Vec::new(),
        };

        let arena_ptr = { let ref mut ptr = *result; ptr as *mut BuilderArena};
        result.segment0.reader.arena = BuilderArenaPtr(arena_ptr);

        result
    }

    pub fn allocate_owned_memory(&mut self, minimumSize : WordCount) -> (*mut Word, WordCount) {
        let size = std::cmp::max(minimumSize, self.nextSize);
        let new_words : *mut Word = unsafe {
            std::cast::transmute(std::libc::calloc(size as std::libc::size_t,
                                                   BYTES_PER_WORD as std::libc::size_t)) };

        match self.owned_memory {
            None => self.owned_memory = Some(vec!(new_words)),
            Some(ref mut segs) => segs.push(new_words)
        }

        match self.allocation_strategy {
            message::GrowHeuristically => { self.nextSize += size; }
            _ => { }
        }
        (new_words, size)
    }

    #[inline]
    pub fn allocate(&mut self, amount : WordCount) -> (*mut SegmentBuilder, *mut Word) {
        unsafe {
            match self.segment0.allocate(amount) {
                Some(result) => { return ((&mut self.segment0) as *mut SegmentBuilder, result) }
                None => {}
            }

            //# Need to fall back to additional segments.

            let id = match self.more_segments {
                None => {
                    self.more_segments = Some(Vec::new());
                    1
                }
                Some(ref mut msegs) => {
                    let len = msegs.len();
                    let result_ptr = &mut *msegs.as_mut_slice()[len-1] as *mut SegmentBuilder;
                    match msegs.as_mut_slice()[len - 1].allocate(amount) {
                        Some(result) => { return (result_ptr, result) }
                        None => { len + 1 }
                    }
                }
            };

            let (words, size) = self.allocate_owned_memory(amount);
            let mut new_builder = ~SegmentBuilder::new(self, id as u32, words, size);
            let builder_ptr = &mut *new_builder as *mut SegmentBuilder;

            match self.more_segments {
                None => fail!("impossible"),
                Some(ref mut msegs) => {
                    msegs.push(new_builder);
                }
            }

            (builder_ptr, (*builder_ptr).allocate(amount).unwrap() )
        }
    }

    pub fn get_segment(&mut self, id : SegmentId) -> *mut SegmentBuilder {
        if id == 0 {
            &mut self.segment0 as *mut SegmentBuilder
        } else {
            match self.more_segments {
                None => fail!("invalid segment id {}", id),
                Some(ref mut msegs) => {
                    &mut *msegs.as_mut_slice()[id - 1] as *mut SegmentBuilder
                }
            }
        }
    }

    pub fn get_segments_for_output<T>(&self, cont : |&[&[Word]]| -> T) -> T {
        unsafe {
            match self.more_segments {
                None => {
                    std::vec::raw::buf_as_slice::<Word, T>(
                        self.segment0.reader.ptr,
                        self.segment0.current_size(),
                        |v| cont([v]) )
                }
                Some(ref msegs) => {
                    let mut result = Vec::new();
                    result.push(std::cast::transmute(
                            std::raw::Slice { data : self.segment0.reader.ptr,
                                                       len : self.segment0.current_size()}));

                    for seg in msegs.iter() {
                        result.push(std::cast::transmute(
                            std::raw::Slice { data : seg.reader.ptr,
                                                        len : seg.current_size()}));
                    }
                    cont(result.as_slice())
                }
            }
        }
    }

    pub fn get_cap_table<'a>(&'a self) -> &'a [Option<~ClientHook>] {
        self.cap_table.as_slice()
    }

    pub fn inject_cap(&mut self, cap : ~ClientHook) -> u32 {
        self.cap_table.push(Some(cap));
        self.cap_table.len() as u32 - 1
    }
}

pub enum ArenaPtr {
    ReaderArenaPtr(*ReaderArena),
    BuilderArenaPtr(*mut BuilderArena),
    Null
}

impl ArenaPtr {
    pub fn try_get_segment(&self, id : SegmentId) -> *SegmentReader {
        unsafe {
            match self {
                &ReaderArenaPtr(reader) => {
                    (&*reader).try_get_segment(id)
                }
                &BuilderArenaPtr(builder) => {
                    if id == 0 {
                        &(*builder).segment0.reader as *SegmentReader
                    } else {
                        match (*builder).more_segments {
                            None => {fail!("no more segments!")}
                            Some(ref segs) => {
                               &segs.as_slice()[id as uint - 1].reader as *SegmentReader
                            }
                        }
                    }
                }
                &Null => {
                    fail!()
                }
            }
        }
    }

    pub fn extract_cap(&self, index : uint) -> Option<~ClientHook> {
        unsafe {
            match self {
                &ReaderArenaPtr(reader) => {
                    if index < (*reader).cap_table.len() {
                        match (*reader).cap_table.as_slice()[index] {
                            Some( ref hook ) => { Some(hook.copy()) }
                            None => {
                                None
                            }
                        }
                    } else {
                        None
                    }
                }
                &BuilderArenaPtr(builder) => {
                    if index < (*builder).cap_table.len() {
                        match (*builder).cap_table.as_slice()[index] {
                            Some( ref hook ) => { Some(hook.copy()) }
                            None => {
                                None
                            }
                        }
                    } else {
                        None
                    }
                }
                &Null => {
                    fail!();
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
///
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
pub const unsafe fn unreachable_unchecked() -> ! {
    // SAFETY: the safety contract for `intrinsics::unreachable` must
    // be upheld by the caller.
    unsafe { intrinsics::unreachable() }
}

/// Emits a machine instruction hinting to the processor that it is running in busy-wait
/// spin-loop ("spin lock").
///
/// For a discussion of different locking strategies and their trade-offs, see
/// [`core::sync::atomic::spin_loop_hint`].
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.
///
/// [`core::sync::atomic::spin_loop_hint`]: crate::sync::atomic::spin_loop_hint
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
    {
        #[cfg(target_arch = "x86")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
    {
        #[cfg(target_arch = "aarch64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
            // with support for the v6 feature.
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `x` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
#[inline]
#[unstable(feature = "test", issue = "50297")]
#[allow(unreachable_code)] // this makes #[cfg] a bit easier below.
pub fn black_box<T>(dummy: T) -> T {
    // We need to "use" the argument in some way LLVM can't introspect, and on
    // targets that support it we can typically leverage inline assembly to do
    // this. LLVM's interpretation of inline assembly is that it's, well, a black
    // box. This isn't the greatest implementation since it probably deoptimizes
    // more than we want, but it's so far good enough.

    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
    // SAFETY: the inline assembly is a no-op.
    unsafe {
        llvm_asm!("" : : "r"(&dummy));
    }

    dummy
}
<commit_msg>Rollup merge of #75967 - aticu:blackbox_typo, r=Dylan-DPC<commit_after>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
///
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
pub const unsafe fn unreachable_unchecked() -> ! {
    // SAFETY: the safety contract for `intrinsics::unreachable` must
    // be upheld by the caller.
    unsafe { intrinsics::unreachable() }
}

/// Emits a machine instruction hinting to the processor that it is running in busy-wait
/// spin-loop ("spin lock").
///
/// For a discussion of different locking strategies and their trade-offs, see
/// [`core::sync::atomic::spin_loop_hint`].
///
/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
/// do anything at all.
///
/// [`core::sync::atomic::spin_loop_hint`]: crate::sync::atomic::spin_loop_hint
#[inline]
#[unstable(feature = "renamed_spin_loop", issue = "55002")]
pub fn spin_loop() {
    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
    {
        #[cfg(target_arch = "x86")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
    {
        #[cfg(target_arch = "aarch64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
            // with support for the v6 feature.
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
#[inline]
#[unstable(feature = "test", issue = "50297")]
#[allow(unreachable_code)] // this makes #[cfg] a bit easier below.
pub fn black_box<T>(dummy: T) -> T {
    // We need to "use" the argument in some way LLVM can't introspect, and on
    // targets that support it we can typically leverage inline assembly to do
    // this. LLVM's interpretation of inline assembly is that it's, well, a black
    // box. This isn't the greatest implementation since it probably deoptimizes
    // more than we want, but it's so far good enough.

    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
    // SAFETY: the inline assembly is a no-op.
    unsafe {
        llvm_asm!("" : : "r"(&dummy));
    }

    dummy
}
<|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

use super::objects::{DocType, EsId, Admin};
use chrono;
use regex;
use hyper;
use hyper::status::StatusCode;
use rs_es::error::EsError;
use rs_es;
use rs_es::EsResponse;
use serde;
use serde_json;
use rs_es::operations::search::ScanResult;

use super::objects::{AliasOperations, AliasOperation, AliasParameter};
use rs_es::units::Duration;

// Rubber is an wrapper around elasticsearch API
pub struct Rubber {
    es_client: rs_es::Client,
    // some operation are not implemented in rs_es, we need to use a raw http client
    http_client: hyper::client::Client,
}

/// return the index associated to the given type and dataset
/// this will be an alias over another real index
fn get_main_type_and_dataset_index(doc_type: &str, dataset: &str) -> String {
    format!("munin_{}_{}", doc_type, dataset)
}

/// return the index associated to the given type
/// this will be an alias over another real index
fn get_main_type_index(doc_type: &str) -> String {
    format!("munin_{}", doc_type)
}

impl Rubber {
    // build a rubber with a connection string (http://host:port/)
    pub fn new(cnx: &str) -> Rubber {
        let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
        let cap = re.captures(cnx).unwrap();
        let host = cap.name("host").unwrap().as_str();
        let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();
        info!("elastic search host {:?} port {:?}", host, port);

        Rubber {
            es_client: rs_es::Client::new(&host, port),
            http_client: hyper::client::Client::new(),
        }
    }

    pub fn get(&self, path: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a get on {}", path);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .get(&url)
            .send());
        rs_es::do_req(result)
    }
    fn put(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a put on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .put(&url)
            .body(body)
            .send());
        rs_es::do_req(result)
    }
    fn post(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a post on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .post(&url)
            .body(body)
            .send());
        rs_es::do_req(result)
    }

    pub fn make_index(&self, doc_type: &str, dataset: &str) -> Result<String, String> {
        let current_time = chrono::UTC::now().format("%Y%m%d_%H%M%S_%f");
        let index_name = format!("munin_{}_{}_{}", doc_type, dataset, current_time);
        info!("creating index {}", index_name);
        self.create_index(&index_name.to_string()).map(|_| index_name)
    }

    fn create_index(&self, name: &String) -> Result<(), String> {
        debug!("creating index");
        // Note: in rs_es it can be done with MappingOperation but for the moment I think
        // storing the mapping in json is more convenient
        let analysis = include_str!("../../../json/settings.json");
        self.put(name, &analysis)
            .map_err(|e| {
                info!("Error while creating new index {}", name);
                e.to_string()
            })
            .and_then(|res| if res.status == StatusCode::Ok {
                Ok(())
            } else {
                Err(format!("cannot create index: {:?}", res))
            })
    }

    fn get_last_index(&self, doc_type: &str, dataset: &str) -> Result<Vec<String>, String> {
        let base_index = get_main_type_and_dataset_index(doc_type, dataset);
        self.get(&format!("{}/_aliases", base_index))
            .map_err(|e| e.to_string())
            .and_then(|res| match res.status {
                StatusCode::Ok => {
                    let value: serde_json::Value = try!(res.read_response()
                        .map_err(|e| e.to_string()));
                    Ok(value.as_object()
                        .and_then(|aliases| Some(aliases.keys().cloned().collect()))
                        .unwrap_or_else(|| {
                            info!("no previous index to delete for type {} and dataset {}",
                                  doc_type,
                                  dataset);
                            vec![]
                        }))
                }
                StatusCode::NotFound => {
                    info!("impossible to find alias {}, no last index to remove",
                          base_index);
                    Ok(vec![])
                }
                _ => Err(format!("invalid elasticsearch response: {:?}", res)),
            })
    }

    /// publish the index as the new index for this doc_type and this dataset
    /// move the index alias of the doc_type and the dataset to point to this indexes
    /// and remove the old index
    pub fn publish_index(&mut self,
                         doc_type: &str,
                         dataset: &str,
                         index: String)
                         -> Result<(), String> {
        let v = vec!["addr", "street", "poi", "admin", "way"];
        debug!("publishing index");
        let last_indexes = try!(self.get_last_index(doc_type, dataset));

        let dataset_index = get_main_type_and_dataset_index(doc_type, dataset);
        try!(self.alias(&dataset_index, &vec![index.clone()], &last_indexes));

        let type_index = get_main_type_index(doc_type);
        try!(self.alias(&type_index, &vec![dataset_index.clone()], &last_indexes));

        if v.contains(&doc_type) {
            try!(self.alias("munin_street_network",
                            &vec![type_index.to_string()],
                            &vec![]));
            try!(self.alias("munin", &vec!["munin_street_network".to_string()], &vec![]));
        } else {
            try!(self.alias("munin", &vec![type_index.to_string()], &vec![]));
        }
        for i in last_indexes {
            try!(self.delete_index(&i));
        }
        Ok(())
    }

    pub fn is_existing_index(&self, name: &String) -> Result<bool, String> {
        self.get(&name)
            .map_err(|e| e.to_string())
            .map(|res| res.status == StatusCode::Ok)
    }

    /// add a list of new indexes to the alias
    /// remove a list of indexes from the alias
    fn alias(&self, alias: &str, add: &Vec<String>, remove: &Vec<String>) -> Result<(), String> {
        info!("for {}, adding alias {:?}, removing {:?}",
              alias,
              add,
              remove);
        let add_operations = add.iter().map(|x| {
            AliasOperation {
                remove: None,
                add: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let remove_operations = remove.iter().map(|x| {
            AliasOperation {
                add: None,
                remove: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let operations =
            AliasOperations { actions: add_operations.chain(remove_operations).collect() };
        let json = serde_json::to_string(&operations).unwrap();
        self.post("_aliases", &json)
            .map_err(|e| e.to_string())
            .and_then(|res| if res.status == StatusCode::Ok {
                Ok(())
            } else {
                error!("failed to change aliases for {}, es response: {:?}",
                       alias,
                       res);
                Err(format!("failed to post aliases for {}: {:?}", alias, res).to_string())
            })
    }

    pub fn delete_index(&mut self, index: &String) -> Result<(), String> {
        debug!("deleting index {}", &index);
        let res = self.es_client
            .delete_index(&index)
            .map(|res| res.acknowledged)
            .unwrap_or(false);
        if !res {
            Err(format!("Error deleting index {}", &index).into())
        } else {
            Ok(())
        }
    }

    pub fn bulk_index<T, I>(&mut self,
                            index: &String,
                            iter: I)
                            -> Result<usize, rs_es::error::EsError>
        where T: serde::Serialize + DocType + EsId,
              I: Iterator<Item = T>
    {
        use rs_es::operations::bulk::Action;
        let mut nb = 0;
        let chunk_size = 1000;
        // fold is used for creating the action and optionally set the id of the object
        let mut actions = iter.map(|v| {
            v.es_id()
                .into_iter()
                .fold(Action::index(v), |action, id| action.with_id(id))
        });
        loop {
            let chunk = actions.by_ref().take(chunk_size).collect::<Vec<_>>();
            nb += chunk.len();
            try!(self.es_client
                .bulk(&chunk)
                .with_index(&index)
                .with_doc_type(T::doc_type())
                .send());

            if chunk.len() < chunk_size {
                break;
            }
        }

        Ok(nb)
    }

    /// add all the element of 'iter' into elasticsearch
    ///
    /// To have zero downtime:
    /// first all the elements are added in a temporary index and when all has been indexed
    /// the index is published and the old index is removed
    pub fn index<T, I>(&mut self, doc_type: &str, dataset: &str, iter: I) -> Result<usize, String>
        where T: serde::Serialize + DocType + EsId,
              I: Iterator<Item = T>
    {
        // TODO better error handling
        let index = try!(self.make_index(doc_type, dataset));
        let nb_elements = try!(self.bulk_index(&index, iter).map_err(|e| e.to_string()));
        try!(self.publish_index(doc_type, dataset, index));
        Ok(nb_elements)
    }

    pub fn get_admins_from_dataset(&mut self,
                                   dataset: &str)
                                   -> Result<Vec<Admin>, rs_es::error::EsError> {
        self.get_admins_from_index(&get_main_type_and_dataset_index("admin", dataset))
    }

    pub fn get_all_admins(&mut self) -> Result<Vec<Admin>, rs_es::error::EsError> {
        self.get_admins_from_index(&get_main_type_index("admin"))
    }

    fn get_admins_from_index(&mut self, index: &str) -> Result<Vec<Admin>, rs_es::error::EsError> {
        let mut result: Vec<Admin> = vec![];
        let mut scan: ScanResult<Admin> = try!(self.es_client
            .search_query()
            .with_indexes(&[&index])
            .with_size(1000)
            .with_types(&[&"admin"])
            .scan(&Duration::minutes(1)));
        loop {
            let page = try!(scan.scroll(&mut self.es_client, &Duration::minutes(1)));
            if page.hits.hits.len() == 0 {
                break;
            }
            result.extend(page.hits.hits.into_iter().filter_map(|hit| hit.source).map(|ad| *ad));
        }
        try!(scan.close(&mut self.es_client));
        Ok(result)
    }
}

#[test]
pub fn test_valid_url() {
    Rubber::new("http://localhost:9200");
    Rubber::new("localhost:9200");
}

#[test]
#[should_panic]
pub fn test_invalid_url() {
    Rubber::new("http://bob");
}

#[test]
#[should_panic]
pub fn test_invalid_url_no_port() {
    Rubber::new("localhost");
}
<commit_msg>street deleted<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

use super::objects::{DocType, EsId, Admin};
use chrono;
use regex;
use hyper;
use hyper::status::StatusCode;
use rs_es::error::EsError;
use rs_es;
use rs_es::EsResponse;
use serde;
use serde_json;
use rs_es::operations::search::ScanResult;

use super::objects::{AliasOperations, AliasOperation, AliasParameter};
use rs_es::units::Duration;

// Rubber is an wrapper around elasticsearch API
pub struct Rubber {
    es_client: rs_es::Client,
    // some operation are not implemented in rs_es, we need to use a raw http client
    http_client: hyper::client::Client,
}

/// return the index associated to the given type and dataset
/// this will be an alias over another real index
fn get_main_type_and_dataset_index(doc_type: &str, dataset: &str) -> String {
    format!("munin_{}_{}", doc_type, dataset)
}

/// return the index associated to the given type
/// this will be an alias over another real index
fn get_main_type_index(doc_type: &str) -> String {
    format!("munin_{}", doc_type)
}

impl Rubber {
    // build a rubber with a connection string (http://host:port/)
    pub fn new(cnx: &str) -> Rubber {
        let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
        let cap = re.captures(cnx).unwrap();
        let host = cap.name("host").unwrap().as_str();
        let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();
        info!("elastic search host {:?} port {:?}", host, port);

        Rubber {
            es_client: rs_es::Client::new(&host, port),
            http_client: hyper::client::Client::new(),
        }
    }

    pub fn get(&self, path: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a get on {}", path);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .get(&url)
            .send());
        rs_es::do_req(result)
    }
    fn put(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a put on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .put(&url)
            .body(body)
            .send());
        rs_es::do_req(result)
    }
    fn post(&self, path: &str, body: &str) -> Result<hyper::client::response::Response, EsError> {
        // Note: a bit duplicate on rs_es because some ES operations are not implemented
        debug!("doing a post on {} with {}", path, body);
        let url = self.es_client.full_url(path);
        let result = try!(self.http_client
            .post(&url)
            .body(body)
            .send());
        rs_es::do_req(result)
    }

    pub fn make_index(&self, doc_type: &str, dataset: &str) -> Result<String, String> {
        let current_time = chrono::UTC::now().format("%Y%m%d_%H%M%S_%f");
        let index_name = format!("munin_{}_{}_{}", doc_type, dataset, current_time);
        info!("creating index {}", index_name);
        self.create_index(&index_name.to_string()).map(|_| index_name)
    }

    fn create_index(&self, name: &String) -> Result<(), String> {
        debug!("creating index");
        // Note: in rs_es it can be done with MappingOperation but for the moment I think
        // storing the mapping in json is more convenient
        let analysis = include_str!("../../../json/settings.json");
        self.put(name, &analysis)
            .map_err(|e| {
                info!("Error while creating new index {}", name);
                e.to_string()
            })
            .and_then(|res| if res.status == StatusCode::Ok {
                Ok(())
            } else {
                Err(format!("cannot create index: {:?}", res))
            })
    }

    fn get_last_index(&self, doc_type: &str, dataset: &str) -> Result<Vec<String>, String> {
        let base_index = get_main_type_and_dataset_index(doc_type, dataset);
        self.get(&format!("{}/_aliases", base_index))
            .map_err(|e| e.to_string())
            .and_then(|res| match res.status {
                StatusCode::Ok => {
                    let value: serde_json::Value = try!(res.read_response()
                        .map_err(|e| e.to_string()));
                    Ok(value.as_object()
                        .and_then(|aliases| Some(aliases.keys().cloned().collect()))
                        .unwrap_or_else(|| {
                            info!("no previous index to delete for type {} and dataset {}",
                                  doc_type,
                                  dataset);
                            vec![]
                        }))
                }
                StatusCode::NotFound => {
                    info!("impossible to find alias {}, no last index to remove",
                          base_index);
                    Ok(vec![])
                }
                _ => Err(format!("invalid elasticsearch response: {:?}", res)),
            })
    }

    /// publish the index as the new index for this doc_type and this dataset
    /// move the index alias of the doc_type and the dataset to point to this indexes
    /// and remove the old index
    pub fn publish_index(&mut self,
                         doc_type: &str,
                         dataset: &str,
                         index: String)
                         -> Result<(), String> {
        let v = vec!["addr", "poi", "admin", "way"];
        debug!("publishing index");
        let last_indexes = try!(self.get_last_index(doc_type, dataset));

        let dataset_index = get_main_type_and_dataset_index(doc_type, dataset);
        try!(self.alias(&dataset_index, &vec![index.clone()], &last_indexes));

        let type_index = get_main_type_index(doc_type);
        try!(self.alias(&type_index, &vec![dataset_index.clone()], &last_indexes));

        if v.contains(&doc_type) {
            try!(self.alias("munin_street_network",
                            &vec![type_index.to_string()],
                            &vec![]));
            try!(self.alias("munin", &vec!["munin_street_network".to_string()], &vec![]));
        } else {
            try!(self.alias("munin", &vec![type_index.to_string()], &vec![]));
        }
        for i in last_indexes {
            try!(self.delete_index(&i));
        }
        Ok(())
    }

    pub fn is_existing_index(&self, name: &String) -> Result<bool, String> {
        self.get(&name)
            .map_err(|e| e.to_string())
            .map(|res| res.status == StatusCode::Ok)
    }

    /// add a list of new indexes to the alias
    /// remove a list of indexes from the alias
    fn alias(&self, alias: &str, add: &Vec<String>, remove: &Vec<String>) -> Result<(), String> {
        info!("for {}, adding alias {:?}, removing {:?}",
              alias,
              add,
              remove);
        let add_operations = add.iter().map(|x| {
            AliasOperation {
                remove: None,
                add: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let remove_operations = remove.iter().map(|x| {
            AliasOperation {
                add: None,
                remove: Some(AliasParameter {
                    index: x.clone(),
                    alias: alias.to_string(),
                }),
            }
        });
        let operations =
            AliasOperations { actions: add_operations.chain(remove_operations).collect() };
        let json = serde_json::to_string(&operations).unwrap();
        self.post("_aliases", &json)
            .map_err(|e| e.to_string())
            .and_then(|res| if res.status == StatusCode::Ok {
                Ok(())
            } else {
                error!("failed to change aliases for {}, es response: {:?}",
                       alias,
                       res);
                Err(format!("failed to post aliases for {}: {:?}", alias, res).to_string())
            })
    }

    pub fn delete_index(&mut self, index: &String) -> Result<(), String> {
        debug!("deleting index {}", &index);
        let res = self.es_client
            .delete_index(&index)
            .map(|res| res.acknowledged)
            .unwrap_or(false);
        if !res {
            Err(format!("Error deleting index {}", &index).into())
        } else {
            Ok(())
        }
    }

    pub fn bulk_index<T, I>(&mut self,
                            index: &String,
                            iter: I)
                            -> Result<usize, rs_es::error::EsError>
        where T: serde::Serialize + DocType + EsId,
              I: Iterator<Item = T>
    {
        use rs_es::operations::bulk::Action;
        let mut nb = 0;
        let chunk_size = 1000;
        // fold is used for creating the action and optionally set the id of the object
        let mut actions = iter.map(|v| {
            v.es_id()
                .into_iter()
                .fold(Action::index(v), |action, id| action.with_id(id))
        });
        loop {
            let chunk = actions.by_ref().take(chunk_size).collect::<Vec<_>>();
            nb += chunk.len();
            try!(self.es_client
                .bulk(&chunk)
                .with_index(&index)
                .with_doc_type(T::doc_type())
                .send());

            if chunk.len() < chunk_size {
                break;
            }
        }

        Ok(nb)
    }

    /// add all the element of 'iter' into elasticsearch
    ///
    /// To have zero downtime:
    /// first all the elements are added in a temporary index and when all has been indexed
    /// the index is published and the old index is removed
    pub fn index<T, I>(&mut self, doc_type: &str, dataset: &str, iter: I) -> Result<usize, String>
        where T: serde::Serialize + DocType + EsId,
              I: Iterator<Item = T>
    {
        // TODO better error handling
        let index = try!(self.make_index(doc_type, dataset));
        let nb_elements = try!(self.bulk_index(&index, iter).map_err(|e| e.to_string()));
        try!(self.publish_index(doc_type, dataset, index));
        Ok(nb_elements)
    }

    pub fn get_admins_from_dataset(&mut self,
                                   dataset: &str)
                                   -> Result<Vec<Admin>, rs_es::error::EsError> {
        self.get_admins_from_index(&get_main_type_and_dataset_index("admin", dataset))
    }

    pub fn get_all_admins(&mut self) -> Result<Vec<Admin>, rs_es::error::EsError> {
        self.get_admins_from_index(&get_main_type_index("admin"))
    }

    fn get_admins_from_index(&mut self, index: &str) -> Result<Vec<Admin>, rs_es::error::EsError> {
        let mut result: Vec<Admin> = vec![];
        let mut scan: ScanResult<Admin> = try!(self.es_client
            .search_query()
            .with_indexes(&[&index])
            .with_size(1000)
            .with_types(&[&"admin"])
            .scan(&Duration::minutes(1)));
        loop {
            let page = try!(scan.scroll(&mut self.es_client, &Duration::minutes(1)));
            if page.hits.hits.len() == 0 {
                break;
            }
            result.extend(page.hits.hits.into_iter().filter_map(|hit| hit.source).map(|ad| *ad));
        }
        try!(scan.close(&mut self.es_client));
        Ok(result)
    }
}

#[test]
pub fn test_valid_url() {
    Rubber::new("http://localhost:9200");
    Rubber::new("localhost:9200");
}

#[test]
#[should_panic]
pub fn test_invalid_url() {
    Rubber::new("http://bob");
}

#[test]
#[should_panic]
pub fn test_invalid_url_no_port() {
    Rubber::new("localhost");
}
<|endoftext|>


<commit_before>generate_error_imports!();
use std::convert::From;

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct CustomErrorData {}

generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
    ConfigurationError      => "Store Configuration Error",
    CreateStoreDirDenied    => "Creating store directory implicitely denied",
    FileError               => "File Error",
    IoError                 => "IO Error",
    IdLocked                => "ID locked",
    IdNotFound              => "ID not found",
    OutOfMemory             => "Out of Memory",
    FileNotFound            => "File corresponding to ID not found",
    FileNotCreated          => "File corresponding to ID could not be created",
    FileNotWritten          => "File corresponding to ID could not be written to",
    FileNotSeeked           => "File corresponding to ID could not be seeked",
    FileNotRemoved          => "File corresponding to ID could not be removed",
    FileNotRenamed          => "File corresponding to ID could not be renamed",
    FileNotCopied           => "File could not be copied",
    DirNotCreated           => "Directory/Directories could not be created",
    StorePathExists         => "Store path exists",
    StorePathCreate         => "Store path create",
    LockError               => "Error locking datastructure",
    LockPoisoned            => "The internal Store Lock has been poisoned",
    EntryAlreadyBorrowed    => "Entry is already borrowed",
    EntryAlreadyExists      => "Entry already exists",
    MalformedEntry          => "Entry has invalid formatting, missing header",
    HeaderPathSyntaxError   => "Syntax error in accessor string",
    HeaderPathTypeFailure   => "Header has wrong type for path",
    HeaderKeyNotFound       => "Header Key not found",
    HeaderTypeFailure       => "Header type is wrong",
    HookRegisterError       => "Hook register error",
    AspectNameNotFoundError => "Aspect name not found",
    HookExecutionError      => "Hook execution error",
    PreHookExecuteError     => "Pre-Hook execution error",
    PostHookExecuteError    => "Post-Hook execution error",
    StorePathLacksVersion   => "The supplied store path has no version part",
    GlobError               => "glob() error",
    EncodingError           => "Encoding error",
    StorePathError          => "Store Path error",
    EntryRenameError        => "Entry rename error",
    StoreIdHandlingError    => "StoreId handling error",

    CreateCallError            => "Error when calling create()",
    RetrieveCallError          => "Error when calling retrieve()",
    GetCallError               => "Error when calling get()",
    GetAllVersionsCallError    => "Error when calling get_all_versions()",
    RetrieveForModuleCallError => "Error when calling retrieve_for_module()",
    UpdateCallError            => "Error when calling update()",
    RetrieveCopyCallError      => "Error when calling retrieve_copy()",
    DeleteCallError            => "Error when calling delete()",
    MoveCallError              => "Error when calling move()",
    MoveByIdCallError          => "Error when calling move_by_id()"
);

generate_result_helper!(StoreError, StoreErrorKind);
generate_option_helper!(StoreError, StoreErrorKind);

generate_custom_error_types!(ParserError, ParserErrorKind, CustomErrorData,
    TOMLParserErrors    => "Several TOML-Parser-Errors",
    MissingMainSection  => "Missing main section",
    MissingVersionInfo  => "Missing version information in main section",
    NonTableInBaseTable => "A non-table was found in the base table",
    HeaderInconsistency => "The header is inconsistent"
);

impl From<ParserError> for StoreError {
    fn from(ps: ParserError) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::MalformedEntry,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

impl From<::std::io::Error> for StoreError {
    fn from(ps: ::std::io::Error) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::IoError,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

<commit_msg>Add error kind for StoreId::new() with id-part that is absolute<commit_after>generate_error_imports!();
use std::convert::From;

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct CustomErrorData {}

generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData,
    ConfigurationError      => "Store Configuration Error",
    CreateStoreDirDenied    => "Creating store directory implicitely denied",
    FileError               => "File Error",
    IoError                 => "IO Error",
    IdLocked                => "ID locked",
    IdNotFound              => "ID not found",
    OutOfMemory             => "Out of Memory",
    FileNotFound            => "File corresponding to ID not found",
    FileNotCreated          => "File corresponding to ID could not be created",
    FileNotWritten          => "File corresponding to ID could not be written to",
    FileNotSeeked           => "File corresponding to ID could not be seeked",
    FileNotRemoved          => "File corresponding to ID could not be removed",
    FileNotRenamed          => "File corresponding to ID could not be renamed",
    FileNotCopied           => "File could not be copied",
    DirNotCreated           => "Directory/Directories could not be created",
    StorePathExists         => "Store path exists",
    StorePathCreate         => "Store path create",
    LockError               => "Error locking datastructure",
    LockPoisoned            => "The internal Store Lock has been poisoned",
    EntryAlreadyBorrowed    => "Entry is already borrowed",
    EntryAlreadyExists      => "Entry already exists",
    MalformedEntry          => "Entry has invalid formatting, missing header",
    HeaderPathSyntaxError   => "Syntax error in accessor string",
    HeaderPathTypeFailure   => "Header has wrong type for path",
    HeaderKeyNotFound       => "Header Key not found",
    HeaderTypeFailure       => "Header type is wrong",
    HookRegisterError       => "Hook register error",
    AspectNameNotFoundError => "Aspect name not found",
    HookExecutionError      => "Hook execution error",
    PreHookExecuteError     => "Pre-Hook execution error",
    PostHookExecuteError    => "Post-Hook execution error",
    StorePathLacksVersion   => "The supplied store path has no version part",
    GlobError               => "glob() error",
    EncodingError           => "Encoding error",
    StorePathError          => "Store Path error",
    EntryRenameError        => "Entry rename error",
    StoreIdHandlingError    => "StoreId handling error",
    StoreIdLocalPartAbsoluteError => "StoreId 'id' part is absolute (starts with '/') which is not allowed",

    CreateCallError            => "Error when calling create()",
    RetrieveCallError          => "Error when calling retrieve()",
    GetCallError               => "Error when calling get()",
    GetAllVersionsCallError    => "Error when calling get_all_versions()",
    RetrieveForModuleCallError => "Error when calling retrieve_for_module()",
    UpdateCallError            => "Error when calling update()",
    RetrieveCopyCallError      => "Error when calling retrieve_copy()",
    DeleteCallError            => "Error when calling delete()",
    MoveCallError              => "Error when calling move()",
    MoveByIdCallError          => "Error when calling move_by_id()"
);

generate_result_helper!(StoreError, StoreErrorKind);
generate_option_helper!(StoreError, StoreErrorKind);

generate_custom_error_types!(ParserError, ParserErrorKind, CustomErrorData,
    TOMLParserErrors    => "Several TOML-Parser-Errors",
    MissingMainSection  => "Missing main section",
    MissingVersionInfo  => "Missing version information in main section",
    NonTableInBaseTable => "A non-table was found in the base table",
    HeaderInconsistency => "The header is inconsistent"
);

impl From<ParserError> for StoreError {
    fn from(ps: ParserError) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::MalformedEntry,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

impl From<::std::io::Error> for StoreError {
    fn from(ps: ::std::io::Error) -> StoreError {
        StoreError {
            err_type: StoreErrorKind::IoError,
            cause: Some(Box::new(ps)),
            custom_data: None,
        }
    }
}

<|endoftext|>


<commit_before>//! Seat global utilities
//!
//! This module provides you with utilities for handling the seat globals
//! and the associated input Wayland objects.
//!
//! ## How to use it
//!
//! ### Initialization
//!
//! ```
//! # extern crate wayland_server;
//! use smithay::wayland::seat::Seat;
//!
//! # let mut display = wayland_server::Display::new();
//! // insert the seat:
//! let (seat, seat_global) = Seat::new(
//!     &mut display,             // the display
//!     "seat-0".into(),          // the name of the seat, will be advertized to clients
//!     None                      // insert a logger here
//! );
//! ```
//!
//! ### Run usage
//!
//! Once the seat is initialized, you can add capabilities to it.
//!
//! Currently, only pointer and keyboard capabilities are supported by smithay.
//!
//! You can add these capabilities via methods of the [`Seat`] struct:
//! [`Seat::add_keyboard`] and [`Seat::add_pointer`].
//! These methods return handles that can be cloned and sent across thread, so you can keep one around
//! in your event-handling code to forward inputs to your clients.
//!
//! This module further defines the `"cursor_image"` role, that is assigned to surfaces used by clients
//! to change the cursor icon.

use std::{cell::RefCell, fmt, ops::Deref as _, rc::Rc};

mod keyboard;
mod pointer;

pub use self::{
    keyboard::{
        keysyms, Error as KeyboardError, FilterResult, KeyboardHandle, Keysym, ModifiersState, XkbConfig,
    },
    pointer::{
        AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle,
        PointerInnerHandle,
    },
};

use wayland_server::{
    protocol::{wl_seat, wl_surface},
    Display, Filter, Global, Main, UserDataMap,
};

#[derive(Debug)]
struct Inner {
    pointer: Option<PointerHandle>,
    keyboard: Option<KeyboardHandle>,
    known_seats: Vec<wl_seat::WlSeat>,
}

pub(crate) struct SeatRc {
    inner: RefCell<Inner>,
    user_data: UserDataMap,
    pub(crate) log: ::slog::Logger,
    name: String,
}

// UserDataMap does not implement debug, so we have to impl Debug manually
impl fmt::Debug for SeatRc {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SeatRc")
            .field("inner", &self.inner)
            .field("user_data", &"...")
            .field("log", &self.log)
            .field("name", &self.name)
            .finish()
    }
}

impl Inner {
    fn compute_caps(&self) -> wl_seat::Capability {
        let mut caps = wl_seat::Capability::empty();
        if self.pointer.is_some() {
            caps |= wl_seat::Capability::Pointer;
        }
        if self.keyboard.is_some() {
            caps |= wl_seat::Capability::Keyboard;
        }
        caps
    }

    fn send_all_caps(&self) {
        let capabilities = self.compute_caps();
        for seat in &self.known_seats {
            seat.capabilities(capabilities);
        }
    }
}

/// A Seat handle
///
/// This struct gives you access to the control of the
/// capabilities of the associated seat.
///
/// It is directly inserted in the wayland display by its [`new`](Seat::new) method.
///
/// This is an handle to the inner logic, it can be cloned.
///
/// See module-level documentation for details of use.
#[derive(Debug, Clone)]
pub struct Seat {
    pub(crate) arc: Rc<SeatRc>,
}

impl Seat {
    /// Create a new seat global
    ///
    /// A new seat global is created with given name and inserted
    /// into this wayland display.
    ///
    /// You are provided with the state token to retrieve it (allowing
    /// you to add or remove capabilities from it), and the global handle,
    /// in case you want to remove it.
    pub fn new<L>(display: &mut Display, name: String, logger: L) -> (Seat, Global<wl_seat::WlSeat>)
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger);
        let arc = Rc::new(SeatRc {
            inner: RefCell::new(Inner {
                pointer: None,
                keyboard: None,
                known_seats: Vec::new(),
            }),
            log: log.new(slog::o!("smithay_module" => "seat_handler", "seat_name" => name.clone())),
            name,
            user_data: UserDataMap::new(),
        });
        let seat = Seat { arc: arc.clone() };
        let global = display.create_global(
            5,
            Filter::new(move |(new_seat, _version), _, _| {
                let seat = implement_seat(new_seat, arc.clone());
                let mut inner = arc.inner.borrow_mut();
                if seat.as_ref().version() >= 2 {
                    seat.name(arc.name.clone());
                }
                seat.capabilities(inner.compute_caps());
                inner.known_seats.push(seat);
            }),
        );
        (seat, global)
    }

    /// Attempt to retrieve a [`Seat`] from an existing resource
    pub fn from_resource(seat: &wl_seat::WlSeat) -> Option<Seat> {
        seat.as_ref()
            .user_data()
            .get::<Rc<SeatRc>>()
            .cloned()
            .map(|arc| Seat { arc })
    }

    /// Access the `UserDataMap` associated with this `Seat`
    pub fn user_data(&self) -> &UserDataMap {
        &self.arc.user_data
    }

    /// Adds the pointer capability to this seat
    ///
    /// You are provided a [`PointerHandle`], which allows you to send input events
    /// to this pointer. This handle can be cloned.
    ///
    /// Calling this method on a seat that already has a pointer capability
    /// will overwrite it, and will be seen by the clients as if the
    /// mouse was unplugged and a new one was plugged.
    ///
    /// You need to provide a callback that will be notified whenever a client requests
    /// to set a custom cursor image.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate wayland_server;
    /// #
    /// # use smithay::wayland::seat::Seat;
    /// #
    /// # let mut display = wayland_server::Display::new();
    /// # let (mut seat, seat_global) = Seat::new(
    /// #     &mut display,
    /// #     "seat-0".into(),
    /// #     None
    /// # );
    /// let pointer_handle = seat.add_pointer(
    ///     |new_status| { /* a closure handling requests from clients to change the cursor icon */ }
    /// );
    /// ```
    pub fn add_pointer<F>(&mut self, cb: F) -> PointerHandle
    where
        F: FnMut(CursorImageStatus) + 'static,
    {
        let mut inner = self.arc.inner.borrow_mut();
        let pointer = self::pointer::create_pointer_handler(cb);
        if inner.pointer.is_some() {
            // there is already a pointer, remove it and notify the clients
            // of the change
            inner.pointer = None;
            inner.send_all_caps();
        }
        inner.pointer = Some(pointer.clone());
        inner.send_all_caps();
        pointer
    }

    /// Access the pointer of this seat if any
    pub fn get_pointer(&self) -> Option<PointerHandle> {
        self.arc.inner.borrow_mut().pointer.clone()
    }

    /// Remove the pointer capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_pointer(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.pointer.is_some() {
            inner.pointer = None;
            inner.send_all_caps();
        }
    }

    /// Adds the keyboard capability to this seat
    ///
    /// You are provided a [`KeyboardHandle`], which allows you to send input events
    /// to this keyboard. This handle can be cloned.
    ///
    /// You also provide a Model/Layout/Variant/Options specification of the
    /// keymap to be used for this keyboard, as well as any repeat-info that
    /// will be forwarded to the clients.
    ///
    /// Calling this method on a seat that already has a keyboard capability
    /// will overwrite it, and will be seen by the clients as if the
    /// keyboard was unplugged and a new one was plugged.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate smithay;
    /// # use smithay::wayland::seat::{Seat, XkbConfig};
    /// # let mut seat: Seat = unimplemented!();
    /// let keyboard = seat
    ///     .add_keyboard(
    ///         XkbConfig {
    ///             layout: "de",
    ///             variant: "nodeadkeys",
    ///             ..XkbConfig::default()
    ///         },
    ///         200,
    ///         25,
    ///         |seat, focus| {
    ///             /* This closure is called whenever the keyboard focus
    ///              * changes, with the new focus as argument */
    ///         }
    ///     )
    ///     .expect("Failed to initialize the keyboard");
    /// ```
    pub fn add_keyboard<F>(
        &mut self,
        xkb_config: keyboard::XkbConfig<'_>,
        repeat_delay: i32,
        repeat_rate: i32,
        mut focus_hook: F,
    ) -> Result<KeyboardHandle, KeyboardError>
    where
        F: FnMut(&Seat, Option<&wl_surface::WlSurface>) + 'static,
    {
        let me = self.clone();
        let mut inner = self.arc.inner.borrow_mut();
        let keyboard = self::keyboard::create_keyboard_handler(
            xkb_config,
            repeat_delay,
            repeat_rate,
            &self.arc.log,
            move |focus| focus_hook(&me, focus),
        )?;
        if inner.keyboard.is_some() {
            // there is already a keyboard, remove it and notify the clients
            // of the change
            inner.keyboard = None;
            inner.send_all_caps();
        }
        inner.keyboard = Some(keyboard.clone());
        inner.send_all_caps();
        Ok(keyboard)
    }

    /// Access the keyboard of this seat if any
    pub fn get_keyboard(&self) -> Option<KeyboardHandle> {
        self.arc.inner.borrow_mut().keyboard.clone()
    }

    /// Remove the keyboard capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_keyboard(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.keyboard.is_some() {
            inner.keyboard = None;
            inner.send_all_caps();
        }
    }

    /// Checks whether a given [`WlSeat`](wl_seat::WlSeat) is associated with this [`Seat`]
    pub fn owns(&self, seat: &wl_seat::WlSeat) -> bool {
        let inner = self.arc.inner.borrow_mut();
        inner.known_seats.iter().any(|s| s.as_ref().equals(seat.as_ref()))
    }
}

impl ::std::cmp::PartialEq for Seat {
    fn eq(&self, other: &Seat) -> bool {
        Rc::ptr_eq(&self.arc, &other.arc)
    }
}

fn implement_seat(seat: Main<wl_seat::WlSeat>, arc: Rc<SeatRc>) -> wl_seat::WlSeat {
    let dest_arc = arc.clone();
    seat.quick_assign(move |seat, request, _| {
        let arc = seat.as_ref().user_data().get::<Rc<SeatRc>>().unwrap();
        let inner = arc.inner.borrow_mut();
        match request {
            wl_seat::Request::GetPointer { id } => {
                let pointer = self::pointer::implement_pointer(id, inner.pointer.as_ref());
                if let Some(ref ptr_handle) = inner.pointer {
                    ptr_handle.new_pointer(pointer);
                } else {
                    // we should send a protocol error... but the protocol does not allow
                    // us, so this pointer will just remain inactive ¯\_(ツ)_/¯
                }
            }
            wl_seat::Request::GetKeyboard { id } => {
                let keyboard = self::keyboard::implement_keyboard(id, inner.keyboard.as_ref());
                if let Some(ref kbd_handle) = inner.keyboard {
                    kbd_handle.new_kbd(keyboard);
                } else {
                    // same as pointer, should error but cannot
                }
            }
            wl_seat::Request::GetTouch { .. } => {
                // TODO
            }
            wl_seat::Request::Release => {
                // Our destructors already handle it
            }
            _ => unreachable!(),
        }
    });
    seat.assign_destructor(Filter::new(move |seat: wl_seat::WlSeat, _, _| {
        dest_arc
            .inner
            .borrow_mut()
            .known_seats
            .retain(|s| !s.as_ref().equals(seat.as_ref()));
    }));
    seat.as_ref().user_data().set(move || arc);

    seat.deref().clone()
}
<commit_msg>seat: Export KeysymHandle<commit_after>//! Seat global utilities
//!
//! This module provides you with utilities for handling the seat globals
//! and the associated input Wayland objects.
//!
//! ## How to use it
//!
//! ### Initialization
//!
//! ```
//! # extern crate wayland_server;
//! use smithay::wayland::seat::Seat;
//!
//! # let mut display = wayland_server::Display::new();
//! // insert the seat:
//! let (seat, seat_global) = Seat::new(
//!     &mut display,             // the display
//!     "seat-0".into(),          // the name of the seat, will be advertized to clients
//!     None                      // insert a logger here
//! );
//! ```
//!
//! ### Run usage
//!
//! Once the seat is initialized, you can add capabilities to it.
//!
//! Currently, only pointer and keyboard capabilities are supported by smithay.
//!
//! You can add these capabilities via methods of the [`Seat`] struct:
//! [`Seat::add_keyboard`] and [`Seat::add_pointer`].
//! These methods return handles that can be cloned and sent across thread, so you can keep one around
//! in your event-handling code to forward inputs to your clients.
//!
//! This module further defines the `"cursor_image"` role, that is assigned to surfaces used by clients
//! to change the cursor icon.

use std::{cell::RefCell, fmt, ops::Deref as _, rc::Rc};

mod keyboard;
mod pointer;

pub use self::{
    keyboard::{
        keysyms, Error as KeyboardError, FilterResult, KeyboardHandle, Keysym, KeysymHandle, ModifiersState,
        XkbConfig,
    },
    pointer::{
        AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle,
        PointerInnerHandle,
    },
};

use wayland_server::{
    protocol::{wl_seat, wl_surface},
    Display, Filter, Global, Main, UserDataMap,
};

#[derive(Debug)]
struct Inner {
    pointer: Option<PointerHandle>,
    keyboard: Option<KeyboardHandle>,
    known_seats: Vec<wl_seat::WlSeat>,
}

pub(crate) struct SeatRc {
    inner: RefCell<Inner>,
    user_data: UserDataMap,
    pub(crate) log: ::slog::Logger,
    name: String,
}

// UserDataMap does not implement debug, so we have to impl Debug manually
impl fmt::Debug for SeatRc {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SeatRc")
            .field("inner", &self.inner)
            .field("user_data", &"...")
            .field("log", &self.log)
            .field("name", &self.name)
            .finish()
    }
}

impl Inner {
    fn compute_caps(&self) -> wl_seat::Capability {
        let mut caps = wl_seat::Capability::empty();
        if self.pointer.is_some() {
            caps |= wl_seat::Capability::Pointer;
        }
        if self.keyboard.is_some() {
            caps |= wl_seat::Capability::Keyboard;
        }
        caps
    }

    fn send_all_caps(&self) {
        let capabilities = self.compute_caps();
        for seat in &self.known_seats {
            seat.capabilities(capabilities);
        }
    }
}

/// A Seat handle
///
/// This struct gives you access to the control of the
/// capabilities of the associated seat.
///
/// It is directly inserted in the wayland display by its [`new`](Seat::new) method.
///
/// This is an handle to the inner logic, it can be cloned.
///
/// See module-level documentation for details of use.
#[derive(Debug, Clone)]
pub struct Seat {
    pub(crate) arc: Rc<SeatRc>,
}

impl Seat {
    /// Create a new seat global
    ///
    /// A new seat global is created with given name and inserted
    /// into this wayland display.
    ///
    /// You are provided with the state token to retrieve it (allowing
    /// you to add or remove capabilities from it), and the global handle,
    /// in case you want to remove it.
    pub fn new<L>(display: &mut Display, name: String, logger: L) -> (Seat, Global<wl_seat::WlSeat>)
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger);
        let arc = Rc::new(SeatRc {
            inner: RefCell::new(Inner {
                pointer: None,
                keyboard: None,
                known_seats: Vec::new(),
            }),
            log: log.new(slog::o!("smithay_module" => "seat_handler", "seat_name" => name.clone())),
            name,
            user_data: UserDataMap::new(),
        });
        let seat = Seat { arc: arc.clone() };
        let global = display.create_global(
            5,
            Filter::new(move |(new_seat, _version), _, _| {
                let seat = implement_seat(new_seat, arc.clone());
                let mut inner = arc.inner.borrow_mut();
                if seat.as_ref().version() >= 2 {
                    seat.name(arc.name.clone());
                }
                seat.capabilities(inner.compute_caps());
                inner.known_seats.push(seat);
            }),
        );
        (seat, global)
    }

    /// Attempt to retrieve a [`Seat`] from an existing resource
    pub fn from_resource(seat: &wl_seat::WlSeat) -> Option<Seat> {
        seat.as_ref()
            .user_data()
            .get::<Rc<SeatRc>>()
            .cloned()
            .map(|arc| Seat { arc })
    }

    /// Access the `UserDataMap` associated with this `Seat`
    pub fn user_data(&self) -> &UserDataMap {
        &self.arc.user_data
    }

    /// Adds the pointer capability to this seat
    ///
    /// You are provided a [`PointerHandle`], which allows you to send input events
    /// to this pointer. This handle can be cloned.
    ///
    /// Calling this method on a seat that already has a pointer capability
    /// will overwrite it, and will be seen by the clients as if the
    /// mouse was unplugged and a new one was plugged.
    ///
    /// You need to provide a callback that will be notified whenever a client requests
    /// to set a custom cursor image.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate wayland_server;
    /// #
    /// # use smithay::wayland::seat::Seat;
    /// #
    /// # let mut display = wayland_server::Display::new();
    /// # let (mut seat, seat_global) = Seat::new(
    /// #     &mut display,
    /// #     "seat-0".into(),
    /// #     None
    /// # );
    /// let pointer_handle = seat.add_pointer(
    ///     |new_status| { /* a closure handling requests from clients to change the cursor icon */ }
    /// );
    /// ```
    pub fn add_pointer<F>(&mut self, cb: F) -> PointerHandle
    where
        F: FnMut(CursorImageStatus) + 'static,
    {
        let mut inner = self.arc.inner.borrow_mut();
        let pointer = self::pointer::create_pointer_handler(cb);
        if inner.pointer.is_some() {
            // there is already a pointer, remove it and notify the clients
            // of the change
            inner.pointer = None;
            inner.send_all_caps();
        }
        inner.pointer = Some(pointer.clone());
        inner.send_all_caps();
        pointer
    }

    /// Access the pointer of this seat if any
    pub fn get_pointer(&self) -> Option<PointerHandle> {
        self.arc.inner.borrow_mut().pointer.clone()
    }

    /// Remove the pointer capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_pointer(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.pointer.is_some() {
            inner.pointer = None;
            inner.send_all_caps();
        }
    }

    /// Adds the keyboard capability to this seat
    ///
    /// You are provided a [`KeyboardHandle`], which allows you to send input events
    /// to this keyboard. This handle can be cloned.
    ///
    /// You also provide a Model/Layout/Variant/Options specification of the
    /// keymap to be used for this keyboard, as well as any repeat-info that
    /// will be forwarded to the clients.
    ///
    /// Calling this method on a seat that already has a keyboard capability
    /// will overwrite it, and will be seen by the clients as if the
    /// keyboard was unplugged and a new one was plugged.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate smithay;
    /// # use smithay::wayland::seat::{Seat, XkbConfig};
    /// # let mut seat: Seat = unimplemented!();
    /// let keyboard = seat
    ///     .add_keyboard(
    ///         XkbConfig {
    ///             layout: "de",
    ///             variant: "nodeadkeys",
    ///             ..XkbConfig::default()
    ///         },
    ///         200,
    ///         25,
    ///         |seat, focus| {
    ///             /* This closure is called whenever the keyboard focus
    ///              * changes, with the new focus as argument */
    ///         }
    ///     )
    ///     .expect("Failed to initialize the keyboard");
    /// ```
    pub fn add_keyboard<F>(
        &mut self,
        xkb_config: keyboard::XkbConfig<'_>,
        repeat_delay: i32,
        repeat_rate: i32,
        mut focus_hook: F,
    ) -> Result<KeyboardHandle, KeyboardError>
    where
        F: FnMut(&Seat, Option<&wl_surface::WlSurface>) + 'static,
    {
        let me = self.clone();
        let mut inner = self.arc.inner.borrow_mut();
        let keyboard = self::keyboard::create_keyboard_handler(
            xkb_config,
            repeat_delay,
            repeat_rate,
            &self.arc.log,
            move |focus| focus_hook(&me, focus),
        )?;
        if inner.keyboard.is_some() {
            // there is already a keyboard, remove it and notify the clients
            // of the change
            inner.keyboard = None;
            inner.send_all_caps();
        }
        inner.keyboard = Some(keyboard.clone());
        inner.send_all_caps();
        Ok(keyboard)
    }

    /// Access the keyboard of this seat if any
    pub fn get_keyboard(&self) -> Option<KeyboardHandle> {
        self.arc.inner.borrow_mut().keyboard.clone()
    }

    /// Remove the keyboard capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_keyboard(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.keyboard.is_some() {
            inner.keyboard = None;
            inner.send_all_caps();
        }
    }

    /// Checks whether a given [`WlSeat`](wl_seat::WlSeat) is associated with this [`Seat`]
    pub fn owns(&self, seat: &wl_seat::WlSeat) -> bool {
        let inner = self.arc.inner.borrow_mut();
        inner.known_seats.iter().any(|s| s.as_ref().equals(seat.as_ref()))
    }
}

impl ::std::cmp::PartialEq for Seat {
    fn eq(&self, other: &Seat) -> bool {
        Rc::ptr_eq(&self.arc, &other.arc)
    }
}

fn implement_seat(seat: Main<wl_seat::WlSeat>, arc: Rc<SeatRc>) -> wl_seat::WlSeat {
    let dest_arc = arc.clone();
    seat.quick_assign(move |seat, request, _| {
        let arc = seat.as_ref().user_data().get::<Rc<SeatRc>>().unwrap();
        let inner = arc.inner.borrow_mut();
        match request {
            wl_seat::Request::GetPointer { id } => {
                let pointer = self::pointer::implement_pointer(id, inner.pointer.as_ref());
                if let Some(ref ptr_handle) = inner.pointer {
                    ptr_handle.new_pointer(pointer);
                } else {
                    // we should send a protocol error... but the protocol does not allow
                    // us, so this pointer will just remain inactive ¯\_(ツ)_/¯
                }
            }
            wl_seat::Request::GetKeyboard { id } => {
                let keyboard = self::keyboard::implement_keyboard(id, inner.keyboard.as_ref());
                if let Some(ref kbd_handle) = inner.keyboard {
                    kbd_handle.new_kbd(keyboard);
                } else {
                    // same as pointer, should error but cannot
                }
            }
            wl_seat::Request::GetTouch { .. } => {
                // TODO
            }
            wl_seat::Request::Release => {
                // Our destructors already handle it
            }
            _ => unreachable!(),
        }
    });
    seat.assign_destructor(Filter::new(move |seat: wl_seat::WlSeat, _, _| {
        dest_arc
            .inner
            .borrow_mut()
            .known_seats
            .retain(|s| !s.as_ref().equals(seat.as_ref()));
    }));
    seat.as_ref().user_data().set(move || arc);

    seat.deref().clone()
}
<|endoftext|>


<commit_before>use actix::prelude::*;
use godcoin::prelude::*;
use log::info;
use std::{
    mem,
    str::FromStr,
    time::{Duration, SystemTime, UNIX_EPOCH},
};

pub struct Minter {
    chain: Blockchain,
    minter_key: KeyPair,
    wallet_key: PublicKey,
    txs: Vec<TxVariant>,
}

impl Actor for Minter {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        let dur = Duration::from_secs(3);
        ctx.run_interval(dur, |minter, _| {
            minter.produce();
        });
    }
}

impl Minter {
    pub fn new(chain: Blockchain, minter_key: KeyPair, wallet_key: PublicKey) -> Self {
        Self {
            chain,
            minter_key,
            wallet_key,
            txs: Vec::new(),
        }
    }

    fn produce(&mut self) {
        let mut transactions = vec![];
        mem::swap(&mut transactions, &mut self.txs);

        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as u64;

        transactions.push(TxVariant::RewardTx(RewardTx {
            base: Tx {
                tx_type: TxType::REWARD,
                fee: Asset::from_str("0 GOLD").unwrap(),
                timestamp,
                signature_pairs: Vec::new(),
            },
            to: self.wallet_key.clone().into(),
            rewards: vec![],
        }));

        let head = self.chain.get_chain_head();
        let block = head.new_child(transactions).sign(&self.minter_key);

        let height = block.height;
        let tx_len = block.transactions.len();

        self.chain.insert_block(block).unwrap();
        let txs = if tx_len == 1 { "tx" } else { "txs" };
        info!(
            "Produced block at height {} with {} {}",
            height, tx_len, txs
        );
    }
}
<commit_msg>Remove unnecessary clone<commit_after>use actix::prelude::*;
use godcoin::prelude::*;
use log::info;
use std::{
    mem,
    str::FromStr,
    time::{Duration, SystemTime, UNIX_EPOCH},
};

pub struct Minter {
    chain: Blockchain,
    minter_key: KeyPair,
    wallet_key: PublicKey,
    txs: Vec<TxVariant>,
}

impl Actor for Minter {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        let dur = Duration::from_secs(3);
        ctx.run_interval(dur, |minter, _| {
            minter.produce();
        });
    }
}

impl Minter {
    pub fn new(chain: Blockchain, minter_key: KeyPair, wallet_key: PublicKey) -> Self {
        Self {
            chain,
            minter_key,
            wallet_key,
            txs: Vec::new(),
        }
    }

    fn produce(&mut self) {
        let mut transactions = vec![];
        mem::swap(&mut transactions, &mut self.txs);

        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as u64;

        transactions.push(TxVariant::RewardTx(RewardTx {
            base: Tx {
                tx_type: TxType::REWARD,
                fee: Asset::from_str("0 GOLD").unwrap(),
                timestamp,
                signature_pairs: Vec::new(),
            },
            to: (&self.wallet_key).into(),
            rewards: vec![],
        }));

        let head = self.chain.get_chain_head();
        let block = head.new_child(transactions).sign(&self.minter_key);

        let height = block.height;
        let tx_len = block.transactions.len();

        self.chain.insert_block(block).unwrap();
        let txs = if tx_len == 1 { "tx" } else { "txs" };
        info!(
            "Produced block at height {} with {} {}",
            height, tx_len, txs
        );
    }
}
<|endoftext|>