<commit_before>use std::io::{self, Read, Write};

use futures::{Poll, Async};

#[derive(Copy, Clone, Debug)]
pub struct BufRange {
    pub start: usize,
    pub end: usize,
}

#[derive(Copy, PartialEq, Clone, Debug)]
enum BufState {
    Reading,
    Writeing,
    None,
}

pub struct SharedBuf {
    inner: Vec<u8>,
    curr: usize,
    state: BufState,
}

impl SharedBuf {
    pub fn new(size: usize) -> SharedBuf {
        SharedBuf {
            inner: vec![0u8; size],
            curr: 0,
            state: BufState::None,
        }
    }

    pub fn get_ref(&self) -> &[u8] {
        &self.inner[..]
    }

    pub fn get_mut(&mut self) -> &mut [u8] {
        &mut self.inner[..]
    }

    pub fn get_ref_from(&self, from: usize) -> &[u8] {
        assert!(from <= self.inner.len());
        &self.inner[from..]
    }

    pub fn get_mut_from(&mut self, from: usize) -> &mut [u8] {
        assert!(from <= self.inner.len());
        &mut self.inner[from..]
    }

    pub fn get_ref_to(&self, to: usize) -> &[u8] {
        assert!(to <= self.inner.len());
        &self.inner[0..to]
    }

    pub fn get_mut_to(&mut self, to: usize) -> &mut [u8] {
        assert!(to <= self.inner.len());
        &mut self.inner[0..to]
    }

    pub fn get_ref_range(&self, range: BufRange) -> &[u8] {
        let BufRange { start, end } = range;

        assert!(end <= self.inner.len());

        &self.inner[start..end]
    }

    pub fn get_mut_range(&mut self, range: BufRange) -> &mut [u8] {
        let BufRange { start, end } = range;

        assert!(end <= self.inner.len());

        &mut self.inner[start..end]
    }

    pub fn read_exact<R: Read>(
        &mut self,
        reader: &mut R,
        range: BufRange,
    ) -> Poll<BufRange, io::Error> {
        assert!(self.state != BufState::Writeing);

        self.state = BufState::Reading;

        let BufRange { start, end } = range;
        assert!(end <= self.inner.len());

        let need = end - start;
        while self.curr < need {
            let n = try_nb!(reader.read(&mut self.inner[start + self.curr..end]));
            self.curr += n;
            if n == 0 {
                return Err(eof());
            }
        }

        self.curr = 0;
        self.state = BufState::None;
        Ok(Async::Ready(range))
    }

    pub fn write_exact<W: Write>(
        &mut self,
        writer: &mut W,
        range: BufRange,
    ) -> Poll<BufRange, io::Error> {
        assert!(self.state != BufState::Reading);

        self.state = BufState::Writeing;

        let BufRange { start, end } = range;
        assert!(end <= self.inner.len());

        let need = end - start;
        while self.curr < need {
            let n = try_nb!(writer.write(&self.inner[start + self.curr..end]));
            self.curr += n;
            if n == 0 {
                return Err(zero_write());
            }
        }

        self.curr = 0;
        self.state = BufState::None;
        Ok(Async::Ready(range))
    }
}

fn eof() -> io::Error {
    io::Error::new(io::ErrorKind::UnexpectedEof, "early eof")
}

fn zero_write() -> io::Error {
    io::Error::new(io::ErrorKind::WriteZero, "zero-length write")
}
<commit_msg>add size filed<commit_after>use std::io::{self, Read, Write};

use futures::{Poll, Async};

#[derive(Copy, Clone, Debug)]
pub struct BufRange {
    pub start: usize,
    pub end: usize,
}

#[derive(Copy, PartialEq, Clone, Debug)]
enum BufState {
    Reading,
    Writeing,
    None,
}

pub struct SharedBuf {
    size: usize,
    inner: Vec<u8>,
    curr: usize,
    state: BufState,
}

impl SharedBuf {
    pub fn new(size: usize) -> SharedBuf {
        SharedBuf {
            size: size,
            inner: vec![0u8; size],
            curr: 0,
            state: BufState::None,
        }
    }

    pub fn get_ref(&self) -> &[u8] {
        &self.inner[..]
    }

    pub fn get_mut(&mut self) -> &mut [u8] {
        &mut self.inner[..]
    }

    pub fn get_ref_from(&self, from: usize) -> &[u8] {
        assert!(from <= self.size);
        &self.inner[from..]
    }

    pub fn get_mut_from(&mut self, from: usize) -> &mut [u8] {
        assert!(from <= self.size);
        &mut self.inner[from..]
    }

    pub fn get_ref_to(&self, to: usize) -> &[u8] {
        assert!(to <= self.size);
        &self.inner[0..to]
    }

    pub fn get_mut_to(&mut self, to: usize) -> &mut [u8] {
        assert!(to <= self.size);
        &mut self.inner[0..to]
    }

    pub fn get_ref_range(&self, range: BufRange) -> &[u8] {
        let BufRange { start, end } = range;

        assert!(end <= self.size);

        &self.inner[start..end]
    }

    pub fn get_mut_range(&mut self, range: BufRange) -> &mut [u8] {
        let BufRange { start, end } = range;

        assert!(end <= self.size);

        &mut self.inner[start..end]
    }

    pub fn read_exact<R: Read>(
        &mut self,
        reader: &mut R,
        range: BufRange,
    ) -> Poll<BufRange, io::Error> {
        assert!(self.state != BufState::Writeing);

        self.state = BufState::Reading;

        let BufRange { start, end } = range;
        assert!(end <= self.size);

        let need = end - start;
        while self.curr < need {
            let n = try_nb!(reader.read(&mut self.inner[start + self.curr..end]));
            self.curr += n;
            if n == 0 {
                return Err(eof());
            }
        }

        self.curr = 0;
        self.state = BufState::None;
        Ok(Async::Ready(range))
    }

    pub fn write_exact<W: Write>(
        &mut self,
        writer: &mut W,
        range: BufRange,
    ) -> Poll<BufRange, io::Error> {
        assert!(self.state != BufState::Reading);

        self.state = BufState::Writeing;

        let BufRange { start, end } = range;
        assert!(end <= self.size);

        let need = end - start;
        while self.curr < need {
            let n = try_nb!(writer.write(&self.inner[start + self.curr..end]));
            self.curr += n;
            if n == 0 {
                return Err(zero_write());
            }
        }

        self.curr = 0;
        self.state = BufState::None;
        Ok(Async::Ready(range))
    }
}

fn eof() -> io::Error {
    io::Error::new(io::ErrorKind::UnexpectedEof, "early eof")
}

fn zero_write() -> io::Error {
    io::Error::new(io::ErrorKind::WriteZero, "zero-length write")
}
<|endoftext|>


<commit_before>use hb;
use std;

use font::Font;
use common::{HarfbuzzObject, Tag, Language};

pub type GlyphPosition = hb::hb_glyph_position_t;
pub type GlyphInfo = hb::hb_glyph_info_t;
pub type Feature = hb::hb_feature_t;

struct BufferRaw {
    hb_buffer: *mut hb::hb_buffer_t,
}
impl BufferRaw {
    fn new() -> BufferRaw {
        let buffer = unsafe { hb::hb_buffer_create() };

        BufferRaw { hb_buffer: buffer }
    }

    fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.hb_buffer
    }

    fn len(&self) -> usize {
        unsafe { hb::hb_buffer_get_length(self.hb_buffer) as usize }
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    fn add_str(&mut self, string: &str) {
        let utf8_ptr = string.as_ptr() as *const i8;
        unsafe {
            hb::hb_buffer_add_utf8(self.hb_buffer,
                                   utf8_ptr,
                                   string.len() as i32,
                                   0,
                                   string.len() as i32);
        }
    }

    fn set_direction(&mut self, direction: hb::hb_direction_t) {
        unsafe { hb::hb_buffer_set_direction(self.hb_buffer, direction) };
    }

    /// Returns the `Buffer`'s text direction.
    fn get_direction(&self) -> hb::hb_direction_t {
        unsafe { hb::hb_buffer_get_direction(self.hb_buffer) }
    }

    fn set_language(&mut self, lang: Language) {
        unsafe { hb::hb_buffer_set_language(self.hb_buffer, lang.0) }
    }

    fn get_language(&self) -> Language {
        Language(unsafe { hb::hb_buffer_get_language(self.hb_buffer) })
    }

    fn set_script(&mut self, script: hb::hb_script_t) {
        unsafe { hb::hb_buffer_set_script(self.hb_buffer, script) }
    }

    fn get_script(&self) -> hb::hb_script_t {
        unsafe { hb::hb_buffer_get_script(self.hb_buffer) }
    }

    fn guess_segment_properties(&mut self) {
        unsafe { hb::hb_buffer_guess_segment_properties(self.hb_buffer) };
    }

    fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        unsafe {
            let mut segment_props: hb::hb_segment_properties_t = std::mem::uninitialized();
            hb::hb_buffer_get_segment_properties(self.hb_buffer, &mut segment_props as *mut _);
            segment_props
        }
    }

    fn shape(&mut self, font: &Font, features: &[Feature]) {
        unsafe {
            hb::hb_shape(font.as_raw(),
                         self.hb_buffer,
                         features.as_ptr(),
                         features.len() as u32)
        };
    }

    fn clear_contents(&mut self) {
        unsafe { hb::hb_buffer_clear_contents(self.hb_buffer) };
    }

    fn get_glyph_positions(&self) -> &[GlyphPosition] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_pos = hb::hb_buffer_get_glyph_positions(self.hb_buffer,
                                                              &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_pos, length as usize)
        }
    }

    fn get_glyph_infos(&self) -> &[GlyphInfo] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_infos = hb::hb_buffer_get_glyph_infos(self.hb_buffer,
                                                            &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_infos, length as usize)
        }
    }

    /// Reverse the `Buffer`'s contents.
    fn reverse(&mut self) {
        unsafe { hb::hb_buffer_reverse(self.hb_buffer) };
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    fn reverse_range(&mut self, start: usize, end: usize) {
        assert!(start <= self.len(), end <= self.len());
        unsafe { hb::hb_buffer_reverse_range(self.hb_buffer, start as u32, end as u32) }
    }
}

impl Clone for BufferRaw {
    fn clone(&self) -> Self {
        unsafe {
            hb::hb_buffer_reference(self.hb_buffer);
        }
        BufferRaw { hb_buffer: self.hb_buffer }
    }
}

impl Drop for BufferRaw {
    fn drop(&mut self) {
        unsafe {
            hb::hb_buffer_destroy(self.hb_buffer);
        }
    }
}

/// A `UnicodeBuffer` can be filled with unicode text and corresponding cluster indices.
#[derive(Clone)]
pub struct UnicodeBuffer(BufferRaw);
#[allow(dead_code)]
impl UnicodeBuffer {
    /// Creates a new empty `Buffer`.
    pub fn new() -> UnicodeBuffer {
        UnicodeBuffer(BufferRaw::new())
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Adds the string slice to the `Buffer`'s array of codepoints.
    pub fn add_str(mut self, string: &str) -> UnicodeBuffer {
        self.0.add_str(string);
        self
    }

    fn get_string(&self) -> String {
        self.0
            .get_glyph_infos()
            .iter()
            .map(|info| std::char::from_u32(info.codepoint).unwrap())
            .collect()
    }

    /// Sets the text direction of the `Buffer`'s contents.
    pub fn set_direction(mut self, direction: hb::hb_direction_t) -> UnicodeBuffer {
        self.0.set_direction(direction);
        self
    }

    /// Returns the `Buffer`'s text direction.
    pub fn get_direction(&self) -> hb::hb_direction_t {
        self.0.get_direction()
    }

    pub fn set_script(mut self, script: Tag) -> UnicodeBuffer {
        self.0.set_script(unsafe { hb::hb_script_from_iso15924_tag(script.0) });
        self
    }

    pub fn get_script(&self) -> Tag {
        Tag(unsafe { hb::hb_script_to_iso15924_tag(self.0.get_script()) })
    }

    pub fn set_language(mut self, lang: Language) -> UnicodeBuffer {
        self.0.set_language(lang);
        self
    }

    pub fn get_language(&self) -> Language {
        self.0.get_language()
    }

    pub fn guess_segment_properties(mut self) -> UnicodeBuffer {
        self.0.guess_segment_properties();
        self
    }

    pub fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        self.0.get_segment_properties()
    }

    pub fn shape(mut self, font: &Font, features: &[Feature]) -> GlyphBuffer {
        self = self.guess_segment_properties();
        self.0.shape(font, features);
        GlyphBuffer(self.0)
    }

    pub fn clear_contents(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        self
    }
}

impl std::fmt::Debug for UnicodeBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("content", &self.get_string())
            .field("direction", &self.get_direction())
            .field("language", &self.get_language())
            .field("script", &self.get_script())
            .finish()
    }
}

impl std::default::Default for UnicodeBuffer {
    fn default() -> UnicodeBuffer {
        UnicodeBuffer::new()
    }
}

/// A `GlyphBuffer` is obtained through the `shape` function of a `UnicodeBuffer`. It contains
/// the resulting output information of the shaping process.
#[derive(Clone)]
pub struct GlyphBuffer(BufferRaw);

impl GlyphBuffer {
    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn get_glyph_positions(&self) -> &[GlyphPosition] {
        self.0.get_glyph_positions()
    }

    pub fn get_glyph_infos(&self) -> &[GlyphInfo] {
        self.0.get_glyph_infos()
    }

    /// Reverse the `Buffer`'s contents.
    pub fn reverse(&mut self) {
        self.0.reverse()
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub fn reverse_range(&mut self, start: usize, end: usize) {
        self.0.reverse_range(start, end)
    }

    /// Clears the contents of the glyph buffer and returns an empty `UnicodeBuffer` reusing the
    /// existing allocation.
    pub fn clear(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        UnicodeBuffer(self.0)
    }
}

impl std::fmt::Debug for GlyphBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("glyph positions", &self.get_glyph_positions())
            .field("glyph infos", &self.get_glyph_infos())
            .finish()
    }
}

#[derive(Debug, Clone)]
pub enum Buffer {
    UnicodeBuffer(UnicodeBuffer),
    GlyphBuffer(GlyphBuffer),
}
<commit_msg>Change get_language implementations to check for null-ptrs<commit_after>use hb;
use std;

use font::Font;
use common::{HarfbuzzObject, Tag, Language};

pub type GlyphPosition = hb::hb_glyph_position_t;
pub type GlyphInfo = hb::hb_glyph_info_t;
pub type Feature = hb::hb_feature_t;

struct BufferRaw {
    hb_buffer: *mut hb::hb_buffer_t,
}
impl BufferRaw {
    fn new() -> BufferRaw {
        let buffer = unsafe { hb::hb_buffer_create() };

        BufferRaw { hb_buffer: buffer }
    }

    fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.hb_buffer
    }

    fn len(&self) -> usize {
        unsafe { hb::hb_buffer_get_length(self.hb_buffer) as usize }
    }

    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    fn add_str(&mut self, string: &str) {
        let utf8_ptr = string.as_ptr() as *const i8;
        unsafe {
            hb::hb_buffer_add_utf8(self.hb_buffer,
                                   utf8_ptr,
                                   string.len() as i32,
                                   0,
                                   string.len() as i32);
        }
    }

    fn set_direction(&mut self, direction: hb::hb_direction_t) {
        unsafe { hb::hb_buffer_set_direction(self.hb_buffer, direction) };
    }

    /// Returns the `Buffer`'s text direction.
    fn get_direction(&self) -> hb::hb_direction_t {
        unsafe { hb::hb_buffer_get_direction(self.hb_buffer) }
    }

    fn set_language(&mut self, lang: Language) {
        unsafe { hb::hb_buffer_set_language(self.hb_buffer, lang.0) }
    }

    fn get_language(&self) -> Option<Language> {
        let raw_lang = unsafe { hb::hb_buffer_get_language(self.hb_buffer) };
        if raw_lang.is_null() {
            None
        } else {
            Some(Language(raw_lang))
        }
    }

    fn set_script(&mut self, script: hb::hb_script_t) {
        unsafe { hb::hb_buffer_set_script(self.hb_buffer, script) }
    }

    fn get_script(&self) -> hb::hb_script_t {
        unsafe { hb::hb_buffer_get_script(self.hb_buffer) }
    }

    fn guess_segment_properties(&mut self) {
        unsafe { hb::hb_buffer_guess_segment_properties(self.hb_buffer) };
    }

    fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        unsafe {
            let mut segment_props: hb::hb_segment_properties_t = std::mem::uninitialized();
            hb::hb_buffer_get_segment_properties(self.hb_buffer, &mut segment_props as *mut _);
            segment_props
        }
    }

    fn shape(&mut self, font: &Font, features: &[Feature]) {
        unsafe {
            hb::hb_shape(font.as_raw(),
                         self.hb_buffer,
                         features.as_ptr(),
                         features.len() as u32)
        };
    }

    fn clear_contents(&mut self) {
        unsafe { hb::hb_buffer_clear_contents(self.hb_buffer) };
    }

    fn get_glyph_positions(&self) -> &[GlyphPosition] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_pos = hb::hb_buffer_get_glyph_positions(self.hb_buffer,
                                                              &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_pos, length as usize)
        }
    }

    fn get_glyph_infos(&self) -> &[GlyphInfo] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_infos = hb::hb_buffer_get_glyph_infos(self.hb_buffer,
                                                            &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_infos, length as usize)
        }
    }

    /// Reverse the `Buffer`'s contents.
    fn reverse(&mut self) {
        unsafe { hb::hb_buffer_reverse(self.hb_buffer) };
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    fn reverse_range(&mut self, start: usize, end: usize) {
        assert!(start <= self.len(), end <= self.len());
        unsafe { hb::hb_buffer_reverse_range(self.hb_buffer, start as u32, end as u32) }
    }
}

impl Clone for BufferRaw {
    fn clone(&self) -> Self {
        unsafe {
            hb::hb_buffer_reference(self.hb_buffer);
        }
        BufferRaw { hb_buffer: self.hb_buffer }
    }
}

impl Drop for BufferRaw {
    fn drop(&mut self) {
        unsafe {
            hb::hb_buffer_destroy(self.hb_buffer);
        }
    }
}

/// A `UnicodeBuffer` can be filled with unicode text and corresponding cluster indices.
#[derive(Clone)]
pub struct UnicodeBuffer(BufferRaw);
#[allow(dead_code)]
impl UnicodeBuffer {
    /// Creates a new empty `Buffer`.
    pub fn new() -> UnicodeBuffer {
        UnicodeBuffer(BufferRaw::new())
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Adds the string slice to the `Buffer`'s array of codepoints.
    pub fn add_str(mut self, string: &str) -> UnicodeBuffer {
        self.0.add_str(string);
        self
    }

    fn get_string(&self) -> String {
        self.0
            .get_glyph_infos()
            .iter()
            .map(|info| std::char::from_u32(info.codepoint).unwrap())
            .collect()
    }

    /// Sets the text direction of the `Buffer`'s contents.
    pub fn set_direction(mut self, direction: hb::hb_direction_t) -> UnicodeBuffer {
        self.0.set_direction(direction);
        self
    }

    /// Returns the `Buffer`'s text direction.
    pub fn get_direction(&self) -> hb::hb_direction_t {
        self.0.get_direction()
    }

    pub fn set_script(mut self, script: Tag) -> UnicodeBuffer {
        self.0.set_script(unsafe { hb::hb_script_from_iso15924_tag(script.0) });
        self
    }

    pub fn get_script(&self) -> Tag {
        Tag(unsafe { hb::hb_script_to_iso15924_tag(self.0.get_script()) })
    }

    pub fn set_language(mut self, lang: Language) -> UnicodeBuffer {
        self.0.set_language(lang);
        self
    }

    pub fn get_language(&self) -> Option<Language> {
        self.0.get_language()
    }

    pub fn guess_segment_properties(mut self) -> UnicodeBuffer {
        self.0.guess_segment_properties();
        self
    }

    pub fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        self.0.get_segment_properties()
    }

    pub fn shape(mut self, font: &Font, features: &[Feature]) -> GlyphBuffer {
        self = self.guess_segment_properties();
        self.0.shape(font, features);
        GlyphBuffer(self.0)
    }

    pub fn clear_contents(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        self
    }
}

impl std::fmt::Debug for UnicodeBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("content", &self.get_string())
            .field("direction", &self.get_direction())
            .field("language", &self.get_language())
            .field("script", &self.get_script())
            .finish()
    }
}

impl std::default::Default for UnicodeBuffer {
    fn default() -> UnicodeBuffer {
        UnicodeBuffer::new()
    }
}

/// A `GlyphBuffer` is obtained through the `shape` function of a `UnicodeBuffer`. It contains
/// the resulting output information of the shaping process.
#[derive(Clone)]
pub struct GlyphBuffer(BufferRaw);

impl GlyphBuffer {
    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns a pointer to the underlying raw harfbuzz buffer.
    pub fn as_raw(&self) -> *mut hb::hb_buffer_t {
        self.0.as_raw()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn get_glyph_positions(&self) -> &[GlyphPosition] {
        self.0.get_glyph_positions()
    }

    pub fn get_glyph_infos(&self) -> &[GlyphInfo] {
        self.0.get_glyph_infos()
    }

    /// Reverse the `Buffer`'s contents.
    pub fn reverse(&mut self) {
        self.0.reverse()
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub fn reverse_range(&mut self, start: usize, end: usize) {
        self.0.reverse_range(start, end)
    }

    /// Clears the contents of the glyph buffer and returns an empty `UnicodeBuffer` reusing the
    /// existing allocation.
    pub fn clear(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        UnicodeBuffer(self.0)
    }
}

impl std::fmt::Debug for GlyphBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("Buffer")
            .field("glyph positions", &self.get_glyph_positions())
            .field("glyph infos", &self.get_glyph_infos())
            .finish()
    }
}

#[derive(Debug, Clone)]
pub enum Buffer {
    UnicodeBuffer(UnicodeBuffer),
    GlyphBuffer(GlyphBuffer),
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::executor::Executor;
use cita_types::{Address, U256};
use contracts::solc::{
    AccountQuotaLimit, EmergencyBrake, NodeManager, PermissionManagement, PriceManagement,
    QuotaManager, Resource, SysConfig, UserManagement, VersionManager, AUTO_EXEC_QL_VALUE,
};
use libexecutor::economical_model::EconomicalModel;
use std::collections::HashMap;
use types::ids::BlockId;

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct GlobalSysConfig {
    pub nodes: Vec<Address>,
    pub validators: Vec<Address>,
    pub block_quota_limit: usize,
    pub delay_active_interval: usize,
    pub changed_height: usize,
    /// Interval time for creating a block (milliseconds)
    pub block_interval: u64,
    pub emergency_brake: bool,
    pub chain_version: u32,
    pub block_sys_config: BlockSysConfig,
}

impl Default for GlobalSysConfig {
    fn default() -> Self {
        GlobalSysConfig {
            nodes: Vec::new(),
            validators: Vec::new(),
            block_quota_limit: 18_446_744_073_709_551_615,
            delay_active_interval: 1,
            changed_height: 0,
            block_interval: 3000,
            emergency_brake: false,
            chain_version: 0,
            block_sys_config: BlockSysConfig::default(),
        }
    }
}

impl GlobalSysConfig {
    // TODO We have to update all default value when they was changed in .sol files.
    // Is there any better solution?
    pub fn load(executor: &Executor, block_id: BlockId) -> Self {
        let mut conf = GlobalSysConfig::default();
        conf.nodes = executor
            .node_manager()
            .shuffled_stake_nodes(block_id)
            .unwrap_or_else(NodeManager::default_shuffled_stake_nodes);

        conf.validators = executor
            .node_manager()
            .nodes(block_id)
            .unwrap_or_else(NodeManager::default_shuffled_stake_nodes);

        let quota_manager = QuotaManager::new(executor);
        conf.block_quota_limit = quota_manager
            .block_quota_limit(block_id)
            .unwrap_or_else(QuotaManager::default_block_quota_limit)
            as usize;
        conf.block_sys_config.auto_exec_quota_limit = quota_manager
            .auto_exec_quota_limit(block_id)
            .unwrap_or_else(QuotaManager::default_auto_exec_quota_limit);
        let sys_config = SysConfig::new(executor);
        conf.delay_active_interval = sys_config
            .delay_block_number(block_id)
            .unwrap_or_else(SysConfig::default_delay_block_number)
            as usize;
        conf.block_sys_config.check_options.permission = sys_config
            .permission_check(block_id)
            .unwrap_or_else(SysConfig::default_permission_check);
        conf.block_sys_config.check_options.send_tx_permission = sys_config
            .send_tx_permission_check(block_id)
            .unwrap_or_else(SysConfig::default_send_tx_permission_check);
        conf.block_sys_config
            .check_options
            .create_contract_permission = sys_config
            .create_contract_permission_check(block_id)
            .unwrap_or_else(SysConfig::default_create_contract_permission_check);
        conf.block_sys_config.check_options.quota = sys_config
            .quota_check(block_id)
            .unwrap_or_else(SysConfig::default_quota_check);
        conf.block_sys_config.check_options.fee_back_platform = sys_config
            .fee_back_platform_check(block_id)
            .unwrap_or_else(SysConfig::default_fee_back_platform_check);
        conf.block_sys_config.chain_owner = sys_config
            .chain_owner(block_id)
            .unwrap_or_else(SysConfig::default_chain_owner);
        conf.block_interval = sys_config
            .block_interval(block_id)
            .unwrap_or_else(SysConfig::default_block_interval);
        conf.block_sys_config.auto_exec = sys_config
            .auto_exec(block_id)
            .unwrap_or_else(SysConfig::default_auto_exec);

        let permission_manager = PermissionManagement::new(executor);
        conf.block_sys_config.account_permissions =
            permission_manager.load_account_permissions(block_id);
        conf.block_sys_config.super_admin_account =
            permission_manager.get_super_admin_account(block_id);

        let user_manager = UserManagement::new(executor);
        conf.block_sys_config.group_accounts = user_manager.load_group_accounts(block_id);
        conf.block_sys_config.economical_model = sys_config
            .economical_model(block_id)
            .unwrap_or_else(SysConfig::default_economical_model);

        let common_quota_limit = quota_manager
            .account_quota_limit(block_id)
            .unwrap_or_else(QuotaManager::default_account_quota_limit);
        let specific = quota_manager.specific(block_id);

        conf.block_sys_config
            .account_quota_limit
            .set_common_quota_limit(common_quota_limit);
        conf.block_sys_config
            .account_quota_limit
            .set_specific_quota_limit(specific);
        conf.changed_height = executor.get_current_height() as usize;

        let emergency_manager = EmergencyBrake::new(executor);
        conf.emergency_brake = emergency_manager
            .state(block_id)
            .unwrap_or_else(EmergencyBrake::default_state);

        let version_manager = VersionManager::new(executor);
        conf.chain_version = version_manager
            .get_version(block_id)
            .unwrap_or_else(VersionManager::default_version);

        let price_management = PriceManagement::new(executor);
        conf.block_sys_config.quota_price = price_management
            .quota_price(BlockId::Pending)
            .unwrap_or_else(PriceManagement::default_quota_price);

        conf
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Default, Copy)]
pub struct CheckOptions {
    pub permission: bool,
    pub quota: bool,
    pub fee_back_platform: bool,
    pub send_tx_permission: bool,
    pub create_contract_permission: bool,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct BlockSysConfig {
    pub account_quota_limit: AccountQuotaLimit,
    pub chain_owner: Address,
    pub auto_exec_quota_limit: u64,
    pub auto_exec: bool,
    pub quota_price: U256,
    pub super_admin_account: Option<Address>,
    pub account_permissions: HashMap<Address, Vec<Resource>>,
    pub group_accounts: HashMap<Address, Vec<Address>>,
    pub check_options: CheckOptions,
    pub economical_model: EconomicalModel,
}

impl Default for BlockSysConfig {
    fn default() -> Self {
        BlockSysConfig {
            account_quota_limit: AccountQuotaLimit::new(),
            chain_owner: Address::from(0),
            auto_exec_quota_limit: AUTO_EXEC_QL_VALUE,
            auto_exec: false,
            quota_price: PriceManagement::default_quota_price(),
            super_admin_account: None,
            account_permissions: HashMap::new(),
            group_accounts: HashMap::new(),
            check_options: CheckOptions::default(),
            economical_model: EconomicalModel::Quota,
        }
    }
}

impl BlockSysConfig {
    pub fn exempt_checking(&mut self) {
        self.check_options = CheckOptions::default();
    }
}
<commit_msg>:bug: Quota price of sys config is default.<commit_after>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::executor::Executor;
use cita_types::{Address, U256};
use contracts::solc::{
    AccountQuotaLimit, EmergencyBrake, NodeManager, PermissionManagement, PriceManagement,
    QuotaManager, Resource, SysConfig, UserManagement, VersionManager, AUTO_EXEC_QL_VALUE,
};
use libexecutor::economical_model::EconomicalModel;
use std::collections::HashMap;
use types::ids::BlockId;

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct GlobalSysConfig {
    pub nodes: Vec<Address>,
    pub validators: Vec<Address>,
    pub block_quota_limit: usize,
    pub delay_active_interval: usize,
    pub changed_height: usize,
    /// Interval time for creating a block (milliseconds)
    pub block_interval: u64,
    pub emergency_brake: bool,
    pub chain_version: u32,
    pub block_sys_config: BlockSysConfig,
}

impl Default for GlobalSysConfig {
    fn default() -> Self {
        GlobalSysConfig {
            nodes: Vec::new(),
            validators: Vec::new(),
            block_quota_limit: 18_446_744_073_709_551_615,
            delay_active_interval: 1,
            changed_height: 0,
            block_interval: 3000,
            emergency_brake: false,
            chain_version: 0,
            block_sys_config: BlockSysConfig::default(),
        }
    }
}

impl GlobalSysConfig {
    // TODO We have to update all default value when they was changed in .sol files.
    // Is there any better solution?
    pub fn load(executor: &Executor, block_id: BlockId) -> Self {
        let mut conf = GlobalSysConfig::default();
        conf.nodes = executor
            .node_manager()
            .shuffled_stake_nodes(block_id)
            .unwrap_or_else(NodeManager::default_shuffled_stake_nodes);

        conf.validators = executor
            .node_manager()
            .nodes(block_id)
            .unwrap_or_else(NodeManager::default_shuffled_stake_nodes);

        let quota_manager = QuotaManager::new(executor);
        conf.block_quota_limit = quota_manager
            .block_quota_limit(block_id)
            .unwrap_or_else(QuotaManager::default_block_quota_limit)
            as usize;
        conf.block_sys_config.auto_exec_quota_limit = quota_manager
            .auto_exec_quota_limit(block_id)
            .unwrap_or_else(QuotaManager::default_auto_exec_quota_limit);
        let sys_config = SysConfig::new(executor);
        conf.delay_active_interval = sys_config
            .delay_block_number(block_id)
            .unwrap_or_else(SysConfig::default_delay_block_number)
            as usize;
        conf.block_sys_config.check_options.permission = sys_config
            .permission_check(block_id)
            .unwrap_or_else(SysConfig::default_permission_check);
        conf.block_sys_config.check_options.send_tx_permission = sys_config
            .send_tx_permission_check(block_id)
            .unwrap_or_else(SysConfig::default_send_tx_permission_check);
        conf.block_sys_config
            .check_options
            .create_contract_permission = sys_config
            .create_contract_permission_check(block_id)
            .unwrap_or_else(SysConfig::default_create_contract_permission_check);
        conf.block_sys_config.check_options.quota = sys_config
            .quota_check(block_id)
            .unwrap_or_else(SysConfig::default_quota_check);
        conf.block_sys_config.check_options.fee_back_platform = sys_config
            .fee_back_platform_check(block_id)
            .unwrap_or_else(SysConfig::default_fee_back_platform_check);
        conf.block_sys_config.chain_owner = sys_config
            .chain_owner(block_id)
            .unwrap_or_else(SysConfig::default_chain_owner);
        conf.block_interval = sys_config
            .block_interval(block_id)
            .unwrap_or_else(SysConfig::default_block_interval);
        conf.block_sys_config.auto_exec = sys_config
            .auto_exec(block_id)
            .unwrap_or_else(SysConfig::default_auto_exec);

        let permission_manager = PermissionManagement::new(executor);
        conf.block_sys_config.account_permissions =
            permission_manager.load_account_permissions(block_id);
        conf.block_sys_config.super_admin_account =
            permission_manager.get_super_admin_account(block_id);

        let user_manager = UserManagement::new(executor);
        conf.block_sys_config.group_accounts = user_manager.load_group_accounts(block_id);
        conf.block_sys_config.economical_model = sys_config
            .economical_model(block_id)
            .unwrap_or_else(SysConfig::default_economical_model);

        let common_quota_limit = quota_manager
            .account_quota_limit(block_id)
            .unwrap_or_else(QuotaManager::default_account_quota_limit);
        let specific = quota_manager.specific(block_id);

        conf.block_sys_config
            .account_quota_limit
            .set_common_quota_limit(common_quota_limit);
        conf.block_sys_config
            .account_quota_limit
            .set_specific_quota_limit(specific);
        conf.changed_height = executor.get_current_height() as usize;

        let emergency_manager = EmergencyBrake::new(executor);
        conf.emergency_brake = emergency_manager
            .state(block_id)
            .unwrap_or_else(EmergencyBrake::default_state);

        let version_manager = VersionManager::new(executor);
        conf.chain_version = version_manager
            .get_version(block_id)
            .unwrap_or_else(VersionManager::default_version);

        let price_management = PriceManagement::new(executor);
        conf.block_sys_config.quota_price = price_management
            .quota_price(block_id)
            .unwrap_or_else(PriceManagement::default_quota_price);

        conf
    }
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Default, Copy)]
pub struct CheckOptions {
    pub permission: bool,
    pub quota: bool,
    pub fee_back_platform: bool,
    pub send_tx_permission: bool,
    pub create_contract_permission: bool,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct BlockSysConfig {
    pub account_quota_limit: AccountQuotaLimit,
    pub chain_owner: Address,
    pub auto_exec_quota_limit: u64,
    pub auto_exec: bool,
    pub quota_price: U256,
    pub super_admin_account: Option<Address>,
    pub account_permissions: HashMap<Address, Vec<Resource>>,
    pub group_accounts: HashMap<Address, Vec<Address>>,
    pub check_options: CheckOptions,
    pub economical_model: EconomicalModel,
}

impl Default for BlockSysConfig {
    fn default() -> Self {
        BlockSysConfig {
            account_quota_limit: AccountQuotaLimit::new(),
            chain_owner: Address::from(0),
            auto_exec_quota_limit: AUTO_EXEC_QL_VALUE,
            auto_exec: false,
            quota_price: PriceManagement::default_quota_price(),
            super_admin_account: None,
            account_permissions: HashMap::new(),
            group_accounts: HashMap::new(),
            check_options: CheckOptions::default(),
            economical_model: EconomicalModel::Quota,
        }
    }
}

impl BlockSysConfig {
    pub fn exempt_checking(&mut self) {
        self.check_options = CheckOptions::default();
    }
}
<|endoftext|>


<commit_before>use super::util::{CacheKeyPath,
                  ConfigOptCacheKeyPath};
use configopt::ConfigOpt;
use structopt::StructOpt;

arg_enum! {
    #[derive(Serialize, Deserialize)]
    pub enum Shell {
        Bash,
        Fish,
        Zsh,
        PowerShell,
    }
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
/// Commands relating to Habitat runtime config
pub enum Cli {
    Setup(CliSetup),
    Completers(CliCompleters),
}

/// Sets up the CLI with reasonable defaults
#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "setup", no_version, rename_all = "screamingsnake")]
pub struct CliSetup {
    #[structopt(flatten)]
    cache_key_path: CacheKeyPath,
}

/// Creates command-line completers for your shell
#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "completers", no_version, rename_all = "screamingsnake")]
pub struct CliCompleters {
    /// The name of the shell you want to generate the command-completion
    #[structopt(name = "SHELL",
                short = "s",
                long = "shell",
                possible_values = &Shell::variants(),
                case_insensitive = true)]
    shell: Shell,
}
<commit_msg>[PR Feedback] add comment on Serialize<commit_after>use super::util::{CacheKeyPath,
                  ConfigOptCacheKeyPath};
use configopt::ConfigOpt;
use structopt::StructOpt;

arg_enum! {
    // Serialize required by the bound in toml::Value::try_from
    #[derive(Serialize, Deserialize)]
    pub enum Shell {
        Bash,
        Fish,
        Zsh,
        PowerShell,
    }
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
/// Commands relating to Habitat runtime config
pub enum Cli {
    Setup(CliSetup),
    Completers(CliCompleters),
}

/// Sets up the CLI with reasonable defaults
#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "setup", no_version, rename_all = "screamingsnake")]
pub struct CliSetup {
    #[structopt(flatten)]
    cache_key_path: CacheKeyPath,
}

/// Creates command-line completers for your shell
#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "completers", no_version, rename_all = "screamingsnake")]
pub struct CliCompleters {
    /// The name of the shell you want to generate the command-completion
    #[structopt(name = "SHELL",
                short = "s",
                long = "shell",
                possible_values = &Shell::variants(),
                case_insensitive = true)]
    shell: Shell,
}
<|endoftext|>


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

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::FormDataBinding;
use dom::bindings::codegen::Bindings::FormDataBinding::FormDataMethods;
use dom::bindings::codegen::InheritTypes::FileCast;
use dom::bindings::codegen::UnionTypes::FileOrString;
use dom::bindings::codegen::UnionTypes::FileOrString::{eFile, eString};
use dom::bindings::error::{Fallible};
use dom::bindings::global::{GlobalRef, GlobalField};
use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::blob::Blob;
use dom::file::File;
use dom::htmlformelement::HTMLFormElement;
use util::str::DOMString;

use std::borrow::ToOwned;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

#[derive(JSTraceable, Clone)]
#[must_root]
#[derive(HeapSizeOf)]
pub enum FormDatum {
    StringData(DOMString),
    FileData(JS<File>)
}

#[dom_struct]
pub struct FormData {
    reflector_: Reflector,
    data: DOMRefCell<HashMap<DOMString, Vec<FormDatum>>>,
    global: GlobalField,
    form: Option<JS<HTMLFormElement>>
}

impl FormData {
    fn new_inherited(form: Option<&HTMLFormElement>, global: GlobalRef) -> FormData {
        FormData {
            reflector_: Reflector::new(),
            data: DOMRefCell::new(HashMap::new()),
            global: GlobalField::from_rooted(&global),
            form: form.map(|f| JS::from_ref(f)),
        }
    }

    pub fn new(form: Option<&HTMLFormElement>, global: GlobalRef) -> Root<FormData> {
        reflect_dom_object(box FormData::new_inherited(form, global),
                           global, FormDataBinding::Wrap)
    }

    pub fn Constructor(global: GlobalRef, form: Option<&HTMLFormElement>) -> Fallible<Root<FormData>> {
        Ok(FormData::new(form, global))
    }
}

impl FormDataMethods for FormData {
    #[allow(unrooted_must_root)]
    // https://xhr.spec.whatwg.org/#dom-formdata-append
    fn Append(&self, name: DOMString, value: &Blob, filename: Option<DOMString>) {
        let file = FormDatum::FileData(JS::from_rooted(&self.get_file_from_blob(value, filename)));
        let mut data = self.data.borrow_mut();
        match data.entry(name) {
            Occupied(entry) => entry.into_mut().push(file),
            Vacant(entry) => {
                entry.insert(vec!(file));
            }
        }
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-append
    fn Append_(&self, name: DOMString, value: DOMString) {
        let mut data = self.data.borrow_mut();
        match data.entry(name) {
            Occupied(entry) => entry.into_mut().push(FormDatum::StringData(value)),
            Vacant  (entry) => { entry.insert(vec!(FormDatum::StringData(value))); },
        }
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-delete
    fn Delete(&self, name: DOMString) {
        self.data.borrow_mut().remove(&name);
    }

    #[allow(unsafe_code)]
    // https://xhr.spec.whatwg.org/#dom-formdata-get
    fn Get(&self, name: DOMString) -> Option<FileOrString> {
        // FIXME(https://github.com/rust-lang/rust/issues/23338)
        let data = self.data.borrow();
        if data.contains_key(&name) {
            match data[&name][0].clone() {
                FormDatum::StringData(ref s) => Some(eString(s.clone())),
                FormDatum::FileData(ref f) => {
                    Some(eFile(f.root()))
                }
            }
        } else {
            None
        }
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-has
    fn Has(&self, name: DOMString) -> bool {
        self.data.borrow().contains_key(&name)
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-set
    fn Set_(&self, name: DOMString, value: DOMString) {
        self.data.borrow_mut().insert(name, vec!(FormDatum::StringData(value)));
    }

    #[allow(unrooted_must_root)]
    // https://xhr.spec.whatwg.org/#dom-formdata-set
    fn Set(&self, name: DOMString, value: &Blob, filename: Option<DOMString>) {
        let file = FormDatum::FileData(JS::from_rooted(&self.get_file_from_blob(value, filename)));
        self.data.borrow_mut().insert(name, vec!(file));
    }
}

impl FormData {
    fn get_file_from_blob(&self, value: &Blob, filename: Option<DOMString>) -> Root<File> {
        let global = self.global.root();
        let f: Option<&File> = FileCast::to_ref(value);
        let name = filename.unwrap_or(f.map(|inner| inner.name().clone()).unwrap_or("blob".to_owned()));
        File::new(global.r(), value, name)
    }
}
<commit_msg>Cleanup, refactor FormDataMethods::Get<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::FormDataBinding;
use dom::bindings::codegen::Bindings::FormDataBinding::FormDataMethods;
use dom::bindings::codegen::InheritTypes::FileCast;
use dom::bindings::codegen::UnionTypes::FileOrString;
use dom::bindings::codegen::UnionTypes::FileOrString::{eFile, eString};
use dom::bindings::error::{Fallible};
use dom::bindings::global::{GlobalRef, GlobalField};
use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::blob::Blob;
use dom::file::File;
use dom::htmlformelement::HTMLFormElement;
use util::str::DOMString;

use std::borrow::ToOwned;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

#[derive(JSTraceable, Clone)]
#[must_root]
#[derive(HeapSizeOf)]
pub enum FormDatum {
    StringData(DOMString),
    FileData(JS<File>)
}

#[dom_struct]
pub struct FormData {
    reflector_: Reflector,
    data: DOMRefCell<HashMap<DOMString, Vec<FormDatum>>>,
    global: GlobalField,
    form: Option<JS<HTMLFormElement>>
}

impl FormData {
    fn new_inherited(form: Option<&HTMLFormElement>, global: GlobalRef) -> FormData {
        FormData {
            reflector_: Reflector::new(),
            data: DOMRefCell::new(HashMap::new()),
            global: GlobalField::from_rooted(&global),
            form: form.map(|f| JS::from_ref(f)),
        }
    }

    pub fn new(form: Option<&HTMLFormElement>, global: GlobalRef) -> Root<FormData> {
        reflect_dom_object(box FormData::new_inherited(form, global),
                           global, FormDataBinding::Wrap)
    }

    pub fn Constructor(global: GlobalRef, form: Option<&HTMLFormElement>) -> Fallible<Root<FormData>> {
        Ok(FormData::new(form, global))
    }
}

impl FormDataMethods for FormData {
    #[allow(unrooted_must_root)]
    // https://xhr.spec.whatwg.org/#dom-formdata-append
    fn Append(&self, name: DOMString, value: &Blob, filename: Option<DOMString>) {
        let file = FormDatum::FileData(JS::from_rooted(&self.get_file_from_blob(value, filename)));
        let mut data = self.data.borrow_mut();
        match data.entry(name) {
            Occupied(entry) => entry.into_mut().push(file),
            Vacant(entry) => {
                entry.insert(vec!(file));
            }
        }
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-append
    fn Append_(&self, name: DOMString, value: DOMString) {
        let mut data = self.data.borrow_mut();
        match data.entry(name) {
            Occupied(entry) => entry.into_mut().push(FormDatum::StringData(value)),
            Vacant  (entry) => { entry.insert(vec!(FormDatum::StringData(value))); },
        }
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-delete
    fn Delete(&self, name: DOMString) {
        self.data.borrow_mut().remove(&name);
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-get
    fn Get(&self, name: DOMString) -> Option<FileOrString> {
        self.data.borrow()
                 .get(&name)
                 .map(|entry| match entry[0] {
                     FormDatum::StringData(ref s) => eString(s.clone()),
                     FormDatum::FileData(ref f) => eFile(f.root()),
                 })
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-has
    fn Has(&self, name: DOMString) -> bool {
        self.data.borrow().contains_key(&name)
    }

    // https://xhr.spec.whatwg.org/#dom-formdata-set
    fn Set_(&self, name: DOMString, value: DOMString) {
        self.data.borrow_mut().insert(name, vec!(FormDatum::StringData(value)));
    }

    #[allow(unrooted_must_root)]
    // https://xhr.spec.whatwg.org/#dom-formdata-set
    fn Set(&self, name: DOMString, value: &Blob, filename: Option<DOMString>) {
        let file = FormDatum::FileData(JS::from_rooted(&self.get_file_from_blob(value, filename)));
        self.data.borrow_mut().insert(name, vec!(file));
    }
}

impl FormData {
    fn get_file_from_blob(&self, value: &Blob, filename: Option<DOMString>) -> Root<File> {
        let global = self.global.root();
        let f: Option<&File> = FileCast::to_ref(value);
        let name = filename.unwrap_or(f.map(|inner| inner.name().clone()).unwrap_or("blob".to_owned()));
        File::new(global.r(), value, name)
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

use std::fs;
use std::path::{Path, PathBuf};
use std::sync::*;
use std::thread;
use std::time::Duration;
use std::time::Instant;

use futures::channel::mpsc as future_mpsc;
use grpcio::{ChannelBuilder, Environment};

use backup::Task;
use collections::HashMap;
use engine_traits::IterOptions;
use engine_traits::{CfName, CF_DEFAULT, CF_WRITE, DATA_KEY_PREFIX_LEN};
use external_storage_export::make_local_backend;
use kvproto::backup::*;
use kvproto::kvrpcpb::*;
use kvproto::tikvpb::TikvClient;
use rand::Rng;
use test_raftstore::*;
use tidb_query_common::storage::scanner::{RangesScanner, RangesScannerOptions};
use tidb_query_common::storage::{IntervalRange, Range};
use tikv::coprocessor::checksum_crc64_xor;
use tikv::coprocessor::dag::TiKVStorage;
use tikv::storage::kv::Engine;
use tikv::storage::SnapshotStore;
use tikv::{config::BackupConfig, storage::kv::SnapContext};
use tikv_util::config::ReadableSize;
use tikv_util::worker::{LazyWorker, Worker};
use tikv_util::HandyRwLock;
use txn_types::TimeStamp;

pub struct TestSuite {
    pub cluster: Cluster<ServerCluster>,
    pub endpoints: HashMap<u64, LazyWorker<Task>>,
    pub tikv_cli: TikvClient,
    pub context: Context,
    pub ts: TimeStamp,
    pub bg_worker: Worker,

    _env: Arc<Environment>,
}

// Retry if encounter error
macro_rules! retry_req {
    ($call_req: expr, $check_resp: expr, $resp:ident, $retry:literal, $timeout:literal) => {
        let start = Instant::now();
        let timeout = Duration::from_millis($timeout);
        let mut tried_times = 0;
        while tried_times < $retry || start.elapsed() < timeout {
            if $check_resp {
                break;
            } else {
                thread::sleep(Duration::from_millis(200));
                tried_times += 1;
                $resp = $call_req;
                continue;
            }
        }
    };
}

impl TestSuite {
    pub fn new(count: usize, sst_max_size: u64) -> TestSuite {
        let mut cluster = new_server_cluster(1, count);
        // Increase the Raft tick interval to make this test case running reliably.
        configure_for_lease_read(&mut cluster, Some(100), None);
        cluster.run();

        let mut endpoints = HashMap::default();
        let bg_worker = Worker::new("backup-test");
        for (id, engines) in &cluster.engines {
            // Create and run backup endpoints.
            let sim = cluster.sim.rl();
            let backup_endpoint = backup::Endpoint::new(
                *id,
                sim.storages[&id].clone(),
                sim.region_info_accessors[&id].clone(),
                engines.kv.as_inner().clone(),
                BackupConfig {
                    num_threads: 4,
                    batch_size: 8,
                    sst_max_size: ReadableSize(sst_max_size),
                },
                sim.get_concurrency_manager(*id),
            );
            let mut worker = bg_worker.lazy_build(format!("backup-{}", id));
            worker.start(backup_endpoint);
            endpoints.insert(*id, worker);
        }

        // Make sure there is a leader.
        cluster.must_put(b"foo", b"foo");
        let region_id = 1;
        let leader = cluster.leader_of_region(region_id).unwrap();
        let leader_addr = cluster.sim.rl().get_addr(leader.get_store_id());

        let epoch = cluster.get_region_epoch(region_id);
        let mut context = Context::default();
        context.set_region_id(region_id);
        context.set_peer(leader);
        context.set_region_epoch(epoch);

        let env = Arc::new(Environment::new(1));
        let channel = ChannelBuilder::new(env.clone()).connect(&leader_addr);
        let tikv_cli = TikvClient::new(channel);

        TestSuite {
            cluster,
            endpoints,
            tikv_cli,
            context,
            ts: TimeStamp::zero(),
            _env: env,
            bg_worker,
        }
    }

    pub fn alloc_ts(&mut self) -> TimeStamp {
        *self.ts.incr()
    }

    pub fn stop(mut self) {
        for (_, mut worker) in self.endpoints {
            worker.stop();
        }
        self.bg_worker.stop();
        self.cluster.shutdown();
    }

    pub fn must_raw_put(&self, k: Vec<u8>, v: Vec<u8>, cf: String) {
        let mut request = RawPutRequest::default();
        request.set_context(self.context.clone());
        request.set_key(k);
        request.set_value(v);
        request.set_cf(cf);
        let mut response = self.tikv_cli.raw_put(&request).unwrap();
        retry_req!(
            self.tikv_cli.raw_put(&request).unwrap(),
            !response.has_region_error() && response.error.is_empty(),
            response,
            10,   // retry 10 times
            1000  // 1s timeout
        );
        assert!(
            !response.has_region_error(),
            "{:?}",
            response.get_region_error(),
        );
        assert!(response.error.is_empty(), "{:?}", response.get_error());
    }

    pub fn must_kv_prewrite(&self, muts: Vec<Mutation>, pk: Vec<u8>, ts: TimeStamp) {
        let mut prewrite_req = PrewriteRequest::default();
        prewrite_req.set_context(self.context.clone());
        prewrite_req.set_mutations(muts.into_iter().collect());
        prewrite_req.primary_lock = pk;
        prewrite_req.start_version = ts.into_inner();
        prewrite_req.lock_ttl = prewrite_req.start_version + 1;
        let mut prewrite_resp = self.tikv_cli.kv_prewrite(&prewrite_req).unwrap();
        retry_req!(
            self.tikv_cli.kv_prewrite(&prewrite_req).unwrap(),
            !prewrite_resp.has_region_error() && prewrite_resp.errors.is_empty(),
            prewrite_resp,
            10,   // retry 10 times
            3000  // 3s timeout
        );
        assert!(
            !prewrite_resp.has_region_error(),
            "{:?}",
            prewrite_resp.get_region_error()
        );
        assert!(
            prewrite_resp.errors.is_empty(),
            "{:?}",
            prewrite_resp.get_errors()
        );
    }

    pub fn must_kv_commit(&self, keys: Vec<Vec<u8>>, start_ts: TimeStamp, commit_ts: TimeStamp) {
        let mut commit_req = CommitRequest::default();
        commit_req.set_context(self.context.clone());
        commit_req.start_version = start_ts.into_inner();
        commit_req.set_keys(keys.into_iter().collect());
        commit_req.commit_version = commit_ts.into_inner();
        let mut commit_resp = self.tikv_cli.kv_commit(&commit_req).unwrap();
        retry_req!(
            self.tikv_cli.kv_commit(&commit_req).unwrap(),
            !commit_resp.has_region_error() && !commit_resp.has_error(),
            commit_resp,
            10,   // retry 10 times
            3000  // 3s timeout
        );
        assert!(
            !commit_resp.has_region_error(),
            "{:?}",
            commit_resp.get_region_error()
        );
        assert!(!commit_resp.has_error(), "{:?}", commit_resp.get_error());
    }

    pub fn must_kv_put(&mut self, key_count: usize, versions: usize) {
        for _ in 0..versions {
            for i in 0..key_count {
                let (k, v) = (format!("key_{}", i), format!("value_{}", i));
                // Prewrite
                let start_ts = self.alloc_ts();
                let mut mutation = Mutation::default();
                mutation.set_op(Op::Put);
                mutation.key = k.clone().into_bytes();
                mutation.value = v.clone().into_bytes();
                self.must_kv_prewrite(vec![mutation], k.clone().into_bytes(), start_ts);
                // Commit
                let commit_ts = self.alloc_ts();
                self.must_kv_commit(vec![k.clone().into_bytes()], start_ts, commit_ts);
            }
        }
    }

    pub fn backup(
        &self,
        start_key: Vec<u8>,
        end_key: Vec<u8>,
        begin_ts: TimeStamp,
        backup_ts: TimeStamp,
        path: &Path,
    ) -> future_mpsc::UnboundedReceiver<BackupResponse> {
        let mut req = BackupRequest::default();
        req.set_start_key(start_key);
        req.set_end_key(end_key);
        req.start_version = begin_ts.into_inner();
        req.end_version = backup_ts.into_inner();
        req.set_storage_backend(make_local_backend(path));
        req.set_is_raw_kv(false);
        let (tx, rx) = future_mpsc::unbounded();
        for end in self.endpoints.values() {
            let (task, _) = Task::new(req.clone(), tx.clone()).unwrap();
            end.scheduler().schedule(task).unwrap();
        }
        rx
    }

    pub fn backup_raw(
        &self,
        start_key: Vec<u8>,
        end_key: Vec<u8>,
        cf: String,
        path: &Path,
    ) -> future_mpsc::UnboundedReceiver<BackupResponse> {
        let mut req = BackupRequest::default();
        req.set_start_key(start_key);
        req.set_end_key(end_key);
        req.set_storage_backend(make_local_backend(path));
        req.set_is_raw_kv(true);
        req.set_cf(cf);
        let (tx, rx) = future_mpsc::unbounded();
        for end in self.endpoints.values() {
            let (task, _) = Task::new(req.clone(), tx.clone()).unwrap();
            end.scheduler().schedule(task).unwrap();
        }
        rx
    }

    pub fn admin_checksum(
        &self,
        backup_ts: TimeStamp,
        start: String,
        end: String,
    ) -> (u64, u64, u64) {
        let mut checksum = 0;
        let mut total_kvs = 0;
        let mut total_bytes = 0;
        let sim = self.cluster.sim.rl();
        let engine = sim.storages[&self.context.get_peer().get_store_id()].clone();
        let snap_ctx = SnapContext {
            pb_ctx: &self.context,
            ..Default::default()
        };
        let snapshot = engine.snapshot(snap_ctx).unwrap();
        let snap_store = SnapshotStore::new(
            snapshot,
            backup_ts,
            IsolationLevel::Si,
            false,
            Default::default(),
            false,
        );
        let mut scanner = RangesScanner::new(RangesScannerOptions {
            storage: TiKVStorage::new(snap_store, false),
            ranges: vec![Range::Interval(IntervalRange::from((start, end)))],
            scan_backward_in_range: false,
            is_key_only: false,
            is_scanned_range_aware: false,
        });
        let digest = crc64fast::Digest::new();
        while let Some((k, v)) = scanner.next().unwrap() {
            checksum = checksum_crc64_xor(checksum, digest.clone(), &k, &v);
            total_kvs += 1;
            total_bytes += (k.len() + v.len()) as u64;
        }
        (checksum, total_kvs, total_bytes)
    }

    pub fn gen_raw_kv(&self, key_idx: u64) -> (String, String) {
        (format!("key_{}", key_idx), format!("value_{}", key_idx))
    }

    pub fn raw_kv_checksum(&self, start: String, end: String, cf: CfName) -> (u64, u64, u64) {
        let start = start.into_bytes();
        let end = end.into_bytes();

        let mut total_kvs = 0;
        let mut total_bytes = 0;

        let sim = self.cluster.sim.rl();
        let engine = sim.storages[&self.context.get_peer().get_store_id()].clone();
        let snap_ctx = SnapContext {
            pb_ctx: &self.context,
            ..Default::default()
        };
        let snapshot = engine.snapshot(snap_ctx).unwrap();
        let mut iter_opt = IterOptions::default();
        if !end.is_empty() {
            iter_opt.set_upper_bound(&end, DATA_KEY_PREFIX_LEN);
        }
        let mut iter = snapshot.iter_cf(cf, iter_opt).unwrap();

        if !iter.seek(&start).unwrap() {
            return (0, 0, 0);
        }
        while iter.valid().unwrap() {
            total_kvs += 1;
            total_bytes += (iter.key().len() + iter.value().len()) as u64;
            iter.next().unwrap();
        }
        (0, total_kvs, total_bytes)
    }
}

// Extrat CF name from sst name.
pub fn name_to_cf(name: &str) -> CfName {
    if name.contains(CF_DEFAULT) {
        CF_DEFAULT
    } else if name.contains(CF_WRITE) {
        CF_WRITE
    } else {
        unreachable!()
    }
}

pub fn make_unique_dir(path: &Path) -> PathBuf {
    let uid: u64 = rand::thread_rng().gen();
    let tmp_suffix = format!("{:016x}", uid);
    let unique = path.join(tmp_suffix);
    fs::create_dir_all(&unique).unwrap();
    unique
}
<commit_msg>test_backup: typo Extrat -> Extract (#10355)<commit_after>// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

use std::fs;
use std::path::{Path, PathBuf};
use std::sync::*;
use std::thread;
use std::time::Duration;
use std::time::Instant;

use futures::channel::mpsc as future_mpsc;
use grpcio::{ChannelBuilder, Environment};

use backup::Task;
use collections::HashMap;
use engine_traits::IterOptions;
use engine_traits::{CfName, CF_DEFAULT, CF_WRITE, DATA_KEY_PREFIX_LEN};
use external_storage_export::make_local_backend;
use kvproto::backup::*;
use kvproto::kvrpcpb::*;
use kvproto::tikvpb::TikvClient;
use rand::Rng;
use test_raftstore::*;
use tidb_query_common::storage::scanner::{RangesScanner, RangesScannerOptions};
use tidb_query_common::storage::{IntervalRange, Range};
use tikv::coprocessor::checksum_crc64_xor;
use tikv::coprocessor::dag::TiKVStorage;
use tikv::storage::kv::Engine;
use tikv::storage::SnapshotStore;
use tikv::{config::BackupConfig, storage::kv::SnapContext};
use tikv_util::config::ReadableSize;
use tikv_util::worker::{LazyWorker, Worker};
use tikv_util::HandyRwLock;
use txn_types::TimeStamp;

pub struct TestSuite {
    pub cluster: Cluster<ServerCluster>,
    pub endpoints: HashMap<u64, LazyWorker<Task>>,
    pub tikv_cli: TikvClient,
    pub context: Context,
    pub ts: TimeStamp,
    pub bg_worker: Worker,

    _env: Arc<Environment>,
}

// Retry if encounter error
macro_rules! retry_req {
    ($call_req: expr, $check_resp: expr, $resp:ident, $retry:literal, $timeout:literal) => {
        let start = Instant::now();
        let timeout = Duration::from_millis($timeout);
        let mut tried_times = 0;
        while tried_times < $retry || start.elapsed() < timeout {
            if $check_resp {
                break;
            } else {
                thread::sleep(Duration::from_millis(200));
                tried_times += 1;
                $resp = $call_req;
                continue;
            }
        }
    };
}

impl TestSuite {
    pub fn new(count: usize, sst_max_size: u64) -> TestSuite {
        let mut cluster = new_server_cluster(1, count);
        // Increase the Raft tick interval to make this test case running reliably.
        configure_for_lease_read(&mut cluster, Some(100), None);
        cluster.run();

        let mut endpoints = HashMap::default();
        let bg_worker = Worker::new("backup-test");
        for (id, engines) in &cluster.engines {
            // Create and run backup endpoints.
            let sim = cluster.sim.rl();
            let backup_endpoint = backup::Endpoint::new(
                *id,
                sim.storages[&id].clone(),
                sim.region_info_accessors[&id].clone(),
                engines.kv.as_inner().clone(),
                BackupConfig {
                    num_threads: 4,
                    batch_size: 8,
                    sst_max_size: ReadableSize(sst_max_size),
                },
                sim.get_concurrency_manager(*id),
            );
            let mut worker = bg_worker.lazy_build(format!("backup-{}", id));
            worker.start(backup_endpoint);
            endpoints.insert(*id, worker);
        }

        // Make sure there is a leader.
        cluster.must_put(b"foo", b"foo");
        let region_id = 1;
        let leader = cluster.leader_of_region(region_id).unwrap();
        let leader_addr = cluster.sim.rl().get_addr(leader.get_store_id());

        let epoch = cluster.get_region_epoch(region_id);
        let mut context = Context::default();
        context.set_region_id(region_id);
        context.set_peer(leader);
        context.set_region_epoch(epoch);

        let env = Arc::new(Environment::new(1));
        let channel = ChannelBuilder::new(env.clone()).connect(&leader_addr);
        let tikv_cli = TikvClient::new(channel);

        TestSuite {
            cluster,
            endpoints,
            tikv_cli,
            context,
            ts: TimeStamp::zero(),
            _env: env,
            bg_worker,
        }
    }

    pub fn alloc_ts(&mut self) -> TimeStamp {
        *self.ts.incr()
    }

    pub fn stop(mut self) {
        for (_, mut worker) in self.endpoints {
            worker.stop();
        }
        self.bg_worker.stop();
        self.cluster.shutdown();
    }

    pub fn must_raw_put(&self, k: Vec<u8>, v: Vec<u8>, cf: String) {
        let mut request = RawPutRequest::default();
        request.set_context(self.context.clone());
        request.set_key(k);
        request.set_value(v);
        request.set_cf(cf);
        let mut response = self.tikv_cli.raw_put(&request).unwrap();
        retry_req!(
            self.tikv_cli.raw_put(&request).unwrap(),
            !response.has_region_error() && response.error.is_empty(),
            response,
            10,   // retry 10 times
            1000  // 1s timeout
        );
        assert!(
            !response.has_region_error(),
            "{:?}",
            response.get_region_error(),
        );
        assert!(response.error.is_empty(), "{:?}", response.get_error());
    }

    pub fn must_kv_prewrite(&self, muts: Vec<Mutation>, pk: Vec<u8>, ts: TimeStamp) {
        let mut prewrite_req = PrewriteRequest::default();
        prewrite_req.set_context(self.context.clone());
        prewrite_req.set_mutations(muts.into_iter().collect());
        prewrite_req.primary_lock = pk;
        prewrite_req.start_version = ts.into_inner();
        prewrite_req.lock_ttl = prewrite_req.start_version + 1;
        let mut prewrite_resp = self.tikv_cli.kv_prewrite(&prewrite_req).unwrap();
        retry_req!(
            self.tikv_cli.kv_prewrite(&prewrite_req).unwrap(),
            !prewrite_resp.has_region_error() && prewrite_resp.errors.is_empty(),
            prewrite_resp,
            10,   // retry 10 times
            3000  // 3s timeout
        );
        assert!(
            !prewrite_resp.has_region_error(),
            "{:?}",
            prewrite_resp.get_region_error()
        );
        assert!(
            prewrite_resp.errors.is_empty(),
            "{:?}",
            prewrite_resp.get_errors()
        );
    }

    pub fn must_kv_commit(&self, keys: Vec<Vec<u8>>, start_ts: TimeStamp, commit_ts: TimeStamp) {
        let mut commit_req = CommitRequest::default();
        commit_req.set_context(self.context.clone());
        commit_req.start_version = start_ts.into_inner();
        commit_req.set_keys(keys.into_iter().collect());
        commit_req.commit_version = commit_ts.into_inner();
        let mut commit_resp = self.tikv_cli.kv_commit(&commit_req).unwrap();
        retry_req!(
            self.tikv_cli.kv_commit(&commit_req).unwrap(),
            !commit_resp.has_region_error() && !commit_resp.has_error(),
            commit_resp,
            10,   // retry 10 times
            3000  // 3s timeout
        );
        assert!(
            !commit_resp.has_region_error(),
            "{:?}",
            commit_resp.get_region_error()
        );
        assert!(!commit_resp.has_error(), "{:?}", commit_resp.get_error());
    }

    pub fn must_kv_put(&mut self, key_count: usize, versions: usize) {
        for _ in 0..versions {
            for i in 0..key_count {
                let (k, v) = (format!("key_{}", i), format!("value_{}", i));
                // Prewrite
                let start_ts = self.alloc_ts();
                let mut mutation = Mutation::default();
                mutation.set_op(Op::Put);
                mutation.key = k.clone().into_bytes();
                mutation.value = v.clone().into_bytes();
                self.must_kv_prewrite(vec![mutation], k.clone().into_bytes(), start_ts);
                // Commit
                let commit_ts = self.alloc_ts();
                self.must_kv_commit(vec![k.clone().into_bytes()], start_ts, commit_ts);
            }
        }
    }

    pub fn backup(
        &self,
        start_key: Vec<u8>,
        end_key: Vec<u8>,
        begin_ts: TimeStamp,
        backup_ts: TimeStamp,
        path: &Path,
    ) -> future_mpsc::UnboundedReceiver<BackupResponse> {
        let mut req = BackupRequest::default();
        req.set_start_key(start_key);
        req.set_end_key(end_key);
        req.start_version = begin_ts.into_inner();
        req.end_version = backup_ts.into_inner();
        req.set_storage_backend(make_local_backend(path));
        req.set_is_raw_kv(false);
        let (tx, rx) = future_mpsc::unbounded();
        for end in self.endpoints.values() {
            let (task, _) = Task::new(req.clone(), tx.clone()).unwrap();
            end.scheduler().schedule(task).unwrap();
        }
        rx
    }

    pub fn backup_raw(
        &self,
        start_key: Vec<u8>,
        end_key: Vec<u8>,
        cf: String,
        path: &Path,
    ) -> future_mpsc::UnboundedReceiver<BackupResponse> {
        let mut req = BackupRequest::default();
        req.set_start_key(start_key);
        req.set_end_key(end_key);
        req.set_storage_backend(make_local_backend(path));
        req.set_is_raw_kv(true);
        req.set_cf(cf);
        let (tx, rx) = future_mpsc::unbounded();
        for end in self.endpoints.values() {
            let (task, _) = Task::new(req.clone(), tx.clone()).unwrap();
            end.scheduler().schedule(task).unwrap();
        }
        rx
    }

    pub fn admin_checksum(
        &self,
        backup_ts: TimeStamp,
        start: String,
        end: String,
    ) -> (u64, u64, u64) {
        let mut checksum = 0;
        let mut total_kvs = 0;
        let mut total_bytes = 0;
        let sim = self.cluster.sim.rl();
        let engine = sim.storages[&self.context.get_peer().get_store_id()].clone();
        let snap_ctx = SnapContext {
            pb_ctx: &self.context,
            ..Default::default()
        };
        let snapshot = engine.snapshot(snap_ctx).unwrap();
        let snap_store = SnapshotStore::new(
            snapshot,
            backup_ts,
            IsolationLevel::Si,
            false,
            Default::default(),
            false,
        );
        let mut scanner = RangesScanner::new(RangesScannerOptions {
            storage: TiKVStorage::new(snap_store, false),
            ranges: vec![Range::Interval(IntervalRange::from((start, end)))],
            scan_backward_in_range: false,
            is_key_only: false,
            is_scanned_range_aware: false,
        });
        let digest = crc64fast::Digest::new();
        while let Some((k, v)) = scanner.next().unwrap() {
            checksum = checksum_crc64_xor(checksum, digest.clone(), &k, &v);
            total_kvs += 1;
            total_bytes += (k.len() + v.len()) as u64;
        }
        (checksum, total_kvs, total_bytes)
    }

    pub fn gen_raw_kv(&self, key_idx: u64) -> (String, String) {
        (format!("key_{}", key_idx), format!("value_{}", key_idx))
    }

    pub fn raw_kv_checksum(&self, start: String, end: String, cf: CfName) -> (u64, u64, u64) {
        let start = start.into_bytes();
        let end = end.into_bytes();

        let mut total_kvs = 0;
        let mut total_bytes = 0;

        let sim = self.cluster.sim.rl();
        let engine = sim.storages[&self.context.get_peer().get_store_id()].clone();
        let snap_ctx = SnapContext {
            pb_ctx: &self.context,
            ..Default::default()
        };
        let snapshot = engine.snapshot(snap_ctx).unwrap();
        let mut iter_opt = IterOptions::default();
        if !end.is_empty() {
            iter_opt.set_upper_bound(&end, DATA_KEY_PREFIX_LEN);
        }
        let mut iter = snapshot.iter_cf(cf, iter_opt).unwrap();

        if !iter.seek(&start).unwrap() {
            return (0, 0, 0);
        }
        while iter.valid().unwrap() {
            total_kvs += 1;
            total_bytes += (iter.key().len() + iter.value().len()) as u64;
            iter.next().unwrap();
        }
        (0, total_kvs, total_bytes)
    }
}

// Extract CF name from sst name.
pub fn name_to_cf(name: &str) -> CfName {
    if name.contains(CF_DEFAULT) {
        CF_DEFAULT
    } else if name.contains(CF_WRITE) {
        CF_WRITE
    } else {
        unreachable!()
    }
}

pub fn make_unique_dir(path: &Path) -> PathBuf {
    let uid: u64 = rand::thread_rng().gen();
    let tmp_suffix = format!("{:016x}", uid);
    let unique = path.join(tmp_suffix);
    fs::create_dir_all(&unique).unwrap();
    unique
}
<|endoftext|>


<commit_before>//! Logging utilities

use lazy_static::lazy_static;
use std::collections::VecDeque;
use std::sync::Mutex;

/// Saves all log records in a global deque.
///
/// Uses a `DebugView` to access it.
struct CursiveLogger;

static LOGGER: CursiveLogger = CursiveLogger;

/// A log record.
pub struct Record {
    /// Log level used for this record
    pub level: log::Level,
    /// Time this message was logged
    pub time: chrono::DateTime<chrono::Utc>,
    /// Message content
    pub message: String,
}

lazy_static! {
    /// Circular buffer for logs. Use it to implement `DebugView`.
    pub static ref LOGS: Mutex<VecDeque<Record>> =
        Mutex::new(VecDeque::new());
}

impl log::Log for CursiveLogger {
    fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
        true
    }

    fn log(&self, record: &log::Record<'_>) {
        let mut logs = LOGS.lock().unwrap();
        // TODO: customize the format? Use colors? Save more info?
        if logs.len() == logs.capacity() {
            logs.pop_front();
        }
        logs.push_back(Record {
            level: record.level(),
            message: format!("{}", record.args()),
            time: chrono::Utc::now(),
        });
    }

    fn flush(&self) {}
}

/// Initialize the Cursive logger.
///
/// Make sure this is the only logger your are using.
///
/// Use a [`DebugView`](crate::views::DebugView) to see the logs, or use
/// [`Cursive::toggle_debug_console()`](crate::Cursive::toggle_debug_console()).
pub fn init() {
    // TODO: Configure the deque size?
    LOGS.lock().unwrap().reserve(1_000);

    // This will panic if `set_logger` was already called.
    log::set_logger(&LOGGER).unwrap();

    // TODO: read the level from env variable? From argument?
    log::set_max_level(log::LevelFilter::Trace);
}
<commit_msg>More public fields in cursive::logger<commit_after>//! Logging utilities

use lazy_static::lazy_static;
use std::collections::VecDeque;
use std::sync::Mutex;

/// Saves all log records in a global deque.
///
/// Uses a `DebugView` to access it.
pub struct CursiveLogger;

static LOGGER: CursiveLogger = CursiveLogger;

/// A log record.
pub struct Record {
    /// Log level used for this record
    pub level: log::Level,
    /// Time this message was logged
    pub time: chrono::DateTime<chrono::Utc>,
    /// Message content
    pub message: String,
}

lazy_static! {
    /// Circular buffer for logs. Use it to implement `DebugView`.
    pub static ref LOGS: Mutex<VecDeque<Record>> =
        Mutex::new(VecDeque::new());
}

/// Log a record in cursive's log queue.
pub fn log(record: &log::Record<'_>) {
    let mut logs = LOGS.lock().unwrap();
    // TODO: customize the format? Use colors? Save more info?
    if logs.len() == logs.capacity() {
        logs.pop_front();
    }
    logs.push_back(Record {
        level: record.level(),
        message: format!("{}", record.args()),
        time: chrono::Utc::now(),
    });
}

impl log::Log for CursiveLogger {
    fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
        true
    }

    fn log(&self, record: &log::Record<'_>) {
        log(record);
    }

    fn flush(&self) {}
}

/// Initialize the Cursive logger.
///
/// Make sure this is the only logger your are using.
///
/// Use a [`DebugView`](crate::views::DebugView) to see the logs, or use
/// [`Cursive::toggle_debug_console()`](crate::Cursive::toggle_debug_console()).
pub fn init() {
    // TODO: Configure the deque size?
    reserve_logs(1_000);

    // This will panic if `set_logger` was already called.
    log::set_logger(&LOGGER).unwrap();

    // TODO: read the level from env variable? From argument?
    log::set_max_level(log::LevelFilter::Trace);
}

/// Return a logger that stores records in cursive's log queue.
///
/// These logs can then be read by a [`DebugView`](crate::views::DebugView).
///
/// An easier alternative might be to use [`init()`].
pub fn get_logger() -> CursiveLogger {
    reserve_logs(1_000);
    CursiveLogger
}

/// Adds `n` more entries to cursive's log queue.
///
/// Most of the time you don't need to use this directly.
///
/// You should call this if you're not using `init()` nor `get_logger()`.
pub fn reserve_logs(n: usize) {
    LOGS.lock().unwrap().reserve(n);
}
<|endoftext|>


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

/// Connect events to sending a message.
///
/// Rule #1:
/// Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// Rule #2:
/// Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// Rule #3:
/// Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// Rule #4:
/// Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// Rule #1:
/// Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// Rule #2:
/// Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}
<commit_msg>Revert "Temporary fix to publish the crate"<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

include!("../relm-state/src/macros.rs");
<|endoftext|>