<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 app_units::Au;
use std::collections::HashMap;
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions};

use dwrote;

lazy_static! {
    static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
        family_name: "Arial".to_owned(),
        weight: dwrote::FontWeight::Regular,
        stretch: dwrote::FontStretch::Normal,
        style: dwrote::FontStyle::Normal,
    };
}

pub struct FontContext {
    fonts: HashMap<FontKey, dwrote::Font>,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

impl FontContext {
    pub fn new() -> FontContext {
        FontContext {
            fonts: HashMap::new(),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, _: &[u8]) {
        if self.fonts.contains_key(font_key) {
            return
        }

        debug!("DWrite WR backend can't do raw fonts yet, using Arial instead");

        self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
        if self.fonts.contains_key(font_key) {
            return
        }

        let system_fc = dwrote::FontCollection::system();
        let realized_font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
        self.fonts.insert((*font_key).clone(), realized_font);
    }

    fn get_glyph_dimensions_and_maybe_rasterize(&self,
                                                font_key: FontKey,
                                                size: Au,
                                                glyph: u32,
                                                render_mode: Option<FontRenderMode>)
                                                -> (Option<GlyphDimensions>, Option<RasterizedGlyph>)
    {
        let font = self.fonts.get(&font_key).unwrap();
        let face = font.create_font_face();
        let glyph = glyph as u16;

        let glyph = glyph as u16;
        let advance = 0.0f32;
        let offset = dwrote::GlyphOffset { advanceOffset: 0.0, ascenderOffset: 0.0 };

        let glyph_run = dwrote::DWRITE_GLYPH_RUN {
            fontFace: unsafe { face.as_ptr() },
            fontEmSize: size.to_f32_px(), // size in DIPs (1/96", same as CSS pixels)
            glyphCount: 1,
            glyphIndices: &glyph,
            glyphAdvances: &advance,
            glyphOffsets: &offset,
            isSideways: 0,
            bidiLevel: 0,
        };

        // dwrite requires DWRITE_RENDERING_MODE_ALIASED if the texture
        // type is DWRITE_TEXTURE_ALIASED_1x1.  If CLEARTYPE_3x1,
        // then the other modes can be used.

        // TODO(vlad): get_glyph_dimensions needs to take the render mode into account
        // but the API doesn't give it to us right now.  Just assume subpixel.
        let (r_mode, m_mode, tex_type) = match render_mode {
            Some(FontRenderMode::Mono) => (dwrote::DWRITE_RENDERING_MODE_ALIASED,
                                           dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
                                           dwrote::DWRITE_TEXTURE_ALIASED_1x1),
            Some(FontRenderMode::Alpha) => (dwrote::DWRITE_RENDERING_MODE_GDI_NATURAL,
                                            dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
                                            dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1),
            Some(FontRenderMode::Subpixel) | None => (dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL,
                                                      dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
                                                      dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1),
        };

        // XX use the xform to handle subpixel positioning (what skia does), I believe that keeps
        //let xform = dwrote::DWRITE_MATRIX { m11: 1.0, m12: 0.0, m21: 0.0, m22: 1.0, dx: 0.0, dy: 0.0 };
        let analysis = dwrote::GlyphRunAnalysis::create(&glyph_run, 1.0, None, r_mode, m_mode, 0.0, 0.0);
        let bounds = analysis.get_alpha_texture_bounds(tex_type);

        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;
        let dims = GlyphDimensions {
            left: bounds.left,
            top: -bounds.top,
            width: width,
            height: height,
        };

        // if empty, then nothing
        if dims.width == 0 || dims.height == 0 {
            return (None, None);
        }

        // if we weren't asked to rasterize, we're done
        if render_mode.is_none() {
            return (Some(dims), None);
        }

        let pixels = analysis.create_alpha_texture(tex_type, bounds);
        let mut rgba_pixels = vec![0; pixels.len() * 4];

        match render_mode.unwrap() {
            FontRenderMode::Mono => {
                for i in 0..pixels.len() {
                    rgba_pixels[i*4+0] = 0xff;
                    rgba_pixels[i*4+1] = 0xff;
                    rgba_pixels[i*4+2] = 0xff;
                    rgba_pixels[i*4+3] = pixels[i];
                }
            }
            FontRenderMode::Alpha => {
                for i in 0..pixels.len()/3 {
                    // TODO(vlad): we likely need to do something smarter
                    let alpha = (pixels[i*3+0] as u32 + pixels[i*3+0] as u32 + pixels[i*3+0] as u32) / 3;
                    rgba_pixels[i*4+0] = 0xff;
                    rgba_pixels[i*4+1] = 0xff;
                    rgba_pixels[i*4+2] = 0xff;
                    rgba_pixels[i*4+3] = alpha as u8;
                }
            }
            FontRenderMode::Subpixel => {
                for i in 0..pixels.len()/3 {
                    rgba_pixels[i*4+0] = pixels[i*3+0];
                    rgba_pixels[i*4+1] = pixels[i*3+1];
                    rgba_pixels[i*4+2] = pixels[i*3+2];
                    rgba_pixels[i*4+3] = 0xff;
                }
            }
        }

        (Some(dims), Some(RasterizedGlyph {
            width: dims.width,
            height: dims.height,
            bytes: rgba_pixels,
        }))
    }

    pub fn get_glyph_dimensions(&self,
                                font_key: FontKey,
                                size: Au,
                                glyph: u32) -> Option<GlyphDimensions> {
        let (maybe_dims, _) =
            self.get_glyph_dimensions_and_maybe_rasterize(font_key, size, glyph, None);
        maybe_dims
    }

    pub fn rasterize_glyph(&mut self,
                           font_key: FontKey,
                           size: Au,
                           glyph: u32,
                           render_mode: FontRenderMode) -> Option<RasterizedGlyph> {
        let (_, maybe_glyph) =
            self.get_glyph_dimensions_and_maybe_rasterize(font_key, size, glyph, Some(render_mode));
        maybe_glyph
    }
}
<commit_msg>Auto merge of #667 - vvuk:master, r=kvark<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 app_units::Au;
use std::collections::HashMap;
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions};

use dwrote;

lazy_static! {
    static ref DEFAULT_FONT_DESCRIPTOR: dwrote::FontDescriptor = dwrote::FontDescriptor {
        family_name: "Arial".to_owned(),
        weight: dwrote::FontWeight::Regular,
        stretch: dwrote::FontStretch::Normal,
        style: dwrote::FontStyle::Normal,
    };
}

pub struct FontContext {
    fonts: HashMap<FontKey, dwrote::Font>,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

impl FontContext {
    pub fn new() -> FontContext {
        FontContext {
            fonts: HashMap::new(),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, _: &[u8]) {
        if self.fonts.contains_key(font_key) {
            return
        }

        debug!("DWrite WR backend can't do raw fonts yet, using Arial instead");

        self.add_native_font(font_key, DEFAULT_FONT_DESCRIPTOR.clone());
    }

    pub fn add_native_font(&mut self, font_key: &FontKey, font_handle: dwrote::FontDescriptor) {
        if self.fonts.contains_key(font_key) {
            return
        }

        let system_fc = dwrote::FontCollection::system();
        let realized_font = system_fc.get_font_from_descriptor(&font_handle).unwrap();
        self.fonts.insert((*font_key).clone(), realized_font);
    }

    fn get_glyph_dimensions_and_maybe_rasterize(&self,
                                                font_key: FontKey,
                                                size: Au,
                                                glyph: u32,
                                                render_mode: Option<FontRenderMode>)
                                                -> (Option<GlyphDimensions>, Option<RasterizedGlyph>)
    {
        let font = self.fonts.get(&font_key).unwrap();
        let face = font.create_font_face();
        let glyph = glyph as u16;

        let glyph = glyph as u16;
        let advance = 0.0f32;
        let offset = dwrote::GlyphOffset { advanceOffset: 0.0, ascenderOffset: 0.0 };

        let glyph_run = dwrote::DWRITE_GLYPH_RUN {
            fontFace: unsafe { face.as_ptr() },
            fontEmSize: size.to_f32_px(), // size in DIPs (1/96", same as CSS pixels)
            glyphCount: 1,
            glyphIndices: &glyph,
            glyphAdvances: &advance,
            glyphOffsets: &offset,
            isSideways: 0,
            bidiLevel: 0,
        };

        // dwrite requires DWRITE_RENDERING_MODE_ALIASED if the texture
        // type is DWRITE_TEXTURE_ALIASED_1x1.  If CLEARTYPE_3x1,
        // then the other modes can be used.

        // TODO(vlad): get_glyph_dimensions needs to take the render mode into account
        // but the API doesn't give it to us right now.  Just assume subpixel.
        let (r_mode, m_mode, tex_type) = match render_mode {
            Some(FontRenderMode::Mono) => (dwrote::DWRITE_RENDERING_MODE_ALIASED,
                                           dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
                                           dwrote::DWRITE_TEXTURE_ALIASED_1x1),
            Some(FontRenderMode::Alpha) => (dwrote::DWRITE_RENDERING_MODE_GDI_NATURAL,
                                            dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
                                            dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1),
            Some(FontRenderMode::Subpixel) | None => (dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL,
                                                      dwrote::DWRITE_MEASURING_MODE_GDI_NATURAL,
                                                      dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1),
        };

        // XX use the xform to handle subpixel positioning (what skia does), I believe that keeps
        //let xform = dwrote::DWRITE_MATRIX { m11: 1.0, m12: 0.0, m21: 0.0, m22: 1.0, dx: 0.0, dy: 0.0 };
        let analysis = dwrote::GlyphRunAnalysis::create(&glyph_run, 1.0, None, r_mode, m_mode, 0.0, 0.0);
        let bounds = analysis.get_alpha_texture_bounds(tex_type);

        let width = (bounds.right - bounds.left) as u32;
        let height = (bounds.bottom - bounds.top) as u32;
        let dims = GlyphDimensions {
            left: bounds.left,
            top: -bounds.top,
            width: width,
            height: height,
        };

        // if empty, then nothing
        if dims.width == 0 || dims.height == 0 {
            return (None, None);
        }

        // if we weren't asked to rasterize, we're done
        if render_mode.is_none() {
            return (Some(dims), None);
        }

        let pixels = analysis.create_alpha_texture(tex_type, bounds);
        let rgba_pixels = match render_mode.unwrap() {
            FontRenderMode::Mono => {
                let mut rgba_pixels = vec![0; pixels.len() * 4];
                for i in 0..pixels.len() {
                    rgba_pixels[i*4+0] = 0xff;
                    rgba_pixels[i*4+1] = 0xff;
                    rgba_pixels[i*4+2] = 0xff;
                    rgba_pixels[i*4+3] = pixels[i];
                }
                rgba_pixels
            }
            FontRenderMode::Alpha => {
                let mut rgba_pixels = vec![0; pixels.len()/3 * 4];
                for i in 0..pixels.len()/3 {
                    // TODO(vlad): we likely need to do something smarter
                    let alpha = (pixels[i*3+0] as u32 + pixels[i*3+0] as u32 + pixels[i*3+0] as u32) / 3;
                    rgba_pixels[i*4+0] = 0xff;
                    rgba_pixels[i*4+1] = 0xff;
                    rgba_pixels[i*4+2] = 0xff;
                    rgba_pixels[i*4+3] = alpha as u8;
                }
                rgba_pixels
            }
            FontRenderMode::Subpixel => {
                let mut rgba_pixels = vec![0; pixels.len()/3 * 4];
                for i in 0..pixels.len()/3 {
                    rgba_pixels[i*4+0] = pixels[i*3+0];
                    rgba_pixels[i*4+1] = pixels[i*3+1];
                    rgba_pixels[i*4+2] = pixels[i*3+2];
                    rgba_pixels[i*4+3] = 0xff;
                }
                rgba_pixels
            }
        };

        (Some(dims), Some(RasterizedGlyph {
            width: dims.width,
            height: dims.height,
            bytes: rgba_pixels,
        }))
    }

    pub fn get_glyph_dimensions(&self,
                                font_key: FontKey,
                                size: Au,
                                glyph: u32) -> Option<GlyphDimensions> {
        let (maybe_dims, _) =
            self.get_glyph_dimensions_and_maybe_rasterize(font_key, size, glyph, None);
        maybe_dims
    }

    pub fn rasterize_glyph(&mut self,
                           font_key: FontKey,
                           size: Au,
                           glyph: u32,
                           render_mode: FontRenderMode) -> Option<RasterizedGlyph> {
        let (_, maybe_glyph) =
            self.get_glyph_dimensions_and_maybe_rasterize(font_key, size, glyph, Some(render_mode));
        maybe_glyph
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 Tyler Neely
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate libc;
extern crate rocksdb;

mod util;

use libc::size_t;

use rocksdb::{DBVector, Error, IteratorMode, Options, WriteBatch, DB};
use util::DBPath;

#[test]
fn test_db_vector() {
    use std::mem;
    let len: size_t = 4;
    let data: *mut u8 = unsafe { libc::calloc(len, mem::size_of::<u8>()) as *mut u8 };
    let v = unsafe { DBVector::from_c(data, len) };
    let ctrl = [0u8, 0, 0, 0];
    assert_eq!(&*v, &ctrl[..]);
}

#[test]
fn external() {
    let path = DBPath::new("_rust_rocksdb_externaltest");

    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let r: Result<Option<DBVector>, Error> = db.get(b"k1");

        assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
        assert!(db.delete(b"k1").is_ok());
        assert!(db.get(b"k1").unwrap().is_none());
    }
}

#[test]
fn db_vector_as_ref_byte_slice() {
    let path = DBPath::new("_rust_rocksdb_db_vector_as_ref_byte_slice");

    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let r: Result<Option<DBVector>, Error> = db.get(b"k1");
        let vector = r.unwrap().unwrap();

        assert!(get_byte_slice(&vector) == b"v1111");
    }
}

fn get_byte_slice<T: AsRef<[u8]>>(source: &'_ T) -> &'_ [u8] {
    source.as_ref()
}

#[test]
fn errors_do_stuff() {
    let path = DBPath::new("_rust_rocksdb_error");
    let _db = DB::open_default(&path).unwrap();
    let opts = Options::default();
    // The DB will still be open when we try to destroy it and the lock should fail.
    match DB::destroy(&opts, &path) {
        Err(s) => {
            let message = s.to_string();
            assert!(message.find("IO error:").is_some());
            assert!(message.find("_rust_rocksdb_error").is_some());
            assert!(message.find("/LOCK:").is_some());
        }
        Ok(_) => panic!("should fail"),
    }
}

#[test]
fn writebatch_works() {
    let path = DBPath::new("_rust_rocksdb_writebacktest");
    {
        let db = DB::open_default(&path).unwrap();
        {
            // test put
            let mut batch = WriteBatch::default();
            assert!(db.get(b"k1").unwrap().is_none());
            assert_eq!(batch.len(), 0);
            assert!(batch.is_empty());
            let _ = batch.put(b"k1", b"v1111");
            assert_eq!(batch.len(), 1);
            assert!(!batch.is_empty());
            assert!(db.get(b"k1").unwrap().is_none());
            assert!(db.write(batch).is_ok());
            let r: Result<Option<DBVector>, Error> = db.get(b"k1");
            assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
        }
        {
            // test delete
            let mut batch = WriteBatch::default();
            let _ = batch.delete(b"k1");
            assert_eq!(batch.len(), 1);
            assert!(!batch.is_empty());
            assert!(db.write(batch).is_ok());
            assert!(db.get(b"k1").unwrap().is_none());
        }
        {
            // test size_in_bytes
            let mut batch = WriteBatch::default();
            let before = batch.size_in_bytes();
            let _ = batch.put(b"k1", b"v1234567890");
            let after = batch.size_in_bytes();
            assert!(before + 10 <= after);
        }
    }
}

#[test]
fn iterator_test() {
    let path = DBPath::new("_rust_rocksdb_iteratortest");
    {
        let data = [(b"k1", b"v1111"), (b"k2", b"v2222"), (b"k3", b"v3333")];
        let db = DB::open_default(&path).unwrap();

        for (key, value) in &data {
            assert!(db.put(key, value).is_ok());
        }

        let iter = db.iterator(IteratorMode::Start);

        for (idx, (db_key, db_value)) in iter.enumerate() {
            let (key, value) = data[idx];
            assert_eq!((&key[..], &value[..]), (db_key.as_ref(), db_value.as_ref()));
        }
    }
}

#[test]
fn snapshot_test() {
    let path = DBPath::new("_rust_rocksdb_snapshottest");
    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let snap = db.snapshot();
        assert!(snap.get(b"k1").unwrap().unwrap().to_utf8().unwrap() == "v1111");

        assert!(db.put(b"k2", b"v2222").is_ok());

        assert!(db.get(b"k2").unwrap().is_some());
        assert!(snap.get(b"k2").unwrap().is_none());
    }
}

#[test]
fn set_option_test() {
    let path = DBPath::new("_rust_rocksdb_set_optionstest");
    {
        let db = DB::open_default(&path).unwrap();
        // set an option to valid values
        assert!(db
            .set_options(&[("disable_auto_compactions", "true")])
            .is_ok());
        assert!(db
            .set_options(&[("disable_auto_compactions", "false")])
            .is_ok());
        // invalid names/values should result in an error
        assert!(db
            .set_options(&[("disable_auto_compactions", "INVALID_VALUE")])
            .is_err());
        assert!(db
            .set_options(&[("INVALID_NAME", "INVALID_VALUE")])
            .is_err());
        // option names/values must not contain NULLs
        assert!(db
            .set_options(&[("disable_auto_compactions", "true\0")])
            .is_err());
        assert!(db
            .set_options(&[("disable_auto_compactions\0", "true")])
            .is_err());
        // empty options are not allowed
        assert!(db.set_options(&[]).is_err());
        // multiple options can be set in a single API call
        let multiple_options = [
            ("paranoid_file_checks", "true"),
            ("report_bg_io_stats", "true"),
        ];
        db.set_options(&multiple_options).unwrap();
    }
}
<commit_msg>Add test for sync snapshot.<commit_after>// Copyright 2019 Tyler Neely
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![feature(thread_spawn_unchecked)]

extern crate libc;
extern crate rocksdb;

mod util;

use libc::size_t;

use rocksdb::{DBVector, Error, IteratorMode, Options, WriteBatch, DB};
use util::DBPath;
use std::thread;

#[test]
fn test_db_vector() {
    use std::mem;
    let len: size_t = 4;
    let data: *mut u8 = unsafe { libc::calloc(len, mem::size_of::<u8>()) as *mut u8 };
    let v = unsafe { DBVector::from_c(data, len) };
    let ctrl = [0u8, 0, 0, 0];
    assert_eq!(&*v, &ctrl[..]);
}

#[test]
fn external() {
    let path = DBPath::new("_rust_rocksdb_externaltest");

    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let r: Result<Option<DBVector>, Error> = db.get(b"k1");

        assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
        assert!(db.delete(b"k1").is_ok());
        assert!(db.get(b"k1").unwrap().is_none());
    }
}

#[test]
fn db_vector_as_ref_byte_slice() {
    let path = DBPath::new("_rust_rocksdb_db_vector_as_ref_byte_slice");

    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let r: Result<Option<DBVector>, Error> = db.get(b"k1");
        let vector = r.unwrap().unwrap();

        assert!(get_byte_slice(&vector) == b"v1111");
    }
}

fn get_byte_slice<T: AsRef<[u8]>>(source: &'_ T) -> &'_ [u8] {
    source.as_ref()
}

#[test]
fn errors_do_stuff() {
    let path = DBPath::new("_rust_rocksdb_error");
    let _db = DB::open_default(&path).unwrap();
    let opts = Options::default();
    // The DB will still be open when we try to destroy it and the lock should fail.
    match DB::destroy(&opts, &path) {
        Err(s) => {
            let message = s.to_string();
            assert!(message.find("IO error:").is_some());
            assert!(message.find("_rust_rocksdb_error").is_some());
            assert!(message.find("/LOCK:").is_some());
        }
        Ok(_) => panic!("should fail"),
    }
}

#[test]
fn writebatch_works() {
    let path = DBPath::new("_rust_rocksdb_writebacktest");
    {
        let db = DB::open_default(&path).unwrap();
        {
            // test put
            let mut batch = WriteBatch::default();
            assert!(db.get(b"k1").unwrap().is_none());
            assert_eq!(batch.len(), 0);
            assert!(batch.is_empty());
            let _ = batch.put(b"k1", b"v1111");
            assert_eq!(batch.len(), 1);
            assert!(!batch.is_empty());
            assert!(db.get(b"k1").unwrap().is_none());
            assert!(db.write(batch).is_ok());
            let r: Result<Option<DBVector>, Error> = db.get(b"k1");
            assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
        }
        {
            // test delete
            let mut batch = WriteBatch::default();
            let _ = batch.delete(b"k1");
            assert_eq!(batch.len(), 1);
            assert!(!batch.is_empty());
            assert!(db.write(batch).is_ok());
            assert!(db.get(b"k1").unwrap().is_none());
        }
        {
            // test size_in_bytes
            let mut batch = WriteBatch::default();
            let before = batch.size_in_bytes();
            let _ = batch.put(b"k1", b"v1234567890");
            let after = batch.size_in_bytes();
            assert!(before + 10 <= after);
        }
    }
}

#[test]
fn iterator_test() {
    let path = DBPath::new("_rust_rocksdb_iteratortest");
    {
        let data = [(b"k1", b"v1111"), (b"k2", b"v2222"), (b"k3", b"v3333")];
        let db = DB::open_default(&path).unwrap();

        for (key, value) in &data {
            assert!(db.put(key, value).is_ok());
        }

        let iter = db.iterator(IteratorMode::Start);

        for (idx, (db_key, db_value)) in iter.enumerate() {
            let (key, value) = data[idx];
            assert_eq!((&key[..], &value[..]), (db_key.as_ref(), db_value.as_ref()));
        }
    }
}

#[test]
fn snapshot_test() {
    let path = DBPath::new("_rust_rocksdb_snapshottest");
    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1111").is_ok());

        let snap = db.snapshot();
        assert!(snap.get(b"k1").unwrap().unwrap().to_utf8().unwrap() == "v1111");

        assert!(db.put(b"k2", b"v2222").is_ok());

        assert!(db.get(b"k2").unwrap().is_some());
        assert!(snap.get(b"k2").unwrap().is_none());
    }
}

#[test]
fn sync_snapshot_test() {
    let path = DBPath::new("_rust_rocksdb_sync_snapshottest");
    {
        let db = DB::open_default(&path).unwrap();

        assert!(db.put(b"k1", b"v1").is_ok());
        assert!(db.put(b"k2", b"v2").is_ok());

        let snapshot = db.snapshot();

        // Unsafe here is safe, because `handler.join()` is called at the end of the
        // method to ensure that snapshot will not outlive database.
        let handler_1 = unsafe {
            thread::Builder::new().spawn_unchecked(|| {
                assert_eq!(snapshot.get(b"k1").unwrap().unwrap().to_utf8().unwrap(), "v1");
            }).unwrap()
        };

        let handler_2 = unsafe {
            thread::Builder::new().spawn_unchecked(|| {
                assert_eq!(snapshot.get(b"k2").unwrap().unwrap().to_utf8().unwrap(), "v2");
            }).unwrap()
        };

        handler_1.join().unwrap();
        handler_2.join().unwrap();
    }
}

#[test]
fn set_option_test() {
    let path = DBPath::new("_rust_rocksdb_set_optionstest");
    {
        let db = DB::open_default(&path).unwrap();
        // set an option to valid values
        assert!(db
            .set_options(&[("disable_auto_compactions", "true")])
            .is_ok());
        assert!(db
            .set_options(&[("disable_auto_compactions", "false")])
            .is_ok());
        // invalid names/values should result in an error
        assert!(db
            .set_options(&[("disable_auto_compactions", "INVALID_VALUE")])
            .is_err());
        assert!(db
            .set_options(&[("INVALID_NAME", "INVALID_VALUE")])
            .is_err());
        // option names/values must not contain NULLs
        assert!(db
            .set_options(&[("disable_auto_compactions", "true\0")])
            .is_err());
        assert!(db
            .set_options(&[("disable_auto_compactions\0", "true")])
            .is_err());
        // empty options are not allowed
        assert!(db.set_options(&[]).is_err());
        // multiple options can be set in a single API call
        let multiple_options = [
            ("paranoid_file_checks", "true"),
            ("report_bg_io_stats", "true"),
        ];
        db.set_options(&multiple_options).unwrap();
    }
}
<|endoftext|>


<commit_before>use callable::*;

use mio::{EventLoop, Handler, EventLoopConfig};
use clock_ticks::precise_time_ns as time_ns;

use pyframe::{print_stacktrace, iterate_stacktrace, iterate_stacktrace_fast,
ThreadProcessor, FrameProcessor};

use std::thread;
use std::sync::{Arc, Mutex};

pub struct Sampler {
    callable_registry: CallableRegistry,
    timestamp: u64,
    elapsed_time: u64,
    samples_count: u64,
    run: bool
}

struct SamplingTimerHandler {
    sampler: Arc<Mutex<Sampler>>
}

impl Handler for SamplingTimerHandler {
    type Timeout = u64;
    type Message = ();

    fn timeout(&mut self, event_loop: &mut EventLoop<SamplingTimerHandler>, timeout: u64) {
        let now = time_ns();

        let mut lock = self.sampler.lock().unwrap();
        lock.sample(now);
        if lock.run {
            // setup next timer
            event_loop.timeout_ms(timeout, timeout);
        }
    }
}

impl Sampler {
    fn new() -> Sampler {
        Sampler {
            callable_registry: CallableRegistry::new(),
            timestamp: time_ns(),
            elapsed_time:0,
            samples_count:0,
            run: true
        }
    }

    pub fn init(rate: u64) -> Arc<Mutex<Sampler>> {
        let timeout_ms = if 1000/rate >0 {1000/rate} else {1} ;

        let mut event_loop = EventLoop::configured(EventLoopConfig {
            io_poll_timeout_ms: 1_000,
            notify_capacity: 4_096,
            messages_per_tick: 256,
            timer_tick_ms: timeout_ms,
            timer_wheel_size: 1_024,
            timer_capacity: 65_536,
        }).unwrap();

        let timeout = event_loop.timeout_ms(timeout_ms, timeout_ms).unwrap();

        let sampler = Arc::new(Mutex::new(Sampler::new()));

        let mut handler = SamplingTimerHandler {
            sampler : sampler.clone()
        };

        thread::spawn(move || {
            let _ = event_loop.run(&mut handler);
        });

        sampler
    }

    pub fn sample(&mut self, now: u64) {
          let delta_ms = (now - self.timestamp)/1000000;
          self.elapsed_time = self.elapsed_time + delta_ms;
          self.samples_count = self.samples_count + 1;

          iterate_stacktrace_fast(self);
//        print_stacktrace();

          self.timestamp = time_ns();
    }

    pub fn stop(&mut self) {
        self.run = false;
    }

    pub fn stats(&mut self) -> Stats {
        Stats {
            callable_stats: self.callable_registry.as_tuples_list(),
            total_time: self.elapsed_time,
            samples_count: self.samples_count
        }
    }
}

#[derive(Debug, Clone)]
pub struct Stats {
    pub callable_stats: Vec<(String, String, i32, u64, u64)>,
    pub total_time: u64,
    pub samples_count: u64
}

impl ThreadProcessor for Sampler {
    fn thread_id(&mut self, key: String) {
    }

    fn frame_processor(&mut self) -> &mut FrameProcessor {
        self
    }
}
impl FrameProcessor for Sampler {
    fn process(&mut self, callable: &Callable, sample_type: SampleType) {
        self.callable_registry.record_sample(callable, sample_type);
    }
}
<commit_msg>Fix time measurement.<commit_after>use callable::*;

use mio::{EventLoop, Handler, EventLoopConfig};
use clock_ticks::precise_time_ns as time_ns;

use pyframe::{print_stacktrace, iterate_stacktrace, iterate_stacktrace_fast,
ThreadProcessor, FrameProcessor};

use std::thread;
use std::sync::{Arc, Mutex};

pub struct Sampler {
    callable_registry: CallableRegistry,
    timestamp: u64,
    elapsed_time: u64,
    samples_count: u64,
    run: bool
}

struct SamplingTimerHandler {
    sampler: Arc<Mutex<Sampler>>
}

impl Handler for SamplingTimerHandler {
    type Timeout = u64;
    type Message = ();

    fn timeout(&mut self, event_loop: &mut EventLoop<SamplingTimerHandler>, timeout: u64) {
        let mut lock = self.sampler.lock().unwrap();
        lock.sample();
        if lock.run {
            // setup next timer
            event_loop.timeout_ms(timeout, timeout);
        }
    }
}

impl Sampler {
    fn new() -> Sampler {
        Sampler {
            callable_registry: CallableRegistry::new(),
            timestamp: time_ns(),
            elapsed_time:0,
            samples_count:0,
            run: true
        }
    }

    pub fn init(rate: u64) -> Arc<Mutex<Sampler>> {
        let timeout_ms = if 1000/rate >0 {1000/rate} else {1} ;

        let mut event_loop = EventLoop::configured(EventLoopConfig {
            io_poll_timeout_ms: 1_000,
            notify_capacity: 4_096,
            messages_per_tick: 256,
            timer_tick_ms: timeout_ms,
            timer_wheel_size: 1_024,
            timer_capacity: 65_536,
        }).unwrap();

        let timeout = event_loop.timeout_ms(timeout_ms, timeout_ms).unwrap();

        let sampler = Arc::new(Mutex::new(Sampler::new()));

        let mut handler = SamplingTimerHandler {
            sampler : sampler.clone()
        };

        thread::spawn(move || {
            let _ = event_loop.run(&mut handler);
        });

        sampler
    }

    pub fn sample(&mut self) {
          self.samples_count = self.samples_count + 1;

          iterate_stacktrace_fast(self);
//        print_stacktrace();

          let now = time_ns();
          let delta_ms = (now - self.timestamp)/1000000;

          self.elapsed_time = self.elapsed_time + delta_ms;

          self.timestamp = time_ns();
    }

    pub fn stop(&mut self) {
        self.run = false;
    }

    pub fn stats(&mut self) -> Stats {
        Stats {
            callable_stats: self.callable_registry.as_tuples_list(),
            total_time: self.elapsed_time,
            samples_count: self.samples_count
        }
    }
}

#[derive(Debug, Clone)]
pub struct Stats {
    pub callable_stats: Vec<(String, String, i32, u64, u64)>,
    pub total_time: u64,
    pub samples_count: u64
}

impl ThreadProcessor for Sampler {
    fn thread_id(&mut self, key: String) {
    }

    fn frame_processor(&mut self) -> &mut FrameProcessor {
        self
    }
}
impl FrameProcessor for Sampler {
    fn process(&mut self, callable: &Callable, sample_type: SampleType) {
        self.callable_registry.record_sample(callable, sample_type);
    }
}
<|endoftext|>


<commit_before>use crate::io::seek::{seek, Seek};
use crate::io::AsyncSeek;
use std::io::SeekFrom;

cfg_io_util! {
    /// An extension trait that adds utility methods to [`AsyncSeek`] types.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{self, Cursor, SeekFrom};
    /// use tokio::io::{AsyncSeekExt, AsyncReadExt};
    ///
    /// #[tokio::main]
    /// async fn main() -> io::Result<()> {
    ///     let mut cursor = Cursor::new(b"abcdefg");
    ///
    ///     // the `seek` method is defined by this trait
    ///     cursor.seek(SeekFrom::Start(3)).await?;
    ///
    ///     let mut buf = [0; 1];
    ///     let n = cursor.read(&mut buf).await?;
    ///     assert_eq!(n, 1);
    ///     assert_eq!(buf, [b'd']);
    ///
    ///     Ok(())
    /// }
    /// ```
    ///
    /// See [module][crate::io] documentation for more details.
    ///
    /// [`AsyncSeek`]: AsyncSeek
    pub trait AsyncSeekExt: AsyncSeek {
        /// Creates a future which will seek an IO object, and then yield the
        /// new position in the object and the object itself.
        ///
        /// Equivalent to:
        ///
        /// ```ignore
        /// async fn seek(&mut self, pos: SeekFrom) -> io::Result<u64>;
        /// ```
        ///
        /// In the case of an error the buffer and the object will be discarded, with
        /// the error yielded.
        ///
        /// # Examples
        ///
        /// ```no_run
        /// use tokio::fs::File;
        /// use tokio::io::{AsyncSeekExt, AsyncReadExt};
        ///
        /// use std::io::SeekFrom;
        ///
        /// # async fn dox() -> std::io::Result<()> {
        /// let mut file = File::open("foo.txt").await?;
        /// file.seek(SeekFrom::Start(6)).await?;
        ///
        /// let mut contents = vec![0u8; 10];
        /// file.read_exact(&mut contents).await?;
        /// # Ok(())
        /// # }
        /// ```
        fn seek(&mut self, pos: SeekFrom) -> Seek<'_, Self>
        where
            Self: Unpin,
        {
            seek(self, pos)
        }
    }
}

impl<S: AsyncSeek + ?Sized> AsyncSeekExt for S {}
<commit_msg>io: add AsyncSeekExt::stream_position (#3650)<commit_after>use crate::io::seek::{seek, Seek};
use crate::io::AsyncSeek;
use std::io::SeekFrom;

cfg_io_util! {
    /// An extension trait that adds utility methods to [`AsyncSeek`] types.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{self, Cursor, SeekFrom};
    /// use tokio::io::{AsyncSeekExt, AsyncReadExt};
    ///
    /// #[tokio::main]
    /// async fn main() -> io::Result<()> {
    ///     let mut cursor = Cursor::new(b"abcdefg");
    ///
    ///     // the `seek` method is defined by this trait
    ///     cursor.seek(SeekFrom::Start(3)).await?;
    ///
    ///     let mut buf = [0; 1];
    ///     let n = cursor.read(&mut buf).await?;
    ///     assert_eq!(n, 1);
    ///     assert_eq!(buf, [b'd']);
    ///
    ///     Ok(())
    /// }
    /// ```
    ///
    /// See [module][crate::io] documentation for more details.
    ///
    /// [`AsyncSeek`]: AsyncSeek
    pub trait AsyncSeekExt: AsyncSeek {
        /// Creates a future which will seek an IO object, and then yield the
        /// new position in the object and the object itself.
        ///
        /// Equivalent to:
        ///
        /// ```ignore
        /// async fn seek(&mut self, pos: SeekFrom) -> io::Result<u64>;
        /// ```
        ///
        /// In the case of an error the buffer and the object will be discarded, with
        /// the error yielded.
        ///
        /// # Examples
        ///
        /// ```no_run
        /// use tokio::fs::File;
        /// use tokio::io::{AsyncSeekExt, AsyncReadExt};
        ///
        /// use std::io::SeekFrom;
        ///
        /// # async fn dox() -> std::io::Result<()> {
        /// let mut file = File::open("foo.txt").await?;
        /// file.seek(SeekFrom::Start(6)).await?;
        ///
        /// let mut contents = vec![0u8; 10];
        /// file.read_exact(&mut contents).await?;
        /// # Ok(())
        /// # }
        /// ```
        fn seek(&mut self, pos: SeekFrom) -> Seek<'_, Self>
        where
            Self: Unpin,
        {
            seek(self, pos)
        }

        /// Creates a future which will return the current seek position from the
        /// start of the stream.
        ///
        /// This is equivalent to `self.seek(SeekFrom::Current(0))`.
        fn stream_position(&mut self) -> Seek<'_, Self>
        where
            Self: Unpin,
        {
            self.seek(SeekFrom::Current(0))
        }
    }
}

impl<S: AsyncSeek + ?Sized> AsyncSeekExt for S {}
<|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 eutil::slice_to_str;
use libc::{size_t, c_int, c_ushort,c_void};
use libc::types::os::arch::c95::wchar_t;
use mem::{new0,newarray0,delete,deletearray};
use std::mem;
use std::ptr;
use std::slice;
use std::string;
use types::{cef_string_utf16_t, cef_string_utf8_t, cef_string_wide_t};
use types::{cef_string_userfree_utf16_t, cef_string_userfree_utf8_t, cef_string_userfree_wide_t};

//cef_string

#[no_mangle]
extern "C" fn string_wide_dtor(str: *mut wchar_t) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
extern "C" fn string_utf8_dtor(str: *mut u8) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
extern "C" fn string_utf16_dtor(str: *mut c_ushort) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_wide_free(cs: *mut cef_string_userfree_wide_t) {
   cef_string_wide_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf8_free(cs: *mut cef_string_userfree_utf8_t) {
   cef_string_utf8_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_free(cs: *mut cef_string_userfree_utf16_t) {
   cef_string_utf16_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_clear(cs: *mut cef_string_utf8_t) {
    unsafe {
        (*cs).dtor.map(|dtor| dtor((*cs).str));
        (*cs).length = 0;
        (*cs).str = 0 as *mut u8;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf8_alloc() -> *mut cef_string_utf8_t {
    #![inline(never)]
    new0::<cef_string_utf8_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_set(src: *const u8, src_len: size_t, output: *mut cef_string_utf8_t, copy: c_int) -> c_int {
    cef_string_utf8_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<u8>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = Some(string_utf8_dtor);
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_cmp(a: *const cef_string_utf8_t, b: *const cef_string_utf8_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice((*a).str as *const u8, (*a).length as uint, |astr:&[u8]| {
            slice::raw::buf_as_slice((*b).str as *const u8, (*b).length as uint, |bstr:&[u8]| {
                  match astr.cmp(bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_to_utf16(src: *const u8, src_len: size_t, output: *mut cef_string_utf16_t) -> c_int {
    slice_to_str(src, src_len as uint, |result| {
        let conv = result.utf16_units().collect::<Vec<u16>>();
        cef_string_utf16_set(conv.as_ptr(), conv.len() as size_t, output, 1);
        1
    })
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_to_utf8(src: *const u16, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(src, src_len as uint, |ustr| {
            match string::String::from_utf16(ustr) {
                Some(str) => {
                    cef_string_utf8_set(str.as_bytes().as_ptr(), str.len() as size_t, output, 1);
                    1 as c_int
                },
                None =>  0 as c_int
            }
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_clear(cs: *mut cef_string_utf16_t) {
    unsafe {
        (*cs).dtor.map(|dtor| dtor((*cs).str));
        (*cs).length = 0;
        (*cs).str = 0 as *mut c_ushort;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_alloc() -> *mut cef_string_utf16_t {
    #![inline(never)]
    new0::<cef_string_utf16_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_set(src: *const c_ushort, src_len: size_t, output: *mut cef_string_utf16_t, copy: c_int) -> c_int {
    cef_string_utf16_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<c_ushort>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = Some(string_utf16_dtor);
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_cmp(a: *const cef_string_utf16_t, b: *const cef_string_utf16_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(mem::transmute((*a).str), (*a).length as uint, |astr:&[u16]| {
            slice::raw::buf_as_slice(mem::transmute((*b).str), (*b).length as uint, |bstr:&[u16]| {
                  match astr.cmp(bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_wide_clear(cs: *mut cef_string_wide_t) {
    unsafe {
        (*cs).dtor.map(|dtor| dtor((*cs).str));
        (*cs).length = 0;
        (*cs).str = 0 as *mut wchar_t;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_wide_alloc() -> *mut cef_string_wide_t {
    #![inline(never)]
    new0::<cef_string_wide_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_wide_set(src: *const wchar_t, src_len: size_t, output: *mut cef_string_wide_t, copy: c_int) -> c_int {
    cef_string_wide_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<wchar_t>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = Some(string_wide_dtor);
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_wide_cmp(a: *const cef_string_wide_t, b: *const cef_string_wide_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice((*a).str as *const wchar_t, (*a).length as uint, |astr:&[wchar_t]| {
            slice::raw::buf_as_slice((*b).str as *const wchar_t, (*b).length as uint, |bstr:&[wchar_t]| {
                  match astr.cmp(bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_to_wide(src: *const u8, src_len: size_t, output: *mut cef_string_wide_t) -> c_int {
    if mem::size_of::<wchar_t>() == mem::size_of::<u16>() {
         return cef_string_utf8_to_utf16(src, src_len, output as *mut cef_string_utf16_t);
    }
    slice_to_str(src, src_len as uint, |result| {
        let conv = result.chars().map(|c| c as u32).collect::<Vec<u32>>();
        cef_string_wide_set(conv.as_ptr() as *const wchar_t, conv.len() as size_t, output, 1)
    })
}
<commit_msg>embedding: cef_string_wide_to_utf8()<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 eutil::slice_to_str;
use libc::{size_t, c_int, c_ushort,c_void};
use libc::types::os::arch::c95::wchar_t;
use mem::{new0,newarray0,delete,deletearray};
use std::char;
use std::mem;
use std::ptr;
use std::slice;
use std::string;
use types::{cef_string_utf16_t, cef_string_utf8_t, cef_string_wide_t};
use types::{cef_string_userfree_utf16_t, cef_string_userfree_utf8_t, cef_string_userfree_wide_t};

//cef_string

#[no_mangle]
extern "C" fn string_wide_dtor(str: *mut wchar_t) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
extern "C" fn string_utf8_dtor(str: *mut u8) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
extern "C" fn string_utf16_dtor(str: *mut c_ushort) {
  deletearray(str as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_wide_free(cs: *mut cef_string_userfree_wide_t) {
   cef_string_wide_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf8_free(cs: *mut cef_string_userfree_utf8_t) {
   cef_string_utf8_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_free(cs: *mut cef_string_userfree_utf16_t) {
   cef_string_utf16_clear(cs);
   delete(cs as *mut c_void)
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_clear(cs: *mut cef_string_utf8_t) {
    unsafe {
        (*cs).dtor.map(|dtor| dtor((*cs).str));
        (*cs).length = 0;
        (*cs).str = 0 as *mut u8;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf8_alloc() -> *mut cef_string_utf8_t {
    #![inline(never)]
    new0::<cef_string_utf8_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_set(src: *const u8, src_len: size_t, output: *mut cef_string_utf8_t, copy: c_int) -> c_int {
    cef_string_utf8_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<u8>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = Some(string_utf8_dtor);
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_cmp(a: *const cef_string_utf8_t, b: *const cef_string_utf8_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice((*a).str as *const u8, (*a).length as uint, |astr:&[u8]| {
            slice::raw::buf_as_slice((*b).str as *const u8, (*b).length as uint, |bstr:&[u8]| {
                  match astr.cmp(bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_to_utf16(src: *const u8, src_len: size_t, output: *mut cef_string_utf16_t) -> c_int {
    slice_to_str(src, src_len as uint, |result| {
        let conv = result.utf16_units().collect::<Vec<u16>>();
        cef_string_utf16_set(conv.as_ptr(), conv.len() as size_t, output, 1);
        1
    })
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_to_utf8(src: *const u16, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(src, src_len as uint, |ustr| {
            match string::String::from_utf16(ustr) {
                Some(str) => {
                    cef_string_utf8_set(str.as_bytes().as_ptr(), str.len() as size_t, output, 1);
                    1 as c_int
                },
                None =>  0 as c_int
            }
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_clear(cs: *mut cef_string_utf16_t) {
    unsafe {
        (*cs).dtor.map(|dtor| dtor((*cs).str));
        (*cs).length = 0;
        (*cs).str = 0 as *mut c_ushort;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_utf16_alloc() -> *mut cef_string_utf16_t {
    #![inline(never)]
    new0::<cef_string_utf16_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_set(src: *const c_ushort, src_len: size_t, output: *mut cef_string_utf16_t, copy: c_int) -> c_int {
    cef_string_utf16_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<c_ushort>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = Some(string_utf16_dtor);
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_utf16_cmp(a: *const cef_string_utf16_t, b: *const cef_string_utf16_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice(mem::transmute((*a).str), (*a).length as uint, |astr:&[u16]| {
            slice::raw::buf_as_slice(mem::transmute((*b).str), (*b).length as uint, |bstr:&[u16]| {
                  match astr.cmp(bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_wide_clear(cs: *mut cef_string_wide_t) {
    unsafe {
        (*cs).dtor.map(|dtor| dtor((*cs).str));
        (*cs).length = 0;
        (*cs).str = 0 as *mut wchar_t;
        (*cs).dtor = mem::transmute(0 as *const u8);
    }
}

#[no_mangle]
pub extern "C" fn cef_string_userfree_wide_alloc() -> *mut cef_string_wide_t {
    #![inline(never)]
    new0::<cef_string_wide_t>(1)
}

#[no_mangle]
pub extern "C" fn cef_string_wide_set(src: *const wchar_t, src_len: size_t, output: *mut cef_string_wide_t, copy: c_int) -> c_int {
    cef_string_wide_clear(output);
    unsafe {
       if copy != 0 {
           if !src.is_null() && src_len > 0 {
             (*output).str = newarray0::<wchar_t>(src_len + 1);
             if (*output).str.is_null() {
                 return 0;
             }

             ptr::copy_memory((*output).str, src, src_len as uint);
             (*output).length = src_len;
             (*output).dtor = Some(string_wide_dtor);
           }
       } else {
         (*output).str = mem::transmute(src);
         (*output).length = src_len;
         (*output).dtor = mem::transmute(0 as *const u8);
       }
    }
    return 1;
}

#[no_mangle]
pub extern "C" fn cef_string_wide_cmp(a: *const cef_string_wide_t, b: *const cef_string_wide_t) -> c_int {
    unsafe {
       slice::raw::buf_as_slice((*a).str as *const wchar_t, (*a).length as uint, |astr:&[wchar_t]| {
            slice::raw::buf_as_slice((*b).str as *const wchar_t, (*b).length as uint, |bstr:&[wchar_t]| {
                  match astr.cmp(bstr) {
                       Less => -1,
                       Equal => 0,
                       Greater => 1
                  }
            })
       })
    }
}

#[no_mangle]
pub extern "C" fn cef_string_utf8_to_wide(src: *const u8, src_len: size_t, output: *mut cef_string_wide_t) -> c_int {
    if mem::size_of::<wchar_t>() == mem::size_of::<u16>() {
         return cef_string_utf8_to_utf16(src, src_len, output as *mut cef_string_utf16_t);
    }
    slice_to_str(src, src_len as uint, |result| {
        let conv = result.chars().map(|c| c as u32).collect::<Vec<u32>>();
        cef_string_wide_set(conv.as_ptr() as *const wchar_t, conv.len() as size_t, output, 1)
    })
}

#[no_mangle]
pub extern "C" fn cef_string_wide_to_utf8(src: *const wchar_t, src_len: size_t, output: *mut cef_string_utf8_t) -> c_int {
    if mem::size_of::<wchar_t>() == mem::size_of::<u16>() {
         return cef_string_utf16_to_utf8(src as *const u16, src_len, output);
    }
    unsafe {
       slice::raw::buf_as_slice(src, src_len as uint, |ustr| {
            let conv = ustr.iter().map(|&c| char::from_u32(c as u32).unwrap_or('\uFFFD')).collect::<String>();
            cef_string_utf8_set(conv.as_bytes().as_ptr(), conv.len() as size_t, output, 1)
       })
    }
}
<|endoftext|>


<commit_before>extern crate itertools;

use std::collections::{HashSet, HashMap};
use std::fmt;
use itertools::Itertools;

struct Puzzle<'a> {
    left: &'a [&'a str],
    right: &'a str,
    all_chars: &'a str,
    char_dig: &'a mut Vec<(char, u8)>,
    leading_zeroes: &'a [char],
}

impl<'a> fmt::Debug for Puzzle<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Puzzle {{left: {:?}, right: {:?}, all_chars: {:?}, char_dig: {:?}, leading_zeroes: {:?}",
            self.left,
            self.right,
            self.all_chars,
            self.char_dig,
            self.leading_zeroes
        )
    }
}

impl<'a> Puzzle<'a> {
    pub fn new(
        left: &'a [&'a str],
        right: &'a str,
        chars: &'a str,
        char_dig: &'a mut Vec<(char, u8)>,
        leading_zeroes: &'a [char],
    ) -> Puzzle<'a> {
        Puzzle {
            left: left,
            right: right,
            all_chars: chars,
            char_dig: char_dig,
            leading_zeroes: leading_zeroes,
        }
    }

    pub fn assign_letter(&mut self, letter: char, digit: u8) -> bool {
        if self.leading_zeroes
            .iter()
            .find(|&&c| c == letter && digit == 0)
            .is_some() || self.char_dig.iter().find(|&&(_, d)| digit == d).is_some()
        {
            return false;
        }

        self.char_dig.push((letter, digit));

        return true;
    }

    pub fn puzzle_solved(&self) -> bool {
        return self.is_combination_alphametic();
    }

    pub fn unassign_letter(&mut self, letter: char, digit: u8) {
        if let Some(idx) = self.char_dig.iter().position(
            |&(x, y)| x == letter && digit == y,
        )
        {
            self.char_dig.remove(idx);
        }
    }
    pub fn find_solution(&mut self, letter_to_assign: &str) -> bool {
        println!("Display: {:?}", self);

        if letter_to_assign.len() == 0 {
            return self.puzzle_solved();
        }

        for d in 0..10 {
            println!("letter_to_assign: {:?}", letter_to_assign);
            if self.assign_letter(letter_to_assign.chars().take(1).next().unwrap(), d) {
                if self.find_solution(&letter_to_assign[1..]) {
                    return true;
                }
                self.unassign_letter(letter_to_assign.chars().take(1).next().unwrap(), d);
            }
        }
        return false;
    }

    fn is_combination_alphametic(&self) -> bool {
        let result = self.str_to_num(self.right, self.char_dig);
        if result.is_none() {
            return false;
        }

        let mut num = 0;
        for token in self.left {
            let rslt = self.str_to_num(*token, self.char_dig);
            if rslt.is_none() {
                return false;
            }
            num += rslt.unwrap();
        }

        result.unwrap() == num
    }

    fn str_to_num(&self, val: &str, lnums_slice: &[(char, u8)]) -> Option<u32> {
        let mut num = 0;
        let mut val_slice = val;
        let letter_to_digit_map = lnums_slice.iter().cloned().collect::<HashMap<_, _>>();

        if let Some(l) = val.chars().take(1).next() {
            if letter_to_digit_map[&l] == 0 {
                return None;
            }
        }
        for letter in val.chars() {
            let digit = letter_to_digit_map[&letter];
            num += 10u32.pow(val_slice.len() as u32 - 1) * digit as u32;
            val_slice = &val_slice[1..];
        }

        Some(num)
    }
}

pub fn solve(puzzle: &str) -> Option<HashMap<char, u8>> {
    let puzzle_split = puzzle.split("==").map(|s| s.trim()).collect::<Vec<_>>();
    if puzzle_split.len() != 2 {
        return None;
    }
    let result = puzzle_split[1];
    let left_tkns = puzzle_split[0]
        .split('+')
        .map(|s| s.trim())
        .collect::<Vec<_>>();

    let mut leading_zero_letters = left_tkns
        .iter()
        .map(|s| s.chars().take(1).next().unwrap())
        .unique()
        .collect::<Vec<_>>();
    leading_zero_letters.push(result.chars().take(1).next().unwrap());

    let leading_zero_letters = leading_zero_letters
        .into_iter()
        .collect::<HashSet<_>>()
        .iter()
        .map(|&x| x)
        .collect::<Vec<_>>();

    let all_chars = left_tkns
        .iter()
        .flat_map(|s| s.chars())
        .chain(puzzle_split[1].chars())
        .unique()
        .collect::<String>();

    let mut char_dig = Vec::new();
    let mut puzzle = Puzzle::new(
        &left_tkns,
        result,
        &all_chars,
        &mut char_dig,
        &leading_zero_letters,
    );

    if puzzle.find_solution(puzzle.all_chars) {
        return Some(
            puzzle
                .char_dig
                .iter()
                .map(|&(x, y)| (x, y))
                .collect::<HashMap<_, _>>(),
        );
    }

    None
}
<commit_msg>Rust: Alphametics, first piece of refactoring<commit_after>extern crate itertools;

use std::collections::{HashSet, HashMap};
use std::fmt;
use itertools::Itertools;

struct Puzzle<'a> {
    all_tkns: Vec<String>,
    all_chars: &'a str,
    char_dig: &'a mut Vec<(char, u8)>,
    leading_zeroes: &'a [char],
}

impl<'a> fmt::Debug for Puzzle<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "all_tkns: {:?}, all_chars: {:?}, char_dig: {:?}, leading_zeroes: {:?}",
            self.all_tkns,
            self.all_chars,
            self.char_dig,
            self.leading_zeroes
        )
    }
}

impl<'a> Puzzle<'a> {
    pub fn new(
        all_tkns: Vec<String>,
        chars: &'a str,
        char_dig: &'a mut Vec<(char, u8)>,
        leading_zeroes: &'a [char],
    ) -> Puzzle<'a> {
        Puzzle {
            all_tkns: all_tkns,
            all_chars: chars,
            char_dig: char_dig,
            leading_zeroes: leading_zeroes,
        }
    }

    pub fn assign_letter(&mut self, letter: char, digit: u8) -> bool {
        if self.leading_zeroes
            .iter()
            .find(|&&c| c == letter && digit == 0)
            .is_some() || self.char_dig.iter().find(|&&(_, d)| digit == d).is_some()
        {
            return false;
        }

        self.char_dig.push((letter, digit));

        true
    }

    pub fn puzzle_solved(&self) -> bool {
        return self.is_combination_alphametic();
    }

    pub fn unassign_letter(&mut self, letter: char, digit: u8) {
        if let Some(idx) = self.char_dig.iter().position(
            |&(x, y)| x == letter && digit == y,
        )
        {
            self.char_dig.remove(idx);
        }
    }
    pub fn find_solution(&mut self, letter_to_assign: &str, carry: i32) -> bool {
        if letter_to_assign.len() == 0 {
            return self.puzzle_solved();
        }

        for d in 0..10 {
            if self.assign_letter(letter_to_assign.chars().take(1).next().unwrap(), d) {
                if self.find_solution(&letter_to_assign[1..], 0) {
                    return true;
                }
                self.unassign_letter(letter_to_assign.chars().take(1).next().unwrap(), d);
            }
        }
        return false;
    }

    fn is_combination_alphametic(&self) -> bool {
        let result = self.str_to_num(self.all_tkns.last().unwrap(), self.char_dig);
        if result.is_none() {
            return false;
        }

        let mut num = 0;
        for token in &self.all_tkns[..self.all_tkns.len() - 1] {
            let rslt = self.str_to_num(&*token, self.char_dig);
            if rslt.is_none() {
                return false;
            }
            num += rslt.unwrap();
        }

        result.unwrap() == num
    }

    fn str_to_num(&self, val: &str, lnums_slice: &[(char, u8)]) -> Option<u32> {
        let mut num = 0;
        let mut val_slice = val;
        let letter_to_digit_map = lnums_slice.iter().cloned().collect::<HashMap<_, _>>();

        if let Some(l) = val.chars().take(1).next() {
            if l != '_' && letter_to_digit_map[&l] == 0 {
                return None;
            }
        }
        for letter in val.chars() {
            let mut digit = 0;
            if letter == '_' {
                digit = 0;
            } else {
                digit = letter_to_digit_map[&letter];
            }
            num += 10u32.pow(val_slice.len() as u32 - 1) * digit as u32;
            val_slice = &val_slice[1..];
        }

        Some(num)
    }
}

fn normalize_tokens(tkns: &mut [String]) {
    let mut tkn_max_lgth = tkns[0].len();
    if let Some(max) = tkns.iter_mut().max_by(|x, y| x.len().cmp(&y.len())) {
        tkn_max_lgth = max.len();
    }
    for tkn in tkns.iter_mut() {
        if tkn.len() < tkn_max_lgth {
            let mut padded_tkn = "_".repeat(tkn_max_lgth - tkn.len());
            padded_tkn.extend(tkn.chars());
            *tkn = padded_tkn;
        }
    }
}

pub fn solve(puzzle: &str) -> Option<HashMap<char, u8>> {
    let puzzle_split = puzzle.split("==").map(|s| s.trim()).collect::<Vec<_>>();
    if puzzle_split.len() != 2 {
        return None;
    }
    let result = puzzle_split[1];
    let left_tkns = puzzle_split[0]
        .split('+')
        .map(|s| s.trim())
        .collect::<Vec<_>>();

    let mut leading_zero_letters = left_tkns
        .iter()
        .map(|s| s.chars().take(1).next().unwrap())
        .unique()
        .collect::<Vec<_>>();
    leading_zero_letters.push(result.chars().take(1).next().unwrap());

    let leading_zero_letters = leading_zero_letters
        .into_iter()
        .collect::<HashSet<_>>()
        .iter()
        .map(|&x| x)
        .collect::<Vec<_>>();

    let all_chars = left_tkns
        .iter()
        .flat_map(|s| s.chars())
        .chain(puzzle_split[1].chars())
        .unique()
        .collect::<String>();

    let mut all_tkns = left_tkns.iter().map(|x| x.to_string()).collect::<Vec<_>>();
    all_tkns.push(result.to_string());

    normalize_tokens(all_tkns.as_mut_slice());

    let mut char_dig = Vec::new();
    let mut puzzle = Puzzle::new(all_tkns, &all_chars, &mut char_dig, &leading_zero_letters);

    if puzzle.find_solution(puzzle.all_chars, 0) {
        return Some(
            puzzle
                .char_dig
                .iter()
                .map(|&(x, y)| (x, y))
                .collect::<HashMap<_, _>>(),
        );
    }

    None
}
<|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 std::str::CharIndices;

// support arguments like '4', 'ab', '4.0'
fn acceptable_arg_character(c: char) -> bool {
    c.is_alphanumeric() || c == '.'
}

// A crapy parser for parsing strings like "translate(1, 3)"
pub fn parse_function(s: &str) -> (&str, Vec<&str>) {
    // XXX: This it not particular easy to read. Sorry.
    struct Parser<'a> {
        itr: CharIndices<'a>,
        start: usize,
        o: Option<(usize, char)>,
    }
    impl<'a> Parser<'a> {
        fn skip_whitespace(&mut self) {
            while let Some(k) = self.o {
                if !k.1.is_whitespace() {
                    break;
                }
                self.start = k.0 + 1;
                self.o = self.itr.next();
            }

        }
    }
    let mut c = s.char_indices();
    let o = c.next();
    let mut p = Parser { itr: c, start: 0, o: o };

    p.skip_whitespace();

    let mut end = p.start;
    while let Some(k) = p.o {
        if !k.1.is_alphabetic() {
            break;
        }
        end = k.0 + 1;
        p.o = p.itr.next();
    }

    let name = &s[p.start..end];
    let mut args = Vec::new();

    p.skip_whitespace();

    if let Some(k) = p.o {
        if !(k.1 == '(') {
            return (name, args);
        }
        p.start = k.0 + 1;
        p.o = p.itr.next();
    }

    loop {
        p.skip_whitespace();

        let mut end = p.start;
        while let Some(k) = p.o {
            if !acceptable_arg_character(k.1) {
                break;
            }
            end = k.0 + 1;
            p.o = p.itr.next();
        }

        args.push(&s[p.start..end]);

        p.skip_whitespace();

        if let Some(k) = p.o {
            // unless we find a comma we're done
            if k.1 != ',' {
                break;
            }
            p.start = k.0 + 1;
            p.o = p.itr.next();
        }

    }
    (name, args)
}

#[test]
fn test() {
    assert!(parse_function("rotate(40)").0 == "rotate");
    assert!(parse_function("  rotate(40)").0 == "rotate");
    assert!(parse_function("  rotate  (40)").0 == "rotate");
    assert!(parse_function("  rotate  (  40 )").1[0] == "40");
}
<commit_msg>[wrench] Increment by utf8_len instead of 1<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 std::str::CharIndices;

// support arguments like '4', 'ab', '4.0'
fn acceptable_arg_character(c: char) -> bool {
    c.is_alphanumeric() || c == '.'
}

// A crapy parser for parsing strings like "translate(1, 3)"
pub fn parse_function(s: &str) -> (&str, Vec<&str>) {
    // XXX: This it not particular easy to read. Sorry.
    struct Parser<'a> {
        itr: CharIndices<'a>,
        start: usize,
        o: Option<(usize, char)>,
    }
    impl<'a> Parser<'a> {
        fn skip_whitespace(&mut self) {
            while let Some(k) = self.o {
                if !k.1.is_whitespace() {
                    break;
                }
                self.start = k.0 + k.1.len_utf8();
                self.o = self.itr.next();
            }

        }
    }
    let mut c = s.char_indices();
    let o = c.next();
    let mut p = Parser { itr: c, start: 0, o: o };

    p.skip_whitespace();

    let mut end = p.start;
    while let Some(k) = p.o {
        if !k.1.is_alphabetic() {
            break;
        }
        end = k.0 + k.1.len_utf8();
        p.o = p.itr.next();
    }

    let name = &s[p.start..end];
    let mut args = Vec::new();

    p.skip_whitespace();

    if let Some(k) = p.o {
        if !(k.1 == '(') {
            return (name, args);
        }
        p.start = k.0 + k.1.len_utf8();
        p.o = p.itr.next();
    }

    loop {
        p.skip_whitespace();

        let mut end = p.start;
        while let Some(k) = p.o {
            if !acceptable_arg_character(k.1) {
                break;
            }
            end = k.0 + k.1.len_utf8();
            p.o = p.itr.next();
        }

        args.push(&s[p.start..end]);

        p.skip_whitespace();

        if let Some(k) = p.o {
            // unless we find a comma we're done
            if k.1 != ',' {
                break;
            }
            p.start = k.0 + k.1.len_utf8();
            p.o = p.itr.next();
        }

    }
    (name, args)
}

#[test]
fn test() {
    assert!(parse_function("rotate(40)").0 == "rotate");
    assert!(parse_function("  rotate(40)").0 == "rotate");
    assert!(parse_function("  rotate  (40)").0 == "rotate");
    assert!(parse_function("  rotate  (  40 )").1[0] == "40");
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs;

use super::{git2, GitStatuses, GitError, GitReference, GitBranch, FileStatus};

pub struct GitRepo {
    repo: git2::Repository,
    path: PathBuf,
}

unsafe impl Send for GitRepo {}
unsafe impl Sync for GitRepo {}

impl GitRepo {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, GitError> {
        let path_ref = path.as_ref();
        let repo = git2::Repository::open(path_ref)
            .map_err(|_| GitError::OpenRepo)?;

        Ok(Self {
               repo: repo,
               path: path_ref.to_owned(),
           })
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn statuses(&self) -> Result<GitStatuses, GitError> {
        // self.repo.graph_ahead_behind

        let mut opts = git2::StatusOptions::new();

        opts.include_ignored(false)
            .include_untracked(true)
            .recurse_untracked_dirs(true)
            .include_unreadable_as_untracked(true)
            .disable_pathspec_match(true)
            .exclude_submodules(true);

        let statuses = self.repo
            .statuses(Some(&mut opts))
            .map_err(|_| GitError::Status)?;

        Ok(GitStatuses::new(statuses))
    }

    pub fn reset(&self) -> Result<GitReference, GitError> {
        let head = self.repo.head().map_err(|_| GitError::Reset)?;
        let obj = head.peel(git2::ObjectType::Any)
            .map_err(|_| GitError::Reset)?;

        let mut builder = git2::build::CheckoutBuilder::new();
        let options = builder
            .remove_untracked(true) // this is ignored for a reset :()
            .progress(|path, a, b| {
                          if path == None {
                              return;
                          }

                          println!("{:?} {:?} {:?}", path, a, b)
                      });

        self.repo
            .reset(&obj, git2::ResetType::Hard, Some(options))
            .map_err(|_| GitError::Reset)?;

        Ok(GitReference::new(&head))
    }

    pub fn checkout(&self, branch_name: &str) -> Result<(), GitError> {
        let branch_type = match branch_name.find("origin/") {
            Some(_) => git2::BranchType::Remote,
            None => git2::BranchType::Local,
        };

        let branch = self.repo
            .find_branch(branch_name, branch_type)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        let obj = branch
            .get()
            .peel(git2::ObjectType::Commit)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        println!("{:?}", &obj);

        let mut opts = git2::build::CheckoutBuilder::new();

        self.repo
            .checkout_tree(&obj, Some(&mut opts))
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        let branch_str = format!("refs/heads/{}", branch_name);
        println!("- checking out '{}'", &branch_str);
        let branch_ref = match self.repo.find_reference(&branch_str) {
            Ok(r) => r,
            Err(e) => {
                println!("- checkout error: {}", e.message());
                return Err(GitError::Checkout(GitBranch::from(branch_type)));
            }
        };

        self.repo
            .set_head(branch_ref.name().unwrap())
            .expect("Error setting head");

        println!(" {} {}",
                 match branch_type {
                     git2::BranchType::Local => " [Local]",
                     git2::BranchType::Remote => "[Remote]",
                 },
                 branch_name);

        Ok(())
    }

    pub fn remove_untracked(&self) -> Result<(), GitError> {
        let statuses = self.statuses()?;
        let iter = statuses
            .iter()
            .filter(|x| match *x.status() {
                        FileStatus::New => true,
                        _ => false,
                    });

        // TODO: Finish this nonsense
        for entry in iter {
            let p = self.path.join(entry.path());

            // The whole file/directory distinction might be useless.
            // If a untracked file is removed from an untracked directory, should also
            // remove now empty directory?
            if p.is_file() {
                fs::remove_file(p)
                    .map_err(|_| GitError::RemoveUntracked)?;
            } else if p.is_dir() {
                fs::remove_dir_all(p)
                    .map_err(|_| GitError::RemoveUntracked)?;
            }
        }

        Ok(())
    }

    pub fn state(&self) -> RepoState {
        RepoState::from(self.repo.state())
    }
}

#[derive(Debug)]
pub enum RepoState {
    Clean,
    Merge,
    Revert,
    RevertSequence,
    CherryPick,
    CherryPickSequence,
    Bisect,
    Rebase,
    RebaseInteractive,
    RebaseMerge,
    ApplyMailbox,
    ApplyMailboxOrRebase,
}

impl From<git2::RepositoryState> for RepoState {
    fn from(state: git2::RepositoryState) -> Self {
        use git2::RepositoryState;

        match state {
            RepositoryState::Clean => RepoState::Clean,
            RepositoryState::Merge => RepoState::Merge,
            RepositoryState::Revert => RepoState::Revert,
            RepositoryState::RevertSequence => RepoState::RevertSequence,
            RepositoryState::CherryPick => RepoState::CherryPick,
            RepositoryState::CherryPickSequence => RepoState::CherryPickSequence,
            RepositoryState::Bisect => RepoState::Bisect,
            RepositoryState::Rebase => RepoState::Rebase,
            RepositoryState::RebaseInteractive => RepoState::RebaseInteractive,
            RepositoryState::RebaseMerge => RepoState::RebaseMerge,
            RepositoryState::ApplyMailbox => RepoState::ApplyMailbox,
            RepositoryState::ApplyMailboxOrRebase => RepoState::ApplyMailboxOrRebase,
        }
    }
}
<commit_msg>Added hacky remote checkout<commit_after>use std::path::{Path, PathBuf};
use std::fs;

use super::{git2, GitStatuses, GitError, GitReference, GitBranch, FileStatus};

pub struct GitRepo {
    repo: git2::Repository,
    path: PathBuf,
}

unsafe impl Send for GitRepo {}
unsafe impl Sync for GitRepo {}

impl GitRepo {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Self, GitError> {
        let path_ref = path.as_ref();
        let repo = git2::Repository::open(path_ref)
            .map_err(|_| GitError::OpenRepo)?;

        Ok(Self {
               repo: repo,
               path: path_ref.to_owned(),
           })
    }

    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn statuses(&self) -> Result<GitStatuses, GitError> {
        // self.repo.graph_ahead_behind

        let mut opts = git2::StatusOptions::new();

        opts.include_ignored(false)
            .include_untracked(true)
            .recurse_untracked_dirs(true)
            .include_unreadable_as_untracked(true)
            .disable_pathspec_match(true)
            .exclude_submodules(true);

        let statuses = self.repo
            .statuses(Some(&mut opts))
            .map_err(|_| GitError::Status)?;

        Ok(GitStatuses::new(statuses))
    }

    pub fn reset(&self) -> Result<GitReference, GitError> {
        let head = self.repo.head().map_err(|_| GitError::Reset)?;
        let obj = head.peel(git2::ObjectType::Any)
            .map_err(|_| GitError::Reset)?;

        let mut builder = git2::build::CheckoutBuilder::new();
        let options = builder
            .remove_untracked(true) // this is ignored for a reset :()
            .progress(|path, a, b| {
                          if path == None {
                              return;
                          }

                          println!("{:?} {:?} {:?}", path, a, b)
                      });

        self.repo
            .reset(&obj, git2::ResetType::Hard, Some(options))
            .map_err(|_| GitError::Reset)?;

        Ok(GitReference::new(&head))
    }

    pub fn checkout(&self, branch_name: &str) -> Result<(), GitError> {
        let branch_type = match branch_name.find("origin/") {
            Some(_) => git2::BranchType::Remote,
            None => git2::BranchType::Local,
        };

        let branch = self.repo
            .find_branch(branch_name, branch_type)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        let obj = branch
            .get()
            .peel(git2::ObjectType::Commit)
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        // This needs to get non-hacky.
        // Should only set head and reset if not already pointing to head.
        match branch_type {
            git2::BranchType::Local => (),
            git2::BranchType::Remote => {
                self.repo.set_head_detached(obj.id()).expect("wut");
                self.repo
                    .reset(&obj, git2::ResetType::Hard, None)
                    .expect("wuufttttt");
                //let branch_str = "refs/heads/topic/ARTC-233";
                //self.repo.set_head(&branch_str).expect("wut");
                return Ok(());
            }
        }

        let mut opts = git2::build::CheckoutBuilder::new();

        self.repo
            .checkout_tree(&obj, Some(&mut opts))
            .map_err(|_| GitError::Checkout(GitBranch::from(branch_type)))?;

        let branch_str = format!("refs/heads/{}", branch_name);
        println!("- checking out '{}'", &branch_str);
        let branch_ref = match self.repo.find_reference(&branch_str) {
            Ok(r) => r,
            Err(e) => {
                println!("- checkout error: {}", e.message());
                return Err(GitError::Checkout(GitBranch::from(branch_type)));
            }
        };

        self.repo
            .set_head(branch_ref.name().unwrap())
            .expect("Error setting head");

        println!(" {} {}",
                 match branch_type {
                     git2::BranchType::Local => " [Local]",
                     git2::BranchType::Remote => "[Remote]",
                 },
                 branch_name);

        Ok(())
    }

    pub fn remove_untracked(&self) -> Result<(), GitError> {
        let statuses = self.statuses()?;
        let iter = statuses
            .iter()
            .filter(|x| match *x.status() {
                        FileStatus::New => true,
                        _ => false,
                    });

        // TODO: Finish this nonsense
        for entry in iter {
            let p = self.path.join(entry.path());

            // The whole file/directory distinction might be useless.
            // If a untracked file is removed from an untracked directory, should also
            // remove now empty directory?
            if p.is_file() {
                fs::remove_file(p)
                    .map_err(|_| GitError::RemoveUntracked)?;
            } else if p.is_dir() {
                fs::remove_dir_all(p)
                    .map_err(|_| GitError::RemoveUntracked)?;
            }
        }

        Ok(())
    }

    pub fn state(&self) -> RepoState {
        RepoState::from(self.repo.state())
    }
}

#[derive(Debug)]
pub enum RepoState {
    Clean,
    Merge,
    Revert,
    RevertSequence,
    CherryPick,
    CherryPickSequence,
    Bisect,
    Rebase,
    RebaseInteractive,
    RebaseMerge,
    ApplyMailbox,
    ApplyMailboxOrRebase,
}

impl From<git2::RepositoryState> for RepoState {
    fn from(state: git2::RepositoryState) -> Self {
        use git2::RepositoryState;

        match state {
            RepositoryState::Clean => RepoState::Clean,
            RepositoryState::Merge => RepoState::Merge,
            RepositoryState::Revert => RepoState::Revert,
            RepositoryState::RevertSequence => RepoState::RevertSequence,
            RepositoryState::CherryPick => RepoState::CherryPick,
            RepositoryState::CherryPickSequence => RepoState::CherryPickSequence,
            RepositoryState::Bisect => RepoState::Bisect,
            RepositoryState::Rebase => RepoState::Rebase,
            RepositoryState::RebaseInteractive => RepoState::RebaseInteractive,
            RepositoryState::RebaseMerge => RepoState::RebaseMerge,
            RepositoryState::ApplyMailbox => RepoState::ApplyMailbox,
            RepositoryState::ApplyMailboxOrRebase => RepoState::ApplyMailboxOrRebase,
        }
    }
}
<|endoftext|>


<commit_before>use glium::backend::Context;
use Camera;
use render::ToArr;
use base::math::*;
use base::world::{HexPillar, PropType};
use world::chunk::Vertex;
use std::rc::Rc;
use glium;

/// Graphical representation of a 'base::Plant'
pub struct PlantView {
    /// contains the vertices for vertex shader
    vertices: glium::VertexBuffer<Vertex>,
    /// program links vertex and fragment shader together
    program: glium::Program,
    plants_pos: Vec<Point2f>,
    /// Context for IndexBuffer
    con: Rc<Context>,
}

impl PlantView {
    /// Creates the graphical representation of given plant
    /// at the given plant offset
    pub fn from_dummy_plant<F>(hex_vec: &[HexPillar],
      pillars_pos: Vec<Point2f>, facade: &F) -> Self
        where F: glium::backend::Facade
    {
        /// get height and width for the plant from given Prop
        let props = hex_vec[0].props();
        let _prop_ = &props[0];
        let p_type = &_prop_.prop;
        let width: f32;
        let height: f32;
        match p_type {
            &PropType::Plant(p) => {
                width = p.stem_width;
                height = p.height
            }
        }
        /// Context for the draw method
        /// to fill the IndexBuffer
        let c = facade.get_context().clone();

        let buffer = vec![Vertex {
                              position: [0.0, 1.0 * width, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 1.0 * width, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 1.0 * width,
                                1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 1.0 * width, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 0.0, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 0.0, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 0.0, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 0.0, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          }];

        let vbuf = glium::VertexBuffer::new(facade, &buffer).unwrap();
        let prog = glium::Program::from_source(facade,
                                               include_str!("plant_dummy.vert"),
                                               include_str!("plant_dummy.frag"),
                                               None)
            .unwrap();

        PlantView {
            vertices: vbuf,
            program: prog,
            plants_pos: pillars_pos,
            con: c,
        }
    }

    pub fn draw<S>(&self, surface: &mut S, camera: &Camera)
        where S: glium::Surface
    {
        /// initialise the IndexBuffer
        let index: [u32; 30] = [1, 0, 2, 2, 0, 3, 2, 3, 4, 4, 3, 5, 4, 5,
                                6, 4, 6, 7, 7, 6, 0, 7,
                                0, 1, 1, 4, 7, 4, 1, 2];
        let ibuf = glium::index::IndexBuffer::new(&self.con,
                      glium::index::PrimitiveType::TrianglesList,
                      &index).unwrap();

        for plant_pos in &self.plants_pos {
            let uniforms = uniform! {
                offset: [plant_pos.x, plant_pos.y],
                proj_matrix: camera.proj_matrix().to_arr(),
                view_matrix: camera.view_matrix().to_arr(),
            };

            surface.draw(&self.vertices,
                      &ibuf,
                      &self.program,
                      &uniforms,
                      &Default::default())
                .unwrap();
        }

    }
}
<commit_msg>More improvements<commit_after>use glium::backend::Context;
use Camera;
use render::ToArr;
use base::math::*;
use base::world::{HexPillar, PropType};
use world::chunk::Vertex;
use std::rc::Rc;
use glium;

/// Graphical representation of a 'base::Plant'
pub struct PlantView {
    /// contains the vertices for vertex shader
    vertices: glium::VertexBuffer<Vertex>,
    /// program links vertex and fragment shader together
    program: glium::Program,
    plants_pos: Vec<Point2f>,
    /// Context for IndexBuffer
    con: Rc<Context>,
}

impl PlantView {
    /// Creates the graphical representation of given plant
    /// at the given plant offset
    pub fn from_dummy_plant<F>(hex_vec: &[HexPillar],
      pillars_pos: Vec<Point2f>, facade: &F) -> Self
        where F: glium::backend::Facade
    {
        // get height and width for the plant from given Prop
        let (width, height) = match hex_vec[0].props()[0].prop() {
            &PropType::Plant(p) => (p.stem_width, p.height),
        }

        // Context for the draw method
        // to fill the IndexBuffer
        let c = facade.get_context().clone();

        let buffer = vec![Vertex {
                              position: [0.0, 1.0 * width, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 1.0 * width, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 1.0 * width,
                                1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 1.0 * width, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 0.0, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [1.0 * width, 0.0, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 0.0, 0.0],
                              color: [0.545, 0.27, 0.075],
                          },
                          Vertex {
                              position: [0.0, 0.0, 1.0 * height],
                              color: [0.545, 0.27, 0.075],
                          }];

        let vbuf = glium::VertexBuffer::new(facade, &buffer).unwrap();
        let prog = glium::Program::from_source(facade,
                                               include_str!("plant_dummy.vert"),
                                               include_str!("plant_dummy.frag"),
                                               None)
            .unwrap();

        PlantView {
            vertices: vbuf,
            program: prog,
            plants_pos: pillars_pos,
            con: c,
        }
    }

    pub fn draw<S>(&self, surface: &mut S, camera: &Camera)
        where S: glium::Surface
    {
        // initialise the IndexBuffer
        let index: [u32; 30] = [1, 0, 2, 2, 0, 3, 2, 3, 4, 4, 3, 5, 4, 5,
                                6, 4, 6, 7, 7, 6, 0, 7,
                                0, 1, 1, 4, 7, 4, 1, 2];
        let ibuf = glium::index::IndexBuffer::new(&self.con,
                      glium::index::PrimitiveType::TrianglesList,
                      &index).unwrap();

        for plant_pos in &self.plants_pos {
            let uniforms = uniform! {
                offset: [plant_pos.x, plant_pos.y],
                proj_matrix: camera.proj_matrix().to_arr(),
                view_matrix: camera.view_matrix().to_arr(),
            };

            surface.draw(&self.vertices,
                      &ibuf,
                      &self.program,
                      &uniforms,
                      &Default::default())
                .unwrap();
        }

    }
}
<|endoftext|>


<commit_before>extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

/* Fields with a custom rename are for deserializing
 * the secifications json file in amq-protocol-codegen
 */
#[derive(Debug, Deserialize, Serialize)]
pub enum AMQPType {
    #[serde(rename="bit")]
    Boolean,
    #[serde(rename="octet")]
    ShortShortInt,
    ShortShortUInt,
    #[serde(rename="short")]
    ShortInt,
    ShortUInt,
    #[serde(rename="long")]
    LongInt,
    LongUInt,
    #[serde(rename="longlong")]
    LongLongInt,
    LongLongUInt,
    Float,
    Double,
    DecimalValue,
    #[serde(rename="shortstr")]
    ShortString,
    #[serde(rename="longstr")]
    LongString,
    FieldArray,
    #[serde(rename="timestamp")]
    TimeStamp,
    #[serde(rename="table")]
    FieldTable,
    Void,
}
<commit_msg>types: add initial types definition<commit_after>extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

use std::collections::HashMap;

/* Fields with a custom rename are for deserializing
 * the secifications json file in amq-protocol-codegen
 */
#[derive(Debug, Deserialize, Serialize)]
pub enum AMQPType {
    #[serde(rename="bit")]
    Boolean,
    #[serde(rename="octet")]
    ShortShortInt,
    ShortShortUInt,
    #[serde(rename="short")]
    ShortInt,
    ShortUInt,
    #[serde(rename="long")]
    LongInt,
    LongUInt,
    #[serde(rename="longlong")]
    LongLongInt,
    LongLongUInt,
    Float,
    Double,
    DecimalValue,
    #[serde(rename="shortstr")]
    ShortString,
    #[serde(rename="longstr")]
    LongString,
    FieldArray,
    #[serde(rename="timestamp")]
    TimeStamp,
    #[serde(rename="table")]
    FieldTable,
    Void,
}

pub type Boolean        = bool;
pub type ShortShortInt  = i8;
pub type ShortShortUInt = u8;
pub type ShortInt       = i16;
pub type ShortUInt      = u16;
pub type LongInt        = i32;
pub type LongUInt       = u32;
pub type LongLongInt    = i64;
pub type LongLongUInt   = u64;
pub type Float          = f32;
pub type Double         = f64;
pub type DecimalValue   = i64;    /* FIXME: find out what this is exactly */
pub type ShortString    = String; /* TODO: don't allow size >= 255 */
pub type LongString     = String;
pub type FieldArray     = Vec<AMQPValue>;
pub type TimeStamp      = u64;
pub type FieldTable     = HashMap<String, AMQPValue>;
pub type Void           = ();

pub enum AMQPValue {
    Boolean(Boolean),
    ShortShortInt(ShortShortInt),
    ShortShortUInt(ShortShortUInt),
    ShortInt(ShortInt),
    ShortUInt(ShortUInt),
    LongInt(LongInt),
    LongUInt(LongUInt),
    LongLongInt(LongLongInt),
    LongLongUInt(LongLongUInt),
    Float(Float),
    Double(Double),
    DecimalValue(DecimalValue),
    ShortString(ShortString),
    LongString(LongString),
    FieldArray(FieldArray),
    TimeStamp(TimeStamp),
    FieldTable(FieldTable),
    Void(Void),
}
<|endoftext|>