<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ptr;
use libc::{c_char, c_int};
use cairo::{self, Surface};
use gdk_pixbuf;
use glib::object::IsA;
use glib::translate::*;
use ffi;
use Cursor;
use Visual;
use Window;

use {
    WindowHints,
    WindowType,
    WindowTypeHint,
    WindowWindowClass,
};

pub struct WindowAttr {
    pub title: Option<String>,
    pub event_mask: i32,
    pub x: Option<i32>,
    pub y: Option<i32>,
    pub width: i32,
    pub height: i32,
    pub wclass: WindowWindowClass,
    pub visual: Option<Visual>,
    pub window_type: WindowType,
    pub cursor: Option<Cursor>,
    pub override_redirect: bool,
    pub type_hint: Option<WindowTypeHint>,
}

impl Default for WindowAttr {
    fn default() -> WindowAttr {
        skip_assert_initialized!();
        WindowAttr {
            title: None,
            event_mask: 0,
            x: None,
            y: None,
            width: 400,
            height: 300,
            wclass: WindowWindowClass::InputOutput,
            visual: None,
            window_type: WindowType::Toplevel,
            cursor: None,
            override_redirect: false,
            type_hint: None,
        }
    }
}

impl WindowAttr {
    fn get_mask(&self) -> u32 {
        let mut mask = ffi::GdkWindowAttributesType::empty();
        if self.title.is_some() { mask.insert(ffi::GDK_WA_TITLE); }
        if self.x.is_some() { mask.insert(ffi::GDK_WA_X); }
        if self.y.is_some() { mask.insert(ffi::GDK_WA_Y); }
        if self.cursor.is_some() { mask.insert(ffi::GDK_WA_CURSOR); }
        if self.visual.is_some() { mask.insert(ffi::GDK_WA_VISUAL); }
        if self.override_redirect { mask.insert(ffi::GDK_WA_NOREDIR); }
        if self.type_hint.is_some() { mask.insert(ffi::GDK_WA_TYPE_HINT); }
        mask.bits()
    }
}

#[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
impl<'a> ToGlibPtr<'a, *mut ffi::GdkWindowAttr> for WindowAttr {
    type Storage = (
        Box<ffi::GdkWindowAttr>,
        Stash<'a, *mut ffi::GdkVisual, Option<Visual>>,
        Stash<'a, *mut ffi::GdkCursor, Option<Cursor>>,
        Stash<'a, *const c_char, Option<String>>,
    );

    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GdkWindowAttr, Self> {
        let title = self.title.to_glib_none();
        let visual = self.visual.to_glib_none();
        let cursor = self.cursor.to_glib_none();

        let mut attrs = Box::new(ffi::GdkWindowAttr {
            title: title.0 as *mut c_char,
            event_mask: self.event_mask,
            x: self.x.unwrap_or(0),
            y: self.y.unwrap_or(0),
            width: self.width,
            height: self.height,
            wclass: self.wclass.to_glib(),
            visual: visual.0,
            window_type: self.window_type.to_glib(),
            cursor: cursor.0,
            wmclass_name: ptr::null_mut(),
            wmclass_class: ptr::null_mut(),
            override_redirect: self.override_redirect.to_glib(),
            type_hint: self.type_hint.unwrap_or(WindowTypeHint::Normal).to_glib(),
        });

        Stash(&mut *attrs, (attrs, visual, cursor, title))
    }
}

impl Window {
    pub fn new(parent: Option<&Window>, attributes: &WindowAttr) -> Window {
        assert_initialized_main_thread!();
        unsafe {
            from_glib_full(ffi::gdk_window_new(
                parent.to_glib_none().0,
                attributes.to_glib_none().0,
                attributes.get_mask() as c_int))
        }
    }

    pub fn create_similar_surface(&self, content: cairo::Content, width: i32, height: i32) -> Option<Surface> {
        unsafe {
            from_glib_full(ffi::gdk_window_create_similar_surface(self.to_glib_none().0, content, width, height))
        }
    }
}

pub trait WindowExtManual {
    unsafe fn set_user_data<T>(&self, user_data: &mut T);

    #[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
    unsafe fn get_user_data<T>(&self) -> &mut T;

    fn set_geometry_hints(&self, geometry: &ffi::GdkGeometry, geom_mask: WindowHints);

    fn get_default_root_window() -> Window;

    fn offscreen_window_set_embedder(&self, embedder: &Window);

    fn offscreen_window_get_embedder(&self) -> Option<Window>;

    fn offscreen_window_get_surface(&self) -> Option<Surface>;

    fn get_pixbuf(&self, src_x: i32, src_y: i32, width: i32, height: i32) -> Option<gdk_pixbuf::Pixbuf>;
}

impl<O: IsA<Window>> WindowExtManual for O {
    unsafe fn set_user_data<T>(&self, user_data: &mut T) {
        ffi::gdk_window_set_user_data(self.to_glib_none().0, user_data as *mut T as *mut _)
    }

    unsafe fn get_user_data<T>(&self) -> &mut T {
        let mut pointer = ::std::ptr::null_mut();
        ffi::gdk_window_get_user_data(self.to_glib_none().0, &mut pointer);
        &mut *(pointer as *mut T)
    }

    fn set_geometry_hints(&self, geometry: &ffi::GdkGeometry, geom_mask: WindowHints) {
        unsafe { ffi::gdk_window_set_geometry_hints(self.to_glib_none().0, geometry, geom_mask.to_glib()) }
    }

    fn get_default_root_window() -> Window {
        assert_initialized_main_thread!();
        unsafe { from_glib_none(ffi::gdk_get_default_root_window()) }
    }

    fn offscreen_window_set_embedder(&self, embedder: &Window) {
        unsafe {
            ffi::gdk_offscreen_window_set_embedder(self.to_glib_none().0, embedder.to_glib_none().0)
        }
    }

    fn offscreen_window_get_embedder(&self) -> Option<Window> {
        unsafe { from_glib_none(ffi::gdk_offscreen_window_get_embedder(self.to_glib_none().0)) }
    }

    fn offscreen_window_get_surface(&self) -> Option<Surface> {
        skip_assert_initialized!();
        unsafe {
            from_glib_none(ffi::gdk_offscreen_window_get_surface(self.to_glib_none().0))
        }
    }

    fn get_pixbuf(&self, src_x: i32, src_y: i32, width: i32, height: i32) -> Option<gdk_pixbuf::Pixbuf> {
        skip_assert_initialized!();
        unsafe {
            from_glib_full(ffi::gdk_pixbuf_get_from_window(self.to_glib_none().0, src_x, src_y, width, height))
        }
    }
}
<commit_msg>Fix flag usage<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ptr;
use libc::{c_char, c_int};
use cairo::{self, Surface};
use gdk_pixbuf;
use glib::object::IsA;
use glib::translate::*;
use ffi;
use Cursor;
use Visual;
use Window;

use {
    WindowHints,
    WindowType,
    WindowTypeHint,
    WindowWindowClass,
};

pub struct WindowAttr {
    pub title: Option<String>,
    pub event_mask: i32,
    pub x: Option<i32>,
    pub y: Option<i32>,
    pub width: i32,
    pub height: i32,
    pub wclass: WindowWindowClass,
    pub visual: Option<Visual>,
    pub window_type: WindowType,
    pub cursor: Option<Cursor>,
    pub override_redirect: bool,
    pub type_hint: Option<WindowTypeHint>,
}

impl Default for WindowAttr {
    fn default() -> WindowAttr {
        skip_assert_initialized!();
        WindowAttr {
            title: None,
            event_mask: 0,
            x: None,
            y: None,
            width: 400,
            height: 300,
            wclass: WindowWindowClass::InputOutput,
            visual: None,
            window_type: WindowType::Toplevel,
            cursor: None,
            override_redirect: false,
            type_hint: None,
        }
    }
}

impl WindowAttr {
    fn get_mask(&self) -> u32 {
        let mut mask : ffi::GdkWindowAttributesType = 0;
        if self.title.is_some() { mask |= ffi::GDK_WA_TITLE; }
        if self.x.is_some() { mask |= ffi::GDK_WA_X; }
        if self.y.is_some() { mask |= ffi::GDK_WA_Y; }
        if self.cursor.is_some() { mask |= ffi::GDK_WA_CURSOR; }
        if self.visual.is_some() { mask |= ffi::GDK_WA_VISUAL; }
        if self.override_redirect { mask |= ffi::GDK_WA_NOREDIR; }
        if self.type_hint.is_some() { mask |= ffi::GDK_WA_TYPE_HINT; }
        mask
    }
}

#[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
impl<'a> ToGlibPtr<'a, *mut ffi::GdkWindowAttr> for WindowAttr {
    type Storage = (
        Box<ffi::GdkWindowAttr>,
        Stash<'a, *mut ffi::GdkVisual, Option<Visual>>,
        Stash<'a, *mut ffi::GdkCursor, Option<Cursor>>,
        Stash<'a, *const c_char, Option<String>>,
    );

    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GdkWindowAttr, Self> {
        let title = self.title.to_glib_none();
        let visual = self.visual.to_glib_none();
        let cursor = self.cursor.to_glib_none();

        let mut attrs = Box::new(ffi::GdkWindowAttr {
            title: title.0 as *mut c_char,
            event_mask: self.event_mask,
            x: self.x.unwrap_or(0),
            y: self.y.unwrap_or(0),
            width: self.width,
            height: self.height,
            wclass: self.wclass.to_glib(),
            visual: visual.0,
            window_type: self.window_type.to_glib(),
            cursor: cursor.0,
            wmclass_name: ptr::null_mut(),
            wmclass_class: ptr::null_mut(),
            override_redirect: self.override_redirect.to_glib(),
            type_hint: self.type_hint.unwrap_or(WindowTypeHint::Normal).to_glib(),
        });

        Stash(&mut *attrs, (attrs, visual, cursor, title))
    }
}

impl Window {
    pub fn new(parent: Option<&Window>, attributes: &WindowAttr) -> Window {
        assert_initialized_main_thread!();
        unsafe {
            from_glib_full(ffi::gdk_window_new(
                parent.to_glib_none().0,
                attributes.to_glib_none().0,
                attributes.get_mask() as c_int))
        }
    }

    pub fn create_similar_surface(&self, content: cairo::Content, width: i32, height: i32) -> Option<Surface> {
        unsafe {
            from_glib_full(ffi::gdk_window_create_similar_surface(self.to_glib_none().0, content, width, height))
        }
    }
}

pub trait WindowExtManual {
    unsafe fn set_user_data<T>(&self, user_data: &mut T);

    #[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
    unsafe fn get_user_data<T>(&self) -> &mut T;

    fn set_geometry_hints(&self, geometry: &ffi::GdkGeometry, geom_mask: WindowHints);

    fn get_default_root_window() -> Window;

    fn offscreen_window_set_embedder(&self, embedder: &Window);

    fn offscreen_window_get_embedder(&self) -> Option<Window>;

    fn offscreen_window_get_surface(&self) -> Option<Surface>;

    fn get_pixbuf(&self, src_x: i32, src_y: i32, width: i32, height: i32) -> Option<gdk_pixbuf::Pixbuf>;
}

impl<O: IsA<Window>> WindowExtManual for O {
    unsafe fn set_user_data<T>(&self, user_data: &mut T) {
        ffi::gdk_window_set_user_data(self.to_glib_none().0, user_data as *mut T as *mut _)
    }

    unsafe fn get_user_data<T>(&self) -> &mut T {
        let mut pointer = ::std::ptr::null_mut();
        ffi::gdk_window_get_user_data(self.to_glib_none().0, &mut pointer);
        &mut *(pointer as *mut T)
    }

    fn set_geometry_hints(&self, geometry: &ffi::GdkGeometry, geom_mask: WindowHints) {
        unsafe { ffi::gdk_window_set_geometry_hints(self.to_glib_none().0, geometry, geom_mask.to_glib()) }
    }

    fn get_default_root_window() -> Window {
        assert_initialized_main_thread!();
        unsafe { from_glib_none(ffi::gdk_get_default_root_window()) }
    }

    fn offscreen_window_set_embedder(&self, embedder: &Window) {
        unsafe {
            ffi::gdk_offscreen_window_set_embedder(self.to_glib_none().0, embedder.to_glib_none().0)
        }
    }

    fn offscreen_window_get_embedder(&self) -> Option<Window> {
        unsafe { from_glib_none(ffi::gdk_offscreen_window_get_embedder(self.to_glib_none().0)) }
    }

    fn offscreen_window_get_surface(&self) -> Option<Surface> {
        skip_assert_initialized!();
        unsafe {
            from_glib_none(ffi::gdk_offscreen_window_get_surface(self.to_glib_none().0))
        }
    }

    fn get_pixbuf(&self, src_x: i32, src_y: i32, width: i32, height: i32) -> Option<gdk_pixbuf::Pixbuf> {
        skip_assert_initialized!();
        unsafe {
            from_glib_full(ffi::gdk_pixbuf_get_from_window(self.to_glib_none().0, src_x, src_y, width, height))
        }
    }
}
<|endoftext|>


<commit_before>#[doc = "Rust TNetStrings serialization library."];

use std;
import option::{some, none};
import std::map;
import std::map::hashmap;
import std::rand;

import io::writer_util;
import io::reader_util;

export t;
export str;
export int;
export float;
export bool;
export null;
export map;
export vec;
export to_writer;
export to_bytes;
export to_str;
export from_reader;
export from_bytes;
export from_str;

#[doc = "Represents a tnetstring value."]
enum t {
    #[doc = "str"]
    str([u8]),
    #[doc = "int"]
    int(int),
    #[doc = "floating"]
    float(float),
    #[doc = "boolean"]
    bool(bool),
    #[doc = "null"]
    null,
    #[doc = "map"]
    map(map::hashmap<[u8], t>),
    #[doc = "list"]
    vec([t]),
}

#[doc = "Serializes a tnetstring value into a io::writer."]
fn to_writer(writer: io::writer, t: t) {
    alt t {
        str(s) {
            writer.write_str(#fmt("%u:", vec::len(s)));
            writer.write(s);
            writer.write_char(',');
        }
        int(i) {
            let s = int::str(i);
            writer.write_str(#fmt("%u:%s#", str::len(s), s));
        }
        float(f) {
            let s = float::to_str(f, 6u);
            writer.write_str(#fmt("%u:%s^", str::len(s), s));
        }
        bool(b) {
            let s = bool::to_str(b);
            writer.write_str(#fmt("%u:%s!", str::len(s), s));
        }
        map(m) {
            let buf = io::mem_buffer();
            let wr = io::mem_buffer_writer(buf);
            m.items({ |key, value|
                to_writer(wr, str(key));
                to_writer(wr, value);
            });
            let payload = io::mem_buffer_buf(buf);
            writer.write_str(#fmt("%u:", vec::len(payload)));
            writer.write(payload);
            writer.write_char('}');
        }
        vec(l) {
            let buf = io::mem_buffer();
            let wr = io::mem_buffer_writer(buf);
            vec::iter(l, {|e| to_writer(wr, e) });
            let payload = io::mem_buffer_buf(buf);
            writer.write_str(#fmt("%u:", vec::len(payload)));
            writer.write(payload);
            writer.write_char(']');
        }
        null {
            writer.write_str("0:~");
        }
    }
}

#[doc = "Serializes a tnetstring value into a byte string."]
fn to_bytes(t: t) -> [u8] {
    let buf = io::mem_buffer();
    let wr = io::mem_buffer_writer(buf);
    to_writer(wr, t);
    io::mem_buffer_buf(buf)
}

#[doc = "Serializes a tnetstring value into a string."]
fn to_str(t: t) -> str {
    let buf = io::mem_buffer();
    let wr = io::mem_buffer_writer(buf);
    to_writer(wr, t);
    io::mem_buffer_str(buf)
}

#[doc = "Deserializes a tnetstring value from an io::reader."]
fn from_reader(reader: io::reader) -> option<t> {
    assert !reader.eof();

    let c = reader.read_byte();
    let len = 0u;

    // Note that netstring spec explicitly forbids padding zeros.
    // If the first char is zero, it must be the only char.
    if c < '0' as int || c > '9' as int {
        fail "Not a tnetstring: invalid or missing length prefix";
    } else if c == '0' as int {
        c = reader.read_byte();
    } else {
        do {
            len = (10u * len) + ((c as uint) - ('0' as uint));

            if reader.eof() {
                fail "Not a tnetstring: invalid or missing length prefix";
            }
            c = reader.read_byte();
        } while c >= '0' as int && c <= '9' as int;
    }

    // Validate end-of-length-prefix marker.
    if c != ':' as int {
        fail "Not a tnetstring: missing length prefix";
    }

    // Read the data plus terminating type tag.
    let payload = reader.read_bytes(len);

    if vec::len(payload) != len {
        fail "Not a tnetstring: invalid length prefix";
    }

    if reader.eof() {
        fail "Not a tnetstring: missing type tag";
    }

    alt reader.read_byte() as char {
      '#' {
        let s = unsafe { str::unsafe::from_bytes(payload) };
        option::chain(int::from_str(s)) {|v| some(int(v)) }
      }
      '}' { some(map(parse_map(payload))) }
      ']' { some(vec(parse_vec(payload))) }
      '!' {
        let s = unsafe { str::unsafe::from_bytes(payload) };
        option::chain(bool::from_str(s)) {|v| some(bool(v)) }
      }
      '^' {
        let s = unsafe { str::unsafe::from_bytes(payload) };
        option::chain(float::from_str(s)) {|v| some(float(v)) }
      }
      '~' {
        assert vec::len(payload) == 0u;
        some(null)
      }
      ',' { some(str(payload)) }
      c {
        let s = str::from_char(c);
        fail #fmt("Invalid payload type: %?", s)
      }
    }
}

fn parse_vec(data: [u8]) -> [t] {
    if vec::len(data) == 0u { ret []; }

    let reader = io::bytes_reader(data);

    let value = from_reader(reader);
    assert option::is_some(value);
    let result = [option::get(value)];

    while !reader.eof() {
        let value = from_reader(reader);
        assert option::is_some(value);
        vec::push(result, option::get(value));
    }

    ret result;
}

fn parse_pair(reader: io::reader) -> ([u8], t) {
    let key = from_reader(reader);
    assert option::is_some(key);
    assert !reader.eof();

    let key = alt option::get(key) {
        str(key) { key }
        _ { fail "Keys can only be strings." }
    };

    let value = from_reader(reader);
    assert option::is_some(value);

    ret (key, option::get(value));
}

fn parse_map(data: [u8]) -> map::hashmap<[u8], t> {
    if vec::len(data) == 0u { ret map::new_bytes_hash(); }

    let reader = io::bytes_reader(data);
    let (key, value) = parse_pair(reader);

    let result = map::new_bytes_hash();
    result.insert(key, value);

    while !reader.eof() {
        let (key, value) = parse_pair(reader);
        result.insert(key, value);
    }

    ret result;
}

#[doc = "Deserializes a tnetstring value from a byte string."]
fn from_bytes(data: [u8]) -> (option<t>, [u8]) {
    let rdr = io::bytes_reader(data);
    let tnetstring = from_reader(rdr);
    (tnetstring, rdr.read_whole_stream())
}

#[doc = "Deserializes a tnetstring value from a string."]
fn from_str(data: str) -> (option<t>, str) {
    io::with_str_reader(data) {|rdr|
        let tnetstring = from_reader(rdr);
        let bytes = rdr.read_whole_stream();
        (tnetstring, str::from_bytes(bytes))
    }

}

#[doc = "Test the equality between two tnetstring values"]
fn eq(t0: t, t1: t) -> bool {
    alt (t0, t1) {
        (str(s0), str(s1)) { s0 == s1 }
        (int(i0), int(i1)) { i0 == i1 }
        (float(f0), float(f1)) { f0 == f1 }
        (bool(b0), bool(b1)) { b0 == b1 }
        (null, null) { true }
        (map(d0), map(d1)) {
            if d0.size() == d1.size() {
                let equal = true;
                d0.items() { |k, v|
                    if !d1.contains_key(k) || !eq(d1.get(k), v) {
                        equal = false;
                    }
                };
                equal
            } else {
                false
            }
        }
        (vec(l0), vec(l1)) {
            vec::all2(l0, l1, eq)
        }
        _ { false }
    }
}

#[cfg(test)]
mod tests {
    // Tests inspired by https://github.com/rfk/tnetstring.

    fn test(string: str, expected: t) {
        let (actual, rest) = from_str(string);
        assert option::is_some(actual);
        assert rest == "";

        let actual = option::get(actual);
        assert eq(actual, expected);
        assert to_str(expected) == string;
    }

    #[test]
    fn test_format() {
        test("11:hello world,", str(str::bytes("hello world")));
        test("0:}", map(map::new_bytes_hash()));
        test("0:]", vec([]));

        let d = map::new_bytes_hash();
        d.insert(str::bytes("hello"),
                vec([
                    int(12345678901),
                    str(str::bytes("this")),
                    bool(true),
                    null,
                    str(str::bytes("\x00\x00\x00\x00"))]));

        test("51:5:hello,39:11:12345678901#4:this,4:true!0:~4:\x00\x00\x00" +
            "\x00,]}", map(d));

        test("5:12345#", int(12345));
        test("12:this is cool,", str(str::bytes("this is cool")));
        test("0:,", str(str::bytes("")));
        test("0:~", null);
        test("4:true!", bool(true));
        test("5:false!", bool(false));
        test("10:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
            str(str::bytes("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")));
        test("24:5:12345#5:67890#5:xxxxx,]",
            vec(
                [int(12345),
                int(67890),
                str(str::bytes("xxxxx"))]));
        test("18:3:0.1^3:0.2^3:0.4^]",
           vec([float(0.1), float(0.2), float(0.4)]));
        test("243:238:233:228:223:218:213:208:203:198:193:188:183:178:173:" +
            "168:163:158:153:148:143:138:133:128:123:118:113:108:103:99:95:" +
            "91:87:83:79:75:71:67:63:59:55:51:47:43:39:35:31:27:23:19:15:" +
            "11:hello-there,]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" +
            "]]]]",
            vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([
                    str(str::bytes("hello-there"))
                ])])])])])])])])])])])])])])])])])])])])])])])])])])])])
                ])])])])])])])])])])])])])])])])])])])])])])]));
    }

    #[test]
    fn test_random() {
        fn randint(rng: rand::rng, a: u32, b: u32) -> u32 {
            (rng.next() % (b - a + 1u32)) + a
        }

        fn get_random_object(rng: rand::rng, depth: u32) -> t {
            if randint(rng, depth, 10u32) <= 4u32 {
                if randint(rng, 0u32, 1u32) == 0u32 {
                    let n = randint(rng, 0u32, 10u32);
                    vec(vec::from_fn(n as uint) { |_i|
                        get_random_object(rng, depth + 1u32)
                    })
                } else {
                    let d = map::new_bytes_hash();

                    let i = randint(rng, 0u32, 10u32);
                    while i != 0u32 {
                        let s = rng.gen_bytes(randint(rng, 0u32, 100u32) as uint);
                        d.insert(s, get_random_object(rng, depth + 1u32));
                        i -= 1u32;
                    }
                    map(d)
                }
            } else {
                alt randint(rng, 0u32, 5u32) {
                  0u32 { null }
                  1u32 { bool(true) }
                  2u32 { bool(false) }
                  3u32 {
                    if randint(rng, 0u32, 1u32) == 0u32 {
                        int(rng.next() as int)
                    } else {
                        int(-rng.next() as int)
                    }
                  }
                  4u32 {
                    let f = rng.next_float();

                    // Generate a float that can be exactly converted to
                    // and from a string.
                    while true {
                        alt float::from_str(float::to_str(f, 6u)) {
                          some(f1) {
                            if f == f1 { break; }
                            f = f1;
                          }
                          none { fail }
                        }
                    }

                    if randint(rng, 0u32, 1u32) == 0u32 {
                        float(f)
                    } else {
                        float(-f)
                    }
                  }
                  5u32 {
                    str(rng.gen_bytes(randint(rng, 0u32, 100u32) as uint))
                  }
                  _ { fail }
                }
            }
        }

        let rng = rand::rng();

        let i = 500u;
        while i != 0u {
            let v0 = get_random_object(rng, 0u32);

            alt from_bytes(to_bytes(v0)) {
                (some(v1), rest) if rest == [] {
                    assert eq(v0, v1);
                }
                _ { fail; }
            }
            i -= 1u;
        }
    }
}
<commit_msg>Update for 0.2<commit_after>#[doc = "Rust TNetStrings serialization library."];

use std;
import option::{some, none};
import std::map;
import std::map::hashmap;
import std::rand;

import io::writer_util;
import io::reader_util;

export t;
export str;
export int;
export float;
export bool;
export null;
export map;
export vec;
export to_writer;
export to_bytes;
export to_str;
export from_reader;
export from_bytes;
export from_str;

#[doc = "Represents a tnetstring value."]
enum t {
    #[doc = "str"]
    str([u8]),
    #[doc = "int"]
    int(int),
    #[doc = "floating"]
    float(float),
    #[doc = "boolean"]
    bool(bool),
    #[doc = "null"]
    null,
    #[doc = "map"]
    map(map::hashmap<[u8], t>),
    #[doc = "list"]
    vec([t]),
}

#[doc = "Serializes a tnetstring value into a io::writer."]
fn to_writer(writer: io::writer, t: t) {
    alt t {
        str(s) {
            writer.write_str(#fmt("%u:", vec::len(s)));
            writer.write(s);
            writer.write_char(',');
        }
        int(i) {
            let s = int::str(i);
            writer.write_str(#fmt("%u:%s#", str::len(s), s));
        }
        float(f) {
            let s = float::to_str(f, 6u);
            writer.write_str(#fmt("%u:%s^", str::len(s), s));
        }
        bool(b) {
            let s = bool::to_str(b);
            writer.write_str(#fmt("%u:%s!", str::len(s), s));
        }
        map(m) {
            let buf = io::mem_buffer();
            let wr = io::mem_buffer_writer(buf);
            m.items({ |key, value|
                to_writer(wr, str(key));
                to_writer(wr, value);
            });
            let payload = io::mem_buffer_buf(buf);
            writer.write_str(#fmt("%u:", vec::len(payload)));
            writer.write(payload);
            writer.write_char('}');
        }
        vec(l) {
            let buf = io::mem_buffer();
            let wr = io::mem_buffer_writer(buf);
            vec::iter(l, {|e| to_writer(wr, e) });
            let payload = io::mem_buffer_buf(buf);
            writer.write_str(#fmt("%u:", vec::len(payload)));
            writer.write(payload);
            writer.write_char(']');
        }
        null {
            writer.write_str("0:~");
        }
    }
}

#[doc = "Serializes a tnetstring value into a byte string."]
fn to_bytes(t: t) -> [u8] {
    let buf = io::mem_buffer();
    let wr = io::mem_buffer_writer(buf);
    to_writer(wr, t);
    io::mem_buffer_buf(buf)
}

#[doc = "Serializes a tnetstring value into a string."]
fn to_str(t: t) -> str {
    let buf = io::mem_buffer();
    let wr = io::mem_buffer_writer(buf);
    to_writer(wr, t);
    io::mem_buffer_str(buf)
}

#[doc = "Deserializes a tnetstring value from an io::reader."]
fn from_reader(reader: io::reader) -> option<t> {
    assert !reader.eof();

    let mut c = reader.read_byte();
    let mut len = 0u;

    // Note that netstring spec explicitly forbids padding zeros.
    // If the first char is zero, it must be the only char.
    if c < '0' as int || c > '9' as int {
        fail "Not a tnetstring: invalid or missing length prefix";
    } else if c == '0' as int {
        c = reader.read_byte();
    } else {
        do {
            len = (10u * len) + ((c as uint) - ('0' as uint));

            if reader.eof() {
                fail "Not a tnetstring: invalid or missing length prefix";
            }
            c = reader.read_byte();
        } while c >= '0' as int && c <= '9' as int;
    }

    // Validate end-of-length-prefix marker.
    if c != ':' as int {
        fail "Not a tnetstring: missing length prefix";
    }

    // Read the data plus terminating type tag.
    let payload = reader.read_bytes(len);

    if vec::len(payload) != len {
        fail "Not a tnetstring: invalid length prefix";
    }

    if reader.eof() {
        fail "Not a tnetstring: missing type tag";
    }

    alt reader.read_byte() as char {
      '#' {
        let s = unsafe { str::unsafe::from_bytes(payload) };
        option::chain(int::from_str(s)) {|v| some(int(v)) }
      }
      '}' { some(map(parse_map(payload))) }
      ']' { some(vec(parse_vec(payload))) }
      '!' {
        let s = unsafe { str::unsafe::from_bytes(payload) };
        option::chain(bool::from_str(s)) {|v| some(bool(v)) }
      }
      '^' {
        let s = unsafe { str::unsafe::from_bytes(payload) };
        option::chain(float::from_str(s)) {|v| some(float(v)) }
      }
      '~' {
        assert vec::len(payload) == 0u;
        some(null)
      }
      ',' { some(str(payload)) }
      c {
        let s = str::from_char(c);
        fail #fmt("Invalid payload type: %?", s)
      }
    }
}

fn parse_vec(data: [u8]) -> [t] {
    if vec::len(data) == 0u { ret []; }

    let reader = io::bytes_reader(data);

    let value = from_reader(reader);
    assert option::is_some(value);
    let mut result = [option::get(value)];

    while !reader.eof() {
        let value = from_reader(reader);
        assert option::is_some(value);
        vec::push(result, option::get(value));
    }

    ret result;
}

fn parse_pair(reader: io::reader) -> ([u8], t) {
    let key = from_reader(reader);
    assert option::is_some(key);
    assert !reader.eof();

    let key = alt option::get(key) {
        str(key) { key }
        _ { fail "Keys can only be strings." }
    };

    let value = from_reader(reader);
    assert option::is_some(value);

    ret (key, option::get(value));
}

fn parse_map(data: [u8]) -> map::hashmap<[u8], t> {
    if vec::len(data) == 0u { ret map::bytes_hash(); }

    let reader = io::bytes_reader(data);
    let (key, value) = parse_pair(reader);

    let result = map::bytes_hash();
    result.insert(key, value);

    while !reader.eof() {
        let (key, value) = parse_pair(reader);
        result.insert(key, value);
    }

    ret result;
}

#[doc = "Deserializes a tnetstring value from a byte string."]
fn from_bytes(data: [u8]) -> (option<t>, [u8]) {
    let rdr = io::bytes_reader(data);
    let tnetstring = from_reader(rdr);
    (tnetstring, rdr.read_whole_stream())
}

#[doc = "Deserializes a tnetstring value from a string."]
fn from_str(data: str) -> (option<t>, str) {
    io::with_str_reader(data) {|rdr|
        let tnetstring = from_reader(rdr);
        let bytes = rdr.read_whole_stream();
        (tnetstring, str::from_bytes(bytes))
    }

}

#[doc = "Test the equality between two tnetstring values"]
fn eq(t0: t, t1: t) -> bool {
    alt (t0, t1) {
        (str(s0), str(s1)) { s0 == s1 }
        (int(i0), int(i1)) { i0 == i1 }
        (float(f0), float(f1)) { f0 == f1 }
        (bool(b0), bool(b1)) { b0 == b1 }
        (null, null) { true }
        (map(d0), map(d1)) {
            if d0.size() == d1.size() {
                let mut equal = true;
                d0.items() { |k, v|
                    if !d1.contains_key(k) || !eq(d1.get(k), v) {
                        equal = false;
                    }
                };
                equal
            } else {
                false
            }
        }
        (vec(l0), vec(l1)) {
            vec::all2(l0, l1, eq)
        }
        _ { false }
    }
}

#[cfg(test)]
mod tests {
    // Tests inspired by https://github.com/rfk/tnetstring.

    fn test(string: str, expected: t) {
        let (actual, rest) = from_str(string);
        assert option::is_some(actual);
        assert rest == "";

        let actual = option::get(actual);
        assert eq(actual, expected);
        assert to_str(expected) == string;
    }

    #[test]
    fn test_format() {
        test("11:hello world,", str(str::bytes("hello world")));
        test("0:}", map(map::bytes_hash()));
        test("0:]", vec([]));

        let d = map::bytes_hash();
        d.insert(str::bytes("hello"),
                vec([
                    int(12345678901),
                    str(str::bytes("this")),
                    bool(true),
                    null,
                    str(str::bytes("\x00\x00\x00\x00"))]));

        test("51:5:hello,39:11:12345678901#4:this,4:true!0:~4:\x00\x00\x00" +
            "\x00,]}", map(d));

        test("5:12345#", int(12345));
        test("12:this is cool,", str(str::bytes("this is cool")));
        test("0:,", str(str::bytes("")));
        test("0:~", null);
        test("4:true!", bool(true));
        test("5:false!", bool(false));
        test("10:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
            str(str::bytes("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")));
        test("24:5:12345#5:67890#5:xxxxx,]",
            vec(
                [int(12345),
                int(67890),
                str(str::bytes("xxxxx"))]));
        test("18:3:0.1^3:0.2^3:0.4^]",
           vec([float(0.1), float(0.2), float(0.4)]));
        test("243:238:233:228:223:218:213:208:203:198:193:188:183:178:173:" +
            "168:163:158:153:148:143:138:133:128:123:118:113:108:103:99:95:" +
            "91:87:83:79:75:71:67:63:59:55:51:47:43:39:35:31:27:23:19:15:" +
            "11:hello-there,]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" +
            "]]]]",
            vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([vec([vec([vec([vec([vec([vec(
                [vec([vec([
                    str(str::bytes("hello-there"))
                ])])])])])])])])])])])])])])])])])])])])])])])])])])])])
                ])])])])])])])])])])])])])])])])])])])])])])]));
    }

    #[test]
    fn test_random() {
        fn randint(rng: rand::rng, a: u32, b: u32) -> u32 {
            (rng.next() % (b - a + 1u32)) + a
        }

        fn get_random_object(rng: rand::rng, depth: u32) -> t {
            if randint(rng, depth, 10u32) <= 4u32 {
                if randint(rng, 0u32, 1u32) == 0u32 {
                    let n = randint(rng, 0u32, 10u32);
                    vec(vec::from_fn(n as uint) { |_i|
                        get_random_object(rng, depth + 1u32)
                    })
                } else {
                    let d = map::bytes_hash();

                    let mut i = randint(rng, 0u32, 10u32);
                    while i != 0u32 {
                        let s = rng.gen_bytes(randint(rng, 0u32, 100u32) as uint);
                        d.insert(s, get_random_object(rng, depth + 1u32));
                        i -= 1u32;
                    }
                    map(d)
                }
            } else {
                alt randint(rng, 0u32, 5u32) {
                  0u32 { null }
                  1u32 { bool(true) }
                  2u32 { bool(false) }
                  3u32 {
                    if randint(rng, 0u32, 1u32) == 0u32 {
                        int(rng.next() as int)
                    } else {
                        int(-rng.next() as int)
                    }
                  }
                  4u32 {
                    let mut f = rng.next_float();

                    // Generate a float that can be exactly converted to
                    // and from a string.
                    while true {
                        alt float::from_str(float::to_str(f, 6u)) {
                          some(f1) {
                            if f == f1 { break; }
                            f = f1;
                          }
                          none { fail }
                        }
                    }

                    if randint(rng, 0u32, 1u32) == 0u32 {
                        float(f)
                    } else {
                        float(-f)
                    }
                  }
                  5u32 {
                    str(rng.gen_bytes(randint(rng, 0u32, 100u32) as uint))
                  }
                  _ { fail }
                }
            }
        }

        let rng = rand::rng();

        let mut i = 500u;
        while i != 0u {
            let v0 = get_random_object(rng, 0u32);

            alt from_bytes(to_bytes(v0)) {
                (some(v1), rest) if rest == [] {
                    assert eq(v0, v1);
                }
                _ { fail; }
            }
            i -= 1u;
        }
    }
}
<|endoftext|>


<commit_before>use core::intrinsics;

// NOTE These functions are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function
#[cfg(windows)]
#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn ___chkstk_ms() {
    asm!("push   %rcx
          push   %rax
          cmp    $$0x1000,%rax
          lea    24(%rsp),%rcx
          jb     1f
          2:
          sub    $$0x1000,%rcx
          test   %rcx,(%rcx)
          sub    $$0x1000,%rax
          cmp    $$0x1000,%rax
          ja     2b
          1:
          sub    %rax,%rcx
          test   %rcx,(%rcx)
          pop    %rax
          pop    %rcx
          ret");
    intrinsics::unreachable();
}

#[cfg(windows)]
#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __alloca() {
    asm!("mov    %rcx,%rax  // x64 _alloca is a normal function with parameter in rcx
          jmp    ___chkstk  // Jump to ___chkstk since fallthrough may be unreliable");
    intrinsics::unreachable();
}

#[cfg(windows)]
#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn ___chkstk() {
    asm!("push   %rcx
          cmp    $$0x1000,%rax
          lea    16(%rsp),%rcx  // rsp before calling this routine -> rcx
          jb     1f
          2:
          sub    $$0x1000,%rcx
          test   %rcx,(%rcx)
          sub    $$0x1000,%rax
          cmp    $$0x1000,%rax
          ja     2b
          1:
          sub    %rax,%rcx
          test   %rcx,(%rcx)

          lea    8(%rsp),%rax   // load pointer to the return address into rax
          mov    %rcx,%rsp      // install the new top of stack pointer into rsp
          mov    -8(%rax),%rcx  // restore rcx
          push   (%rax)         // push return address onto the stack
          sub    %rsp,%rax      // restore the original value in rax
          ret");
    intrinsics::unreachable();
}

<commit_msg>Disable mangling for msvc stack builtins This prevents linker errors in test builds due to the `jmp` instruction in __alloca<commit_after>use core::intrinsics;

// NOTE These functions are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function

// NOTE These functions are never mangled as they are not tested against compiler-rt
// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca

#[cfg(windows)]
#[naked]
#[no_mangle]
pub unsafe fn ___chkstk_ms() {
    asm!("push   %rcx
          push   %rax
          cmp    $$0x1000,%rax
          lea    24(%rsp),%rcx
          jb     1f
          2:
          sub    $$0x1000,%rcx
          test   %rcx,(%rcx)
          sub    $$0x1000,%rax
          cmp    $$0x1000,%rax
          ja     2b
          1:
          sub    %rax,%rcx
          test   %rcx,(%rcx)
          pop    %rax
          pop    %rcx
          ret");
    intrinsics::unreachable();
}

#[cfg(windows)]
#[naked]
#[no_mangle]
pub unsafe fn __alloca() {
    asm!("mov    %rcx,%rax  // x64 _alloca is a normal function with parameter in rcx
          jmp    ___chkstk  // Jump to ___chkstk since fallthrough may be unreliable");
    intrinsics::unreachable();
}

#[cfg(windows)]
#[naked]
#[no_mangle]
pub unsafe fn ___chkstk() {
    asm!("push   %rcx
          cmp    $$0x1000,%rax
          lea    16(%rsp),%rcx  // rsp before calling this routine -> rcx
          jb     1f
          2:
          sub    $$0x1000,%rcx
          test   %rcx,(%rcx)
          sub    $$0x1000,%rax
          cmp    $$0x1000,%rax
          ja     2b
          1:
          sub    %rax,%rcx
          test   %rcx,(%rcx)

          lea    8(%rsp),%rax   // load pointer to the return address into rax
          mov    %rcx,%rsp      // install the new top of stack pointer into rsp
          mov    -8(%rax),%rcx  // restore rcx
          push   (%rax)         // push return address onto the stack
          sub    %rsp,%rax      // restore the original value in rax
          ret");
    intrinsics::unreachable();
}

<|endoftext|>


<commit_before>use target_info;
use chrono::*;

// Information about the build.
// This information is derived at compile time.

// The file has been placed there by the build.rs script and the 'built' crate.
// Import it privately so we can rename the constants to avoid too deep a nesting.
// TODO: Is there a better way of doing this?
mod bi {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

// pub use bi::PKG_NAME;
// pub use bi::PKG_DESCRIPTION;
// pub use bi::PKG_VERSION;
// pub use bi::PKG_VERSION_MAJOR;
// pub use bi::PKG_VERSION_MINOR;
// pub use bi::PKG_VERSION_PATCH;
// pub use bi::PKG_VERSION_PRE;
// pub use bi::PKG_AUTHORS;
// pub use bi::PKG_HOMEPAGE;
// pub use bi::PROFILE;
// pub use bi::DEBUG;
// pub use bi::OPT_LEVEL;
// pub use bi::RUSTC;
// pub use bi::RUSTC_VERSION;
// pub use bi::RUSTDOC;
// pub use bi::RUSTDOC_VERSION;
// pub use bi::FEATURES;
// pub use bi::FEATURES_STR;
// pub use bi::BUILD_TIME_UTC;

#[doc="The name of the program."]
pub const PKG_NAME: &'static str = bi::PKG_NAME;

#[doc="The description."]
pub const PKG_DESCRIPTION: &'static str = bi::PKG_DESCRIPTION;

#[doc="The full version."]
pub const PKG_VERSION: &'static str = bi::PKG_VERSION;

#[doc="The major version."]
pub const PKG_VERSION_MAJOR: &'static str = bi::PKG_VERSION_MAJOR;

#[doc="The minor version."]
pub const PKG_VERSION_MINOR: &'static str = bi::PKG_VERSION_MINOR;

#[doc="The patch version."]
pub const PKG_VERSION_PATCH: &'static str = bi::PKG_VERSION_PATCH;

#[doc="The pre-release version."]
pub const PKG_VERSION_PRE: &'static str = bi::PKG_VERSION_PRE;

#[doc="A colon-separated list of authors."]
pub const PKG_AUTHORS: &'static str = bi::PKG_AUTHORS;

#[doc="The homepage."]
pub const PKG_HOMEPAGE: &'static str = bi::PKG_HOMEPAGE;

#[doc="`release` for release builds, `debug` for other builds."]
pub const PROFILE: &'static str = bi::PROFILE;

#[doc="Value of DEBUG for the profile used during compilation."]
pub const DEBUG: bool = bi::DEBUG;

#[doc="Value of OPT_LEVEL for the profile used during compilation."]
pub const OPT_LEVEL: u8 = bi::OPT_LEVEL;

#[doc="The compiler that cargo resolved to use."]
pub const RUSTC: &'static str = bi::RUSTC;

#[doc="The output of `rustc -V`"]
pub const RUSTC_VERSION: &'static str = bi::RUSTC_VERSION;

#[doc="The output of `rustdoc -V`"]
pub const RUSTDOC_VERSION: &'static str = bi::RUSTDOC_VERSION;

#[doc="The documentation generator that cargo resolved to use."]
pub const RUSTDOC: &'static str = bi::RUSTDOC;

#[doc="The features that were enabled during compilation."]
pub const FEATURES: [&'static str; 0] = bi::FEATURES;

#[doc="The features as a comma-separated string."]
pub const FEATURES_STR: &'static str = bi::FEATURES_STR;

#[doc="The built-time in RFC822, UTC."]
pub const BUILD_TIME_UTC: &'static str = bi::BUILT_TIME_UTC;

#[doc="Return BUILD_TIME_UTC as a chrono DateTime<FixedOffset>."]
pub fn build_time() -> DateTime<FixedOffset> {
    DateTime::parse_from_rfc2822(BUILD_TIME_UTC).unwrap()
}

// TODO: These should be compile-time constants too. However, the target_info crate
// only exposes them as functions.
pub fn arch() -> &'static str {
    target_info::Target::arch()
}

pub fn endian() -> &'static str {
    target_info::Target::endian()
}

pub fn env() -> &'static str {
    target_info::Target::env()
}

pub fn family() -> &'static str {
    target_info::Target::family()
}

pub fn os() -> &'static str {
    target_info::Target::os()
}

pub fn log_build_info() {
    info!(r#"BuildInfo {{ PKG_VERSION: "{}", PROFILE: "{}", DEBUG: "{}", OPT_LEVEL: "{}", RUSTC: "{}", RUSTC_VERSION: "{}", FEATURES_STR: "{}", BUILD_TIME_UTC: "{}", arch: "{}", endian: "{}", env: "{}", family: "{}", os: "{}" }}"#,
        PKG_VERSION, PROFILE, DEBUG, OPT_LEVEL, RUSTC, RUSTC_VERSION, FEATURES_STR, BUILD_TIME_UTC,
        arch(), endian(), env(), family(), os()
        );
}
<commit_msg>Add note about build_info future improvements.<commit_after>use target_info;
use chrono::*;

// Information about the build.
// This information is derived at compile time.

// The file has been placed there by the build.rs script and the 'built' crate.
// Import it privately so we can rename the constants to avoid too deep a nesting.
// TODO: Is there a better way of doing this?
// The best way is simply to combine the two crates into a single new crate called build_info,
// and then just put this 'include' line into main.rs, then the constants can be referred to
// as ::PKG_VERSION.
mod bi {
    include!(concat!(env!("OUT_DIR"), "/built.rs"));
}

// pub use bi::PKG_NAME;
// pub use bi::PKG_DESCRIPTION;
// pub use bi::PKG_VERSION;
// pub use bi::PKG_VERSION_MAJOR;
// pub use bi::PKG_VERSION_MINOR;
// pub use bi::PKG_VERSION_PATCH;
// pub use bi::PKG_VERSION_PRE;
// pub use bi::PKG_AUTHORS;
// pub use bi::PKG_HOMEPAGE;
// pub use bi::PROFILE;
// pub use bi::DEBUG;
// pub use bi::OPT_LEVEL;
// pub use bi::RUSTC;
// pub use bi::RUSTC_VERSION;
// pub use bi::RUSTDOC;
// pub use bi::RUSTDOC_VERSION;
// pub use bi::FEATURES;
// pub use bi::FEATURES_STR;
// pub use bi::BUILD_TIME_UTC;

#[doc="The name of the program."]
pub const PKG_NAME: &'static str = bi::PKG_NAME;

#[doc="The description."]
pub const PKG_DESCRIPTION: &'static str = bi::PKG_DESCRIPTION;

#[doc="The full version."]
pub const PKG_VERSION: &'static str = bi::PKG_VERSION;

#[doc="The major version."]
pub const PKG_VERSION_MAJOR: &'static str = bi::PKG_VERSION_MAJOR;

#[doc="The minor version."]
pub const PKG_VERSION_MINOR: &'static str = bi::PKG_VERSION_MINOR;

#[doc="The patch version."]
pub const PKG_VERSION_PATCH: &'static str = bi::PKG_VERSION_PATCH;

#[doc="The pre-release version."]
pub const PKG_VERSION_PRE: &'static str = bi::PKG_VERSION_PRE;

#[doc="A colon-separated list of authors."]
pub const PKG_AUTHORS: &'static str = bi::PKG_AUTHORS;

#[doc="The homepage."]
pub const PKG_HOMEPAGE: &'static str = bi::PKG_HOMEPAGE;

#[doc="`release` for release builds, `debug` for other builds."]
pub const PROFILE: &'static str = bi::PROFILE;

#[doc="Value of DEBUG for the profile used during compilation."]
pub const DEBUG: bool = bi::DEBUG;

#[doc="Value of OPT_LEVEL for the profile used during compilation."]
pub const OPT_LEVEL: u8 = bi::OPT_LEVEL;

#[doc="The compiler that cargo resolved to use."]
pub const RUSTC: &'static str = bi::RUSTC;

#[doc="The output of `rustc -V`"]
pub const RUSTC_VERSION: &'static str = bi::RUSTC_VERSION;

#[doc="The output of `rustdoc -V`"]
pub const RUSTDOC_VERSION: &'static str = bi::RUSTDOC_VERSION;

#[doc="The documentation generator that cargo resolved to use."]
pub const RUSTDOC: &'static str = bi::RUSTDOC;

#[doc="The features that were enabled during compilation."]
pub const FEATURES: [&'static str; 0] = bi::FEATURES;

#[doc="The features as a comma-separated string."]
pub const FEATURES_STR: &'static str = bi::FEATURES_STR;

#[doc="The built-time in RFC822, UTC."]
pub const BUILD_TIME_UTC: &'static str = bi::BUILT_TIME_UTC;

#[doc="Return BUILD_TIME_UTC as a chrono DateTime<FixedOffset>."]
pub fn build_time() -> DateTime<FixedOffset> {
    DateTime::parse_from_rfc2822(BUILD_TIME_UTC).unwrap()
}

// TODO: These should be compile-time constants too. However, the target_info crate
// only exposes them as functions.
pub fn arch() -> &'static str {
    target_info::Target::arch()
}

pub fn endian() -> &'static str {
    target_info::Target::endian()
}

pub fn env() -> &'static str {
    target_info::Target::env()
}

pub fn family() -> &'static str {
    target_info::Target::family()
}

pub fn os() -> &'static str {
    target_info::Target::os()
}

pub fn log_build_info() {
    info!(r#"BuildInfo {{ PKG_VERSION: "{}", PROFILE: "{}", DEBUG: "{}", OPT_LEVEL: "{}", RUSTC: "{}", RUSTC_VERSION: "{}", FEATURES_STR: "{}", BUILD_TIME_UTC: "{}", arch: "{}", endian: "{}", env: "{}", family: "{}", os: "{}" }}"#,
        PKG_VERSION, PROFILE, DEBUG, OPT_LEVEL, RUSTC, RUSTC_VERSION, FEATURES_STR, BUILD_TIME_UTC,
        arch(), endian(), env(), family(), os()
        );
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

pub fn main() {
    let stdin = io::stdin();
    let mut result = 0;
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        let split = line.split("x");
        let mut nums = split.map(|s| s.parse().unwrap()).collect::<Vec<i32>>();
        nums.sort();
        let area1 = nums[0] * nums[1];
        let area2 = nums[0] * nums[2];
        let area3 = nums[1] * nums[2];
        result += area1 * 2 + area2 * 2 + area3 * 2 + area1;
    }
    println!("Part1: {}", result);
}<commit_msg>day 2 part 2 rust solution<commit_after>use std::io;
use std::io::prelude::*;

pub fn main() {
    let stdin = io::stdin();
    let mut part1 = 0;
    let mut part2 = 0;
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        let split = line.split("x");
        let mut nums = split.map(|s| s.parse().unwrap()).collect::<Vec<i32>>();
        nums.sort();
        let area1 = nums[0] * nums[1];
        let area2 = nums[0] * nums[2];
        let area3 = nums[1] * nums[2];
        part1 += area1 * 2 + area2 * 2 + area3 * 2 + area1;
        part2 += nums[0] * 2 + nums[1] * 2 + nums[0] * nums[1] * nums[2];
    }
    println!("Part1: {}", part1);
    println!("Part2: {}", part2);
}<|endoftext|>


<commit_before>pub use super::super::compiler::*;

use super::super::cache::Cache;
use super::postprocess;
use super::super::wincmd;
use super::super::utils::filter;
use super::super::utils::hash_text;
use super::super::io::tempfile::TempFile;

use std::fs::File;
use std::io::{Error, BufReader, Cursor, Read, Write};
use std::hash::{SipHasher, Hasher};
use std::path::{Path, PathBuf};
use std::process::Output;

pub struct VsCompiler {
	cache: Cache,
	temp_dir: PathBuf
}

impl VsCompiler {
	pub fn new(cache: &Cache, temp_dir: &Path) -> Self {
		VsCompiler {
			cache: cache.clone(),
			temp_dir: temp_dir.to_path_buf()
		}
	}

	fn run_compiler(&self, task: &CompilationTask, source: &Path, args: &Vec<String>) -> Result<OutputInfo, Error> {
		let mut command = task.command.to_command();
		command
			.args(&args)
			.arg(source.to_str().unwrap())
			.arg("/c")
			.arg(&join_flag("/Fo", &task.output_object));
		match &task.input_precompiled {
			&Some(ref path) => {command.arg(&join_flag("/Fp", path));}
			&None => {}
		}
		match &task.output_precompiled {
			&Some(ref path) => {command.arg(&join_flag("/Fp", path));}
			&None => {}
		}
		command.output().map(|o| OutputInfo::new(o))
	}
}

impl Compiler for VsCompiler {
	fn create_task(&self, command: CommandInfo, args: &[String]) -> Result<CompilationTask, String> {
		super::prepare::create_task(command, args)
	}

	fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, Error> {
		// Make parameters list for preprocessing.
		let mut args = filter(&task.args, |arg:&Arg|->Option<String> {
			match arg {
				&Arg::Flag{ref scope, ref flag} => {
					match scope {
						&Scope::Preprocessor | &Scope::Shared => Some("/".to_string() + &flag),
						&Scope::Ignore | &Scope::Compiler => None
					}
				}
				&Arg::Param{ref scope, ref  flag, ref value} => {
					match scope {
						&Scope::Preprocessor | &Scope::Shared => Some("/".to_string() + &flag + &value),
						&Scope::Ignore | &Scope::Compiler => None
					}
				}
				&Arg::Input{..} => None,
				&Arg::Output{..} => None,
			}
		});

		// Add preprocessor paramters.
		let temp_file = TempFile::new_in(&self.temp_dir, ".i");
		args.push("/nologo".to_string());
		args.push("/T".to_string() + &task.language);
		args.push("/P".to_string());
		args.push(task.input_source.display().to_string());

		// Hash data.
		let mut sip_hash = SipHasher::new();
		let hash: &mut Hasher = &mut sip_hash;
		hash.write_u8(0);
		hash.write(wincmd::join(&args).as_bytes());

		let mut command = task.command.to_command();
		command
			.args(&args)
			.arg(&join_flag("/Fi", &temp_file.path()))
			.arg(&join_flag("/Fo", &task.output_object)); // /Fo option also set output path for #import directive
		let output = try! (command.output());
		if output.status.success() {
			match File::open(temp_file.path()) {
				Ok(stream) => {
					let (mut output, sources): (Box<Read>, Vec<PathBuf>) = if task.input_precompiled.is_some() || task.output_precompiled.is_some() {
						let mut buffer: Vec<u8> = Vec::new();
						let sources = try! (postprocess::filter_preprocessed(&task.command.current_dir, &mut BufReader::new(stream), &mut buffer, &task.marker_precompiled, task.output_precompiled.is_some()));
						(Box::new(Cursor::new(buffer)), sources)
					} else {
						(Box::new(stream), Vec::new())
					};
					let mut content = Vec::new();
					try! (output.read_to_end(&mut content));
					hash.write(&content);
					Ok(PreprocessResult::Success(PreprocessedSource {
						hash: format!("{:016x}", hash.finish()),
						sources: sources,
						content: content,
					}))
				}
				Err(e) => Err(e)
			}
		} else {
			Ok(PreprocessResult::Failed(OutputInfo::new(output)))
		}
	}

	// Compile preprocessed file.
	fn compile_step(&self, task: &CompilationTask, preprocessed: PreprocessedSource) -> Result<OutputInfo, Error> {
		let mut args = filter(&task.args, |arg:&Arg|->Option<String> {
			match arg {
				&Arg::Flag{ref scope, ref flag} => {
					match scope {
						&Scope::Compiler | &Scope::Shared => Some("/".to_string() + &flag),
						&Scope::Preprocessor if task.output_precompiled.is_some() => Some("/".to_string() + &flag),
						&Scope::Ignore | &Scope::Preprocessor => None
					}
				}
				&Arg::Param{ref scope, ref  flag, ref value} => {
					match scope {
						&Scope::Compiler | &Scope::Shared => Some("/".to_string() + &flag + &value),
						&Scope::Preprocessor if task.output_precompiled.is_some() => Some("/".to_string() + &flag + &value),
						&Scope::Ignore | &Scope::Preprocessor => None
					}
				}
				&Arg::Input{..} => None,
				&Arg::Output{..} => None
			}
		});
		args.push("/T".to_string() + &task.language);
		match &task.input_precompiled {
			&Some(ref path) => {
				args.push("/Yu".to_string());
				args.push("/Fp".to_string() + &path.display().to_string());
			}
			&None => {}
		}
		if task.output_precompiled.is_some() {
			args.push("/Yc".to_string());
		}
		// Input data, stored in files.
		let mut inputs: Vec<PathBuf> = Vec::new();
		match &task.input_precompiled {
				&Some(ref path) => {inputs.push(path.clone());}
				&None => {}
			}
		// Output files.
		let mut outputs: Vec<PathBuf> = Vec::new();
		outputs.push(task.output_object.clone());
		match &task.output_precompiled {
			&Some(ref path) => {
				outputs.push(path.clone());
			}
			&None => {}
		}

		let hash_params = hash_text(&preprocessed.content) + &wincmd::join(&args);
		self.cache.run_cached(&hash_params, &inputs, &outputs, || -> Result<OutputInfo, Error> {
			match &task.output_precompiled {
				&Some(_) => {
					// Input file path.
					self.run_compiler(task, &task.input_source, &args)
				}
				&None => {
					// Input file path.
					let input_temp = TempFile::new_in(&self.temp_dir, ".i");
					try! (try! (File::create(input_temp.path())).write_all(&preprocessed.content));
					self.run_compiler(task, input_temp.path(), &args)
				}
			}
		})
	}
}

pub fn join_flag(flag: &str, path: &Path) -> String {
	flag.to_string() + &path.to_str().unwrap()
}<commit_msg>Revert "Create precompiled header by compiling original (not preprocessed) source file"<commit_after>pub use super::super::compiler::*;

use super::super::cache::Cache;
use super::postprocess;
use super::super::wincmd;
use super::super::utils::filter;
use super::super::utils::hash_text;
use super::super::io::tempfile::TempFile;

use std::fs::File;
use std::io::{Error, BufReader, Cursor, Read, Write};
use std::hash::{SipHasher, Hasher};
use std::path::{Path, PathBuf};
use std::process::Output;

pub struct VsCompiler {
	cache: Cache,
	temp_dir: PathBuf
}

impl VsCompiler {
	pub fn new(cache: &Cache, temp_dir: &Path) -> Self {
		VsCompiler {
			cache: cache.clone(),
			temp_dir: temp_dir.to_path_buf()
		}
	}
}

impl Compiler for VsCompiler {
	fn create_task(&self, command: CommandInfo, args: &[String]) -> Result<CompilationTask, String> {
		super::prepare::create_task(command, args)
	}

	fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, Error> {
		// Make parameters list for preprocessing.
		let mut args = filter(&task.args, |arg:&Arg|->Option<String> {
			match arg {
				&Arg::Flag{ref scope, ref flag} => {
					match scope {
						&Scope::Preprocessor | &Scope::Shared => Some("/".to_string() + &flag),
						&Scope::Ignore | &Scope::Compiler => None
					}
				}
				&Arg::Param{ref scope, ref  flag, ref value} => {
					match scope {
						&Scope::Preprocessor | &Scope::Shared => Some("/".to_string() + &flag + &value),
						&Scope::Ignore | &Scope::Compiler => None
					}
				}
				&Arg::Input{..} => None,
				&Arg::Output{..} => None,
			}
		});

		// Add preprocessor paramters.
		let temp_file = TempFile::new_in(&self.temp_dir, ".i");
		args.push("/nologo".to_string());
		args.push("/T".to_string() + &task.language);
		args.push("/P".to_string());
		args.push(task.input_source.display().to_string());

		// Hash data.
		let mut sip_hash = SipHasher::new();
		let hash: &mut Hasher = &mut sip_hash;
		hash.write_u8(0);
		hash.write(wincmd::join(&args).as_bytes());

		let mut command = task.command.to_command();
		command
			.args(&args)
			.arg(&join_flag("/Fi", &temp_file.path()))
			.arg(&join_flag("/Fo", &task.output_object)); // /Fo option also set output path for #import directive
		let output = try! (command.output());
		if output.status.success() {
			match File::open(temp_file.path()) {
				Ok(stream) => {
					let (mut output, sources): (Box<Read>, Vec<PathBuf>) = if task.input_precompiled.is_some() || task.output_precompiled.is_some() {
						let mut buffer: Vec<u8> = Vec::new();
						let sources = try! (postprocess::filter_preprocessed(&task.command.current_dir, &mut BufReader::new(stream), &mut buffer, &task.marker_precompiled, task.output_precompiled.is_some()));
						(Box::new(Cursor::new(buffer)), sources)
					} else {
						(Box::new(stream), Vec::new())
					};
					let mut content = Vec::new();
					try! (output.read_to_end(&mut content));
					hash.write(&content);
					Ok(PreprocessResult::Success(PreprocessedSource {
						hash: format!("{:016x}", hash.finish()),
						sources: sources,
						content: content,
					}))
				}
				Err(e) => Err(e)
			}
		} else {
			Ok(PreprocessResult::Failed(OutputInfo::new(output)))
		}
	}

	// Compile preprocessed file.
	fn compile_step(&self, task: &CompilationTask, preprocessed: PreprocessedSource) -> Result<OutputInfo, Error> {
		let mut args = filter(&task.args, |arg:&Arg|->Option<String> {
			match arg {
				&Arg::Flag{ref scope, ref flag} => {
					match scope {
						&Scope::Compiler | &Scope::Shared => Some("/".to_string() + &flag),
						&Scope::Preprocessor if task.output_precompiled.is_some() => Some("/".to_string() + &flag),
						&Scope::Ignore | &Scope::Preprocessor => None
					}
				}
				&Arg::Param{ref scope, ref  flag, ref value} => {
					match scope {
						&Scope::Compiler | &Scope::Shared => Some("/".to_string() + &flag + &value),
						&Scope::Preprocessor if task.output_precompiled.is_some() => Some("/".to_string() + &flag + &value),
						&Scope::Ignore | &Scope::Preprocessor => None
					}
				}
				&Arg::Input{..} => None,
				&Arg::Output{..} => None
			}
		});
		args.push("/T".to_string() + &task.language);
		match &task.input_precompiled {
			&Some(ref path) => {
				args.push("/Yu".to_string());
				args.push("/Fp".to_string() + &path.display().to_string());
			}
			&None => {}
		}
		if task.output_precompiled.is_some() {
			args.push("/Yc".to_string());
		}
		// Input data, stored in files.
		let mut inputs: Vec<PathBuf> = Vec::new();
		match &task.input_precompiled {
				&Some(ref path) => {inputs.push(path.clone());}
				&None => {}
			}
		// Output files.
		let mut outputs: Vec<PathBuf> = Vec::new();
		outputs.push(task.output_object.clone());
		match &task.output_precompiled {
			&Some(ref path) => {
				outputs.push(path.clone());
			}
			&None => {}
		}

		let hash_params = hash_text(&preprocessed.content) + &wincmd::join(&args);
		self.cache.run_cached(&hash_params, &inputs, &outputs, || -> Result<OutputInfo, Error> {
			// Input file path.
			let input_temp = TempFile::new_in(&self.temp_dir, ".i");
			try! (try! (File::create(input_temp.path())).write_all(&preprocessed.content));
			// Run compiler.
			let mut command = task.command.to_command();
			command
				.args(&args)
				.arg(input_temp.path().to_str().unwrap())
				.arg("/c")
				.arg(&join_flag("/Fo", &task.output_object));
			match &task.input_precompiled {
				&Some(ref path) => {command.arg(&join_flag("/Fp", path));}
				&None => {}
			}
			match &task.output_precompiled {
				&Some(ref path) => {command.arg(&join_flag("/Fp", path));}
				&None => {}
			}
			command.output().map(|o| OutputInfo::new(o))
		})
	}
}

pub fn join_flag(flag: &str, path: &Path) -> String {
	flag.to_string() + &path.to_str().unwrap()
}<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::SeekFrom;
use std::fs::File;
use std::mem;

pub struct WordVector {
    vocabulary: Vec<String>,
    pub vectors: Vec<Vec<f32>>,
    clusters: Option<Vec<String>>
}

impl WordVector{
	pub fn load_from_binary(file_name: &str) -> WordVector
	{
		let mut file = File::open(file_name).unwrap();
		let mut reader = BufReader::new(file);
		let mut header = String::new();
		reader.read_line(&mut header).unwrap();
		let mut header_info = header.split_whitespace().map(|x| x.parse::<usize>().unwrap()).take(2);
		let vocabulary_size = header_info.next().unwrap();
		let vector_size = header_info.next().unwrap();
		let vector_length: u64 = 4 * vector_size as u64;
		let mut vectors: Vec<Vec<f32>> = Vec::new();
		let mut vocabulary = vec![String::new(); vocabulary_size];
		for i in 0..vocabulary_size{
			let mut word_bytes: Vec<u8> = Vec::new();
			reader.read_until(b' ', &mut word_bytes).unwrap();
			word_bytes.pop();
			let word = String::from_utf8(word_bytes).unwrap();
			vocabulary[i] = word;
			let mut current_vector = Vec::new();
			for j in 0..vector_size{
				let mut buf: [u8; 4] = [0; 4];
				reader.read(&mut buf);
				let vec = unsafe{mem::transmute::<[u8; 4], f32>(buf)};
				current_vector.push(vec);
			}
			vectors.push(current_vector);
			reader.seek(SeekFrom::Current(1));
		}
		WordVector{
			vocabulary: vocabulary,
			vectors: vectors,
			clusters: None
		}
	}

	fn get_index(&self, word: &str) -> Option<usize>
	{
		return self.vocabulary.iter().position(|x| x == word);
	}

	pub fn get_vector(&self, word: &str) -> Option<&Vec<f32>>
	{
		let index = self.get_index(word);
		match index {
		    Some(val) => {
		    	return Some(&self.vectors[val])
		    },
		    None => None,
		}
	}
}<commit_msg>Create cosine function<commit_after>use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::SeekFrom;
use std::fs::File;
use std::cmp::Ordering;
use std::mem;

pub struct WordVector {
    vocabulary: Vec<String>,
    pub vectors: Vec<Vec<f32>>,
    clusters: Option<Vec<String>>
}

fn dot_product(arr1: &Vec<f32>, arr2: &Vec<f32>) -> f32
	{
		let mut result: f32 = 0.0;
		for (elem1, elem2) in arr1.iter().zip(arr2.iter()){
			result += elem1 * elem2;
		}
		return result;
	}

impl WordVector{
	pub fn load_from_binary(file_name: &str) -> WordVector
	{
		let mut file = File::open(file_name).unwrap();
		let mut reader = BufReader::new(file);
		let mut header = String::new();
		reader.read_line(&mut header).unwrap();
		let mut header_info = header.split_whitespace().map(|x| x.parse::<usize>().unwrap()).take(2);
		let vocabulary_size = header_info.next().unwrap();
		let vector_size = header_info.next().unwrap();
		let vector_length: u64 = 4 * vector_size as u64;
		let mut vectors: Vec<Vec<f32>> = Vec::new();
		let mut vocabulary = vec![String::new(); vocabulary_size];
		for i in 0..vocabulary_size{
			let mut word_bytes: Vec<u8> = Vec::new();
			reader.read_until(b' ', &mut word_bytes).unwrap();
			word_bytes.pop();
			let word = String::from_utf8(word_bytes).unwrap();
			vocabulary[i] = word;
			let mut current_vector = Vec::new();
			for j in 0..vector_size{
				let mut buf: [u8; 4] = [0; 4];
				reader.read(&mut buf);
				let vec = unsafe{ mem::transmute::<[u8; 4], f32>(buf) };
				current_vector.push(vec);
			}
			vectors.push(current_vector);
			reader.seek(SeekFrom::Current(1));
		}
		WordVector{
			vocabulary: vocabulary,
			vectors: vectors,
			clusters: None
		}
	}

	fn get_index(&self, word: &str) -> Option<usize>
	{
		return self.vocabulary.iter().position(|x| x == word);
	}

	pub fn get_vector(&self, word: &str) -> Option<&Vec<f32>>
	{
		let index = self.get_index(word);
		match index {
		    Some(val) => {
		    	return Some(&self.vectors[val])
		    },
		    None => None,
		}
	}

	pub fn cosine(&self, word: &str) -> Option<Vec<(String, f32)>>
	{
		let word_vector = self.get_vector(word);
		match word_vector {
		    Some(val) => {
		        let mut metrics: Vec<(usize, f32)> = Vec::new();
		        for (index, value) in self.vectors.iter().enumerate(){
		    	    metrics.push((index, dot_product(value, val)));
		        }
		        metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
		        metrics.truncate(20);
		        let mut result: Vec<(String, f32)> = Vec::new();
		        for metric in metrics.iter().skip(1){
		    	    result.push((self.vocabulary[metric.0].clone(), metric.1));
		        }
		        return Some(result)
	        },
		    None => None,
		}
	}

}<|endoftext|>


<commit_before>use libc::{c_int, c_ushort, c_uchar, size_t};

use symbols::{ZOPFLI_WINDOW_MASK, ZOPFLI_MIN_MATCH};

const HASH_SHIFT: c_int = 5;
const HASH_MASK: c_int = 32767;

#[repr(C)]
pub struct ZopfliHash {
    head: Vec<c_int>,  /* Hash value to index of its most recent occurrence. */
    prev: Vec<c_ushort>,  /* Index to index of prev. occurrence of same hash. */
    hashval: Vec<c_int>,  /* Index to hash value at this index. */
    val: c_int,  /* Current hash value. */

    /* Fields with similar purpose as the above hash, but for the second hash with
    a value that is calculated differently.  */
    head2: Vec<c_int>,  /* Hash value to index of its most recent occurrence. */
    prev2: Vec<c_ushort>,  /* Index to index of prev. occurrence of same hash. */
    hashval2: Vec<c_int>,  /* Index to hash value at this index. */
    val2: c_int,  /* Current hash value. */

    same: Vec<c_ushort>,  /* Amount of repetitions of same byte after this .*/
}

impl ZopfliHash {
    pub fn new(window_size: size_t) -> ZopfliHash {
        ZopfliHash {
           head: vec![-1; 65536],
           prev: (0..window_size as c_ushort).collect::<Vec<_>>(),
           hashval: vec![-1; window_size],
           val: 0,

           /* Fields with similar purpose as the above hash, but for the second hash with
           a value that is calculated differently.  */
           head2: vec![-1; 65536],
           prev2: (0..window_size as c_ushort).collect::<Vec<_>>(),
           hashval2: vec![-1; window_size],
           val2: 0,

           same: vec![0; window_size],
       }
    }

    /// Update the sliding hash value with the given byte. All calls to this function
    /// must be made on consecutive input characters. Since the hash value exists out
    /// of multiple input bytes, a few warmups with this function are needed initially.
    pub fn update(&mut self, c: c_uchar) {
        self.val = ((self.val << HASH_SHIFT) ^ c as c_int) & HASH_MASK;
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn UpdateHashValue(h_ptr: *mut ZopfliHash, c: c_uchar) {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.update(c);
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliWarmupHash(array: *const c_uchar, pos: size_t, end: size_t, h_ptr: *mut ZopfliHash) {
    unsafe {
        UpdateHashValue(h_ptr, *array.offset((pos + 0) as isize));
    }
    if pos + 1 < end {
        unsafe {
            UpdateHashValue(h_ptr, *array.offset((pos + 1) as isize));
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliUpdateHash(array: *const c_uchar, pos: size_t, end: size_t, h_ptr: *mut ZopfliHash) {
    let hpos = (pos & ZOPFLI_WINDOW_MASK) as usize;
    let mut amount: c_int = 0;

    let hash_value = if pos + ZOPFLI_MIN_MATCH as size_t <= end {
        unsafe { *array.offset((pos + ZOPFLI_MIN_MATCH as size_t - 1) as isize) }
    } else {
        0
    };
    UpdateHashValue(h_ptr, hash_value);

    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.hashval[hpos] = h.val;

    if h.head[h.val as usize] != -1 && h.hashval[h.head[h.val as usize] as usize] == h.val {
        h.prev[hpos] = h.head[h.val as usize] as c_ushort;
    } else {
        h.prev[hpos] = hpos as c_ushort;
    }

    h.head[h.val as usize] = hpos as c_int;

    /* Update "same". */
    if h.same[((pos - 1) & ZOPFLI_WINDOW_MASK) as usize] > 1 {
        amount = h.same[((pos - 1) & ZOPFLI_WINDOW_MASK) as usize] as c_int - 1;
    }

    unsafe {
        while pos + amount as size_t + 1 < end && *array.offset(pos as isize) == *array.offset((pos + amount as size_t + 1) as isize) && amount < -1 {
            amount += 1;
        }
    }
    h.same[hpos] = amount as c_ushort;

    h.val2 = (((h.same[hpos] - ZOPFLI_MIN_MATCH) & 255) ^ h.val as c_ushort) as c_int;
    h.hashval2[hpos] = h.val2;
    if h.head2[h.val2 as usize] != -1 as i32 && h.hashval2[h.head2[h.val2 as usize] as usize] == h.val2 {
        h.prev2[hpos] = h.head2[h.val2 as usize] as c_ushort;
    } else {
        h.prev2[hpos] = hpos as c_ushort;
    }
    h.head2[h.val2 as usize] = hpos as c_int;
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashHead(h_ptr: *mut ZopfliHash) -> *mut c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.head.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashPrev(h_ptr: *mut ZopfliHash) -> *mut c_ushort {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.prev.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashHashval(h_ptr: *mut ZopfliHash) -> *mut c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.hashval.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashVal(h_ptr: *mut ZopfliHash) -> c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.val
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashHead2(h_ptr: *mut ZopfliHash) -> *mut c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.head2.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashPrev2(h_ptr: *mut ZopfliHash) -> *mut c_ushort {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.prev2.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashHashval2(h_ptr: *mut ZopfliHash) -> *mut c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.hashval2.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashVal2(h_ptr: *mut ZopfliHash) -> c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.val2
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashSame(h_ptr: *mut ZopfliHash) -> *mut c_ushort {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.same.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliCleanHash(ptr: *mut ZopfliHash) {
    if ptr.is_null() { return }
    unsafe { Box::from_raw(ptr); }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliInitHash(window_size: size_t) -> *mut ZopfliHash {
    Box::into_raw(Box::new(ZopfliHash::new(window_size)))
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliResetHash(window_size: size_t, h_ptr: *mut ZopfliHash) {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };

    h.val = 0;
    h.head = vec![-1; 65536];
    h.prev = (0..window_size as c_ushort).collect::<Vec<_>>();
    h.hashval = vec![-1; window_size];

    h.same = vec![0; window_size];

    h.val2 = 0;
    h.head2 = vec![-1; 65536];
    h.prev2 = (0..window_size as c_ushort).collect::<Vec<_>>();
    h.hashval2 = vec![-1; window_size];
}
<commit_msg>Have ZopfliWarmupHash call the update method on ZopfliHash<commit_after>use libc::{c_int, c_ushort, c_uchar, size_t};

use symbols::{ZOPFLI_WINDOW_MASK, ZOPFLI_MIN_MATCH};

const HASH_SHIFT: c_int = 5;
const HASH_MASK: c_int = 32767;

#[repr(C)]
pub struct ZopfliHash {
    head: Vec<c_int>,  /* Hash value to index of its most recent occurrence. */
    prev: Vec<c_ushort>,  /* Index to index of prev. occurrence of same hash. */
    hashval: Vec<c_int>,  /* Index to hash value at this index. */
    val: c_int,  /* Current hash value. */

    /* Fields with similar purpose as the above hash, but for the second hash with
    a value that is calculated differently.  */
    head2: Vec<c_int>,  /* Hash value to index of its most recent occurrence. */
    prev2: Vec<c_ushort>,  /* Index to index of prev. occurrence of same hash. */
    hashval2: Vec<c_int>,  /* Index to hash value at this index. */
    val2: c_int,  /* Current hash value. */

    same: Vec<c_ushort>,  /* Amount of repetitions of same byte after this .*/
}

impl ZopfliHash {
    pub fn new(window_size: size_t) -> ZopfliHash {
        ZopfliHash {
           head: vec![-1; 65536],
           prev: (0..window_size as c_ushort).collect::<Vec<_>>(),
           hashval: vec![-1; window_size],
           val: 0,

           /* Fields with similar purpose as the above hash, but for the second hash with
           a value that is calculated differently.  */
           head2: vec![-1; 65536],
           prev2: (0..window_size as c_ushort).collect::<Vec<_>>(),
           hashval2: vec![-1; window_size],
           val2: 0,

           same: vec![0; window_size],
       }
    }

    /// Update the sliding hash value with the given byte. All calls to this function
    /// must be made on consecutive input characters. Since the hash value exists out
    /// of multiple input bytes, a few warmups with this function are needed initially.
    pub fn update(&mut self, c: c_uchar) {
        self.val = ((self.val << HASH_SHIFT) ^ c as c_int) & HASH_MASK;
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn UpdateHashValue(h_ptr: *mut ZopfliHash, c: c_uchar) {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.update(c);
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliWarmupHash(array: *const c_uchar, pos: size_t, end: size_t, h_ptr: *mut ZopfliHash) {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    let c = unsafe { *array.offset((pos + 0) as isize) };
    h.update(c);

    if pos + 1 < end {
        let c = unsafe { *array.offset((pos + 1) as isize) };
        h.update(c);
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliUpdateHash(array: *const c_uchar, pos: size_t, end: size_t, h_ptr: *mut ZopfliHash) {
    let hpos = (pos & ZOPFLI_WINDOW_MASK) as usize;
    let mut amount: c_int = 0;

    let hash_value = if pos + ZOPFLI_MIN_MATCH as size_t <= end {
        unsafe { *array.offset((pos + ZOPFLI_MIN_MATCH as size_t - 1) as isize) }
    } else {
        0
    };
    UpdateHashValue(h_ptr, hash_value);

    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.hashval[hpos] = h.val;

    if h.head[h.val as usize] != -1 && h.hashval[h.head[h.val as usize] as usize] == h.val {
        h.prev[hpos] = h.head[h.val as usize] as c_ushort;
    } else {
        h.prev[hpos] = hpos as c_ushort;
    }

    h.head[h.val as usize] = hpos as c_int;

    /* Update "same". */
    if h.same[((pos - 1) & ZOPFLI_WINDOW_MASK) as usize] > 1 {
        amount = h.same[((pos - 1) & ZOPFLI_WINDOW_MASK) as usize] as c_int - 1;
    }

    unsafe {
        while pos + amount as size_t + 1 < end && *array.offset(pos as isize) == *array.offset((pos + amount as size_t + 1) as isize) && amount < -1 {
            amount += 1;
        }
    }
    h.same[hpos] = amount as c_ushort;

    h.val2 = (((h.same[hpos] - ZOPFLI_MIN_MATCH) & 255) ^ h.val as c_ushort) as c_int;
    h.hashval2[hpos] = h.val2;
    if h.head2[h.val2 as usize] != -1 as i32 && h.hashval2[h.head2[h.val2 as usize] as usize] == h.val2 {
        h.prev2[hpos] = h.head2[h.val2 as usize] as c_ushort;
    } else {
        h.prev2[hpos] = hpos as c_ushort;
    }
    h.head2[h.val2 as usize] = hpos as c_int;
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashHead(h_ptr: *mut ZopfliHash) -> *mut c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.head.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashPrev(h_ptr: *mut ZopfliHash) -> *mut c_ushort {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.prev.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashHashval(h_ptr: *mut ZopfliHash) -> *mut c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.hashval.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashVal(h_ptr: *mut ZopfliHash) -> c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.val
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashHead2(h_ptr: *mut ZopfliHash) -> *mut c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.head2.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashPrev2(h_ptr: *mut ZopfliHash) -> *mut c_ushort {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.prev2.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashHashval2(h_ptr: *mut ZopfliHash) -> *mut c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.hashval2.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashVal2(h_ptr: *mut ZopfliHash) -> c_int {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.val2
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliHashSame(h_ptr: *mut ZopfliHash) -> *mut c_ushort {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };
    h.same.as_mut_ptr()
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliCleanHash(ptr: *mut ZopfliHash) {
    if ptr.is_null() { return }
    unsafe { Box::from_raw(ptr); }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliInitHash(window_size: size_t) -> *mut ZopfliHash {
    Box::into_raw(Box::new(ZopfliHash::new(window_size)))
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn ZopfliResetHash(window_size: size_t, h_ptr: *mut ZopfliHash) {
    let h = unsafe {
        assert!(!h_ptr.is_null());
        &mut *h_ptr
    };

    h.val = 0;
    h.head = vec![-1; 65536];
    h.prev = (0..window_size as c_ushort).collect::<Vec<_>>();
    h.hashval = vec![-1; window_size];

    h.same = vec![0; window_size];

    h.val2 = 0;
    h.head2 = vec![-1; 65536];
    h.prev2 = (0..window_size as c_ushort).collect::<Vec<_>>();
    h.hashval2 = vec![-1; window_size];
}
<|endoftext|>


<commit_before>extern crate syntect;
extern crate liquid;
extern crate pulldown_cmark as cmark;

use error;
use itertools::Itertools;

use liquid::Renderable;
use liquid::Context;
use liquid::Token::{self, Identifier};
use liquid::lexer::Element::{self, Expression, Tag, Raw};
use liquid::Error;

use syntect::parsing::{SyntaxDefinition, SyntaxSet};
use syntect::highlighting::{ThemeSet, Theme};
use syntect::html::{IncludeBackground, highlighted_snippet_for_string, styles_to_coloured_html,
                    start_coloured_html_snippet};
use syntect::easy::HighlightLines;

use std::ascii::AsciiExt;
use std::borrow::Cow::Owned;

use self::cmark::Parser;
use self::cmark::Tag as cmarkTag;
use self::cmark::Event::{self, Start, End, Text, Html};

struct Setup {
    syntax_set: SyntaxSet,
    theme_set: ThemeSet,
}

unsafe impl Send for Setup {}
unsafe impl Sync for Setup {}

lazy_static!{
    static ref SETUP: Setup = Setup {
        syntax_set: SyntaxSet::load_defaults_newlines(),
        theme_set: ThemeSet::load_defaults()
    };
}

struct CodeBlock {
    lang: Option<String>,
    code: String,
    theme: Theme,
}

impl Renderable for CodeBlock {
    fn render(&self, _: &mut Context) -> Result<Option<String>, Error> {
        let syntax = match self.lang {
                Some(ref lang) => SETUP.syntax_set.find_syntax_by_token(lang),
                _ => None,
            }
            .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text());

        Ok(Some(highlighted_snippet_for_string(&self.code, syntax, &self.theme)))
    }
}

pub struct DecoratedParser<'a> {
    h: Option<HighlightLines<'a>>,
    parser: Parser<'a>,
    theme: &'a Theme,
}

impl<'a> DecoratedParser<'a> {
    pub fn new(parser: Parser<'a>, theme: &'a Theme) -> Self {
        DecoratedParser {
            h: None,
            parser: parser,
            theme: &theme,
        }
    }
}

impl<'a> Iterator for DecoratedParser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.parser.next() {
            Some(item) => {
                if let Text(text) = item {
                    if let Some(ref mut h) = self.h {
                        let highlighted = &h.highlight(&text);
                        let html = styles_to_coloured_html(highlighted, IncludeBackground::Yes);
                        Some(Html(Owned(html)))
                    } else {
                        Some(Text(text))
                    }
                } else {
                    if let Start(cmarkTag::CodeBlock(ref info)) = item {
                        // set local highlighter, if found
                        let cur_syntax =
                            info.clone()
                                .split(' ')
                                .next()
                                .and_then(|lang| SETUP.syntax_set.find_syntax_by_token(lang))
                                .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text());
                        self.h = Some(HighlightLines::new(&cur_syntax, self.theme));
                        let snippet = start_coloured_html_snippet(self.theme);
                        return Some(Html(Owned(snippet)));
                    }
                    if let End(cmarkTag::CodeBlock(_)) = item {
                        // reset highlighter
                        self.h = None;
                        // close the code block
                        return Some(Html(Owned("
".to_owned())));
                    }

                    Some(item)
                }
            }
            None => None,
        }
    }
}

pub fn initialize_codeblock(arguments: &[Token],
                            tokens: &[Element],
                            theme_name: &str)
                            -> Result<Box<Renderable>, Error> {

    let content = tokens
        .iter()
        .fold("".to_owned(), |a, b| {
            match *b {
                    Expression(_, ref text) |
                    Tag(_, ref text) |
                    Raw(ref text) => text,
                }
                .to_owned() + &a
        });

    let lang = match arguments.iter().next() {
        Some(&Identifier(ref x)) => Some(x.clone()),
        _ => None,
    };

    Ok(Box::new(CodeBlock {
                    code: content,
                    lang: lang,
                    theme: SETUP.theme_set.themes[theme_name].clone(),
                }))
}

pub fn decorate_markdown<'a>(parser: Parser<'a>, theme_name: &str) -> DecoratedParser<'a> {
    DecoratedParser::new(parser, &SETUP.theme_set.themes[theme_name])
}

pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    return Ok(SETUP.theme_set.themes.contains_key(name));
}

pub fn list_syntax_themes<'a>() -> Vec<&'a String> {
    return SETUP.theme_set.themes.keys().collect::<Vec<_>>();
}

pub fn list_syntaxes<'a>() -> Vec<String> {
    fn definition_to_string(sd: &SyntaxDefinition) -> String {
        let extensions = sd.file_extensions.iter().join(&", ".to_owned());
        format!("{} [{}]", sd.name, extensions)
    }

    let mut syntaxes = SETUP
        .syntax_set
        .syntaxes()
        .iter()
        .map(definition_to_string)
        .collect::<Vec<_>>();

    // sort alphabetically with insensitive ascii case
    syntaxes.sort_by_key(|a| (a as &str).to_ascii_lowercase());

    return syntaxes;
}

#[cfg(test)]
mod test {

    use std::default::Default;
    use syntax_highlight::initialize_codeblock;
    use liquid::{self, Renderable, LiquidOptions, Context};

    const CODE_BLOCK: &'static str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const RENDERED: &'static str = "
\nmod test {\n        fn hello(arg: int) -> bool {\n            true\n        \
         }\n    \
         }\n    \
         \n
\n";
    #[test]
    fn test_codeblock_renders_rust() {
        let mut options: LiquidOptions = Default::default();
        options
            .blocks
            .insert("codeblock".to_string(),
                    Box::new(|_, args, tokens, _| {
                                 initialize_codeblock(args, tokens, "base16-ocean.dark")
                             }));
        let template = liquid::parse(&format!("{{% codeblock rust %}}{}{{% endcodeblock %}}",
                                              CODE_BLOCK),
                                     options)
                .unwrap();
        let mut data = Context::new();
        let output = template.render(&mut data);
        assert_eq!(output.unwrap(), Some(RENDERED.to_string()));
    }

}
<commit_msg>refactor: Make relations clear in syntax_highlight<commit_after>use itertools::Itertools;

use liquid;
use liquid::Token::{self, Identifier};
use liquid::lexer::Element::{self, Expression, Tag, Raw};

use syntect::parsing::{SyntaxDefinition, SyntaxSet};
use syntect::highlighting::{ThemeSet, Theme};
use syntect::html::{IncludeBackground, highlighted_snippet_for_string, styles_to_coloured_html,
                    start_coloured_html_snippet};
use syntect::easy::HighlightLines;

use std::ascii::AsciiExt;
use std::borrow::Cow::Owned;

use pulldown_cmark as cmark;
use pulldown_cmark::Event::{self, Start, End, Text, Html};

use error;

struct Setup {
    syntax_set: SyntaxSet,
    theme_set: ThemeSet,
}

unsafe impl Send for Setup {}
unsafe impl Sync for Setup {}

lazy_static!{
    static ref SETUP: Setup = Setup {
        syntax_set: SyntaxSet::load_defaults_newlines(),
        theme_set: ThemeSet::load_defaults()
    };
}

pub fn has_syntax_theme(name: &str) -> error::Result<bool> {
    return Ok(SETUP.theme_set.themes.contains_key(name));
}

pub fn list_syntax_themes<'a>() -> Vec<&'a String> {
    return SETUP.theme_set.themes.keys().collect::<Vec<_>>();
}

pub fn list_syntaxes<'a>() -> Vec<String> {
    fn definition_to_string(sd: &SyntaxDefinition) -> String {
        let extensions = sd.file_extensions.iter().join(&", ".to_owned());
        format!("{} [{}]", sd.name, extensions)
    }

    let mut syntaxes = SETUP
        .syntax_set
        .syntaxes()
        .iter()
        .map(definition_to_string)
        .collect::<Vec<_>>();

    // sort alphabetically with insensitive ascii case
    syntaxes.sort_by_key(|a| (a as &str).to_ascii_lowercase());

    return syntaxes;
}

struct CodeBlock {
    lang: Option<String>,
    code: String,
    theme: Theme,
}

impl liquid::Renderable for CodeBlock {
    fn render(&self, _: &mut liquid::Context) -> Result<Option<String>, liquid::Error> {
        let syntax = match self.lang {
                Some(ref lang) => SETUP.syntax_set.find_syntax_by_token(lang),
                _ => None,
            }
            .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text());

        Ok(Some(highlighted_snippet_for_string(&self.code, syntax, &self.theme)))
    }
}

pub fn initialize_codeblock(arguments: &[Token],
                            tokens: &[Element],
                            theme_name: &str)
                            -> Result<Box<liquid::Renderable>, liquid::Error> {

    let content = tokens
        .iter()
        .fold("".to_owned(), |a, b| {
            match *b {
                    Expression(_, ref text) |
                    Tag(_, ref text) |
                    Raw(ref text) => text,
                }
                .to_owned() + &a
        });

    let lang = match arguments.iter().next() {
        Some(&Identifier(ref x)) => Some(x.clone()),
        _ => None,
    };

    Ok(Box::new(CodeBlock {
                    code: content,
                    lang: lang,
                    theme: SETUP.theme_set.themes[theme_name].clone(),
                }))
}

pub struct DecoratedParser<'a> {
    h: Option<HighlightLines<'a>>,
    parser: cmark::Parser<'a>,
    theme: &'a Theme,
}

impl<'a> DecoratedParser<'a> {
    pub fn new(parser: cmark::Parser<'a>, theme: &'a Theme) -> Self {
        DecoratedParser {
            h: None,
            parser: parser,
            theme: &theme,
        }
    }
}

impl<'a> Iterator for DecoratedParser<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Event<'a>> {
        match self.parser.next() {
            Some(item) => {
                if let Text(text) = item {
                    if let Some(ref mut h) = self.h {
                        let highlighted = &h.highlight(&text);
                        let html = styles_to_coloured_html(highlighted, IncludeBackground::Yes);
                        Some(Html(Owned(html)))
                    } else {
                        Some(Text(text))
                    }
                } else {
                    if let Start(cmark::Tag::CodeBlock(ref info)) = item {
                        // set local highlighter, if found
                        let cur_syntax =
                            info.clone()
                                .split(' ')
                                .next()
                                .and_then(|lang| SETUP.syntax_set.find_syntax_by_token(lang))
                                .unwrap_or_else(|| SETUP.syntax_set.find_syntax_plain_text());
                        self.h = Some(HighlightLines::new(&cur_syntax, self.theme));
                        let snippet = start_coloured_html_snippet(self.theme);
                        return Some(Html(Owned(snippet)));
                    }
                    if let End(cmark::Tag::CodeBlock(_)) = item {
                        // reset highlighter
                        self.h = None;
                        // close the code block
                        return Some(Html(Owned("
".to_owned())));
                    }

                    Some(item)
                }
            }
            None => None,
        }
    }
}

pub fn decorate_markdown<'a>(parser: cmark::Parser<'a>, theme_name: &str) -> DecoratedParser<'a> {
    DecoratedParser::new(parser, &SETUP.theme_set.themes[theme_name])
}

#[cfg(test)]
mod test {

    use std::default::Default;
    use syntax_highlight::initialize_codeblock;
    use liquid::{self, Renderable, LiquidOptions, Context};

    const CODE_BLOCK: &'static str = "mod test {
        fn hello(arg: int) -> bool {
            \
                                      true
        }
    }
    ";

    const RENDERED: &'static str = "
\nmod test {\n        fn hello(arg: int) -> bool {\n            true\n        \
         }\n    \
         }\n    \
         \n
\n";
    #[test]
    fn test_codeblock_renders_rust() {
        let mut options: LiquidOptions = Default::default();
        options
            .blocks
            .insert("codeblock".to_string(),
                    Box::new(|_, args, tokens, _| {
                                 initialize_codeblock(args, tokens, "base16-ocean.dark")
                             }));
        let template = liquid::parse(&format!("{{% codeblock rust %}}{}{{% endcodeblock %}}",
                                              CODE_BLOCK),
                                     options)
                .unwrap();
        let mut data = Context::new();
        let output = template.render(&mut data);
        assert_eq!(output.unwrap(), Some(RENDERED.to_string()));
    }

}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// Blah blah blah
/// ``` ignore
/// bad_assert!();
/// ```
pub fn foo() {}

<commit_msg>Fix tidy trailing newlines<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// Blah blah blah
/// ``` ignore
/// bad_assert!();
/// ```
pub fn foo() {}
<|endoftext|>