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

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("Pointing", inherited=True, gecko_name="UserInterface") %>

<%helpers:longhand name="cursor" boxed="${product == 'gecko'}" animation_type="none"
  spec="https://drafts.csswg.org/css-ui/#cursor">
    pub use self::computed_value::T as SpecifiedValue;
    use values::HasViewportPercentage;
    use values::computed::ComputedValueAsSpecified;
    use values::specified::url::SpecifiedUrl;

    impl ComputedValueAsSpecified for SpecifiedValue {}
    no_viewport_percentage!(SpecifiedValue);

    pub mod computed_value {
        use std::fmt;
        use style_traits::cursor::Cursor;
        use style_traits::ToCss;
        use values::specified::url::SpecifiedUrl;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum Keyword {
            AutoCursor,
            SpecifiedCursor(Cursor),
        }

        #[cfg(not(feature = "gecko"))]
        pub type T = Keyword;

        #[cfg(feature = "gecko")]
        #[derive(Clone, PartialEq, Debug)]
        pub struct Image {
            pub url: SpecifiedUrl,
            pub hotspot: Option<(f32, f32)>,
        }

        #[cfg(feature = "gecko")]
        #[derive(Clone, PartialEq, Debug)]
        pub struct T {
            pub images: Vec<Image>,
            pub keyword: Keyword,
        }

        impl ToCss for Keyword {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match *self {
                    Keyword::AutoCursor => dest.write_str("auto"),
                    Keyword::SpecifiedCursor(c) => c.to_css(dest),
                }
            }
        }

        #[cfg(feature = "gecko")]
        impl ToCss for Image {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                try!(self.url.to_css(dest));
                if let Some((x, y)) = self.hotspot {
                    try!(dest.write_str(" "));
                    try!(x.to_css(dest));
                    try!(dest.write_str(" "));
                    try!(y.to_css(dest));
                }
                Ok(())
            }
        }

        #[cfg(feature = "gecko")]
        impl ToCss for T {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                for url in &self.images {
                    try!(url.to_css(dest));
                    try!(dest.write_str(", "));
                }
                self.keyword.to_css(dest)
            }
        }
    }

    #[cfg(not(feature = "gecko"))]
    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::Keyword::AutoCursor
    }

    #[cfg(feature = "gecko")]
    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T {
            images: vec![],
            keyword: computed_value::Keyword::AutoCursor
        }
    }

    impl Parse for computed_value::Keyword {
        fn parse(_context: &ParserContext, input: &mut Parser) -> Result<computed_value::Keyword, ()> {
            use std::ascii::AsciiExt;
            use style_traits::cursor::Cursor;
            let ident = try!(input.expect_ident());
            if ident.eq_ignore_ascii_case("auto") {
                Ok(computed_value::Keyword::AutoCursor)
            } else {
                Cursor::from_css_keyword(&ident).map(computed_value::Keyword::SpecifiedCursor)
            }
        }
    }

    #[cfg(feature = "gecko")]
    fn parse_image(context: &ParserContext, input: &mut Parser) -> Result<computed_value::Image, ()> {
        Ok(computed_value::Image {
            url: try!(SpecifiedUrl::parse(context, input)),
            hotspot: match input.try(|input| input.expect_number()) {
                Ok(number) => Some((number, try!(input.expect_number()))),
                Err(()) => None,
            },
        })
    }

    #[cfg(not(feature = "gecko"))]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        computed_value::Keyword::parse(context, input)
    }

    /// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
    #[cfg(feature = "gecko")]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        let mut images = vec![];
        loop {
            match input.try(|input| parse_image(context, input)) {
                Ok(image) => images.push(image),
                Err(()) => break,
            }
            try!(input.expect_comma());
        }

        Ok(computed_value::T {
            images: images,
            keyword: try!(computed_value::Keyword::parse(context, input)),
        })
    }
</%helpers:longhand>

// NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact)
// is nonstandard, slated for CSS4-UI.
// TODO(pcwalton): SVG-only values.
${helpers.single_keyword("pointer-events", "auto none", animation_type="none",
                         spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty")}

${helpers.single_keyword("-moz-user-input", "auto none enabled disabled",
                         products="gecko", gecko_ffi_name="mUserInput",
                         gecko_enum_prefix="StyleUserInput",
                         gecko_inexhaustive=True,
                         animation_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input)")}

${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only",
                         products="gecko", gecko_ffi_name="mUserModify",
                         gecko_enum_prefix="StyleUserModify",
                         needs_conversion=True,
                         animation_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)")}

${helpers.single_keyword("-moz-user-focus",
                         "none ignore normal select-after select-before select-menu select-same select-all",
                         products="gecko", gecko_ffi_name="mUserFocus",
                         gecko_enum_prefix="StyleUserFocus",
                         gecko_inexhaustive=True,
                         animation_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-focus)")}

${helpers.predefined_type("caret-color",
                          "ColorOrAuto",
                          "Either::Second(Auto)",
                          spec="https://drafts.csswg.org/css-ui/#caret-color",
                          animation_type="normal",
                          boxed=True,
                          products="gecko")}
<commit_msg>Auto merge of #16514 - nox:pointer-events, r=upsuper<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("Pointing", inherited=True, gecko_name="UserInterface") %>

<%helpers:longhand name="cursor" boxed="${product == 'gecko'}" animation_type="none"
  spec="https://drafts.csswg.org/css-ui/#cursor">
    pub use self::computed_value::T as SpecifiedValue;
    use values::HasViewportPercentage;
    use values::computed::ComputedValueAsSpecified;
    use values::specified::url::SpecifiedUrl;

    impl ComputedValueAsSpecified for SpecifiedValue {}
    no_viewport_percentage!(SpecifiedValue);

    pub mod computed_value {
        use std::fmt;
        use style_traits::cursor::Cursor;
        use style_traits::ToCss;
        use values::specified::url::SpecifiedUrl;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum Keyword {
            AutoCursor,
            SpecifiedCursor(Cursor),
        }

        #[cfg(not(feature = "gecko"))]
        pub type T = Keyword;

        #[cfg(feature = "gecko")]
        #[derive(Clone, PartialEq, Debug)]
        pub struct Image {
            pub url: SpecifiedUrl,
            pub hotspot: Option<(f32, f32)>,
        }

        #[cfg(feature = "gecko")]
        #[derive(Clone, PartialEq, Debug)]
        pub struct T {
            pub images: Vec<Image>,
            pub keyword: Keyword,
        }

        impl ToCss for Keyword {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match *self {
                    Keyword::AutoCursor => dest.write_str("auto"),
                    Keyword::SpecifiedCursor(c) => c.to_css(dest),
                }
            }
        }

        #[cfg(feature = "gecko")]
        impl ToCss for Image {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                try!(self.url.to_css(dest));
                if let Some((x, y)) = self.hotspot {
                    try!(dest.write_str(" "));
                    try!(x.to_css(dest));
                    try!(dest.write_str(" "));
                    try!(y.to_css(dest));
                }
                Ok(())
            }
        }

        #[cfg(feature = "gecko")]
        impl ToCss for T {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                for url in &self.images {
                    try!(url.to_css(dest));
                    try!(dest.write_str(", "));
                }
                self.keyword.to_css(dest)
            }
        }
    }

    #[cfg(not(feature = "gecko"))]
    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::Keyword::AutoCursor
    }

    #[cfg(feature = "gecko")]
    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T {
            images: vec![],
            keyword: computed_value::Keyword::AutoCursor
        }
    }

    impl Parse for computed_value::Keyword {
        fn parse(_context: &ParserContext, input: &mut Parser) -> Result<computed_value::Keyword, ()> {
            use std::ascii::AsciiExt;
            use style_traits::cursor::Cursor;
            let ident = try!(input.expect_ident());
            if ident.eq_ignore_ascii_case("auto") {
                Ok(computed_value::Keyword::AutoCursor)
            } else {
                Cursor::from_css_keyword(&ident).map(computed_value::Keyword::SpecifiedCursor)
            }
        }
    }

    #[cfg(feature = "gecko")]
    fn parse_image(context: &ParserContext, input: &mut Parser) -> Result<computed_value::Image, ()> {
        Ok(computed_value::Image {
            url: try!(SpecifiedUrl::parse(context, input)),
            hotspot: match input.try(|input| input.expect_number()) {
                Ok(number) => Some((number, try!(input.expect_number()))),
                Err(()) => None,
            },
        })
    }

    #[cfg(not(feature = "gecko"))]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        computed_value::Keyword::parse(context, input)
    }

    /// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
    #[cfg(feature = "gecko")]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        let mut images = vec![];
        loop {
            match input.try(|input| parse_image(context, input)) {
                Ok(image) => images.push(image),
                Err(()) => break,
            }
            try!(input.expect_comma());
        }

        Ok(computed_value::T {
            images: images,
            keyword: try!(computed_value::Keyword::parse(context, input)),
        })
    }
</%helpers:longhand>

// NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact)
// is nonstandard, slated for CSS4-UI.
// TODO(pcwalton): SVG-only values.
${helpers.single_keyword("pointer-events", "auto none", animation_type="none",
                         extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke",
                         spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty")}

${helpers.single_keyword("-moz-user-input", "auto none enabled disabled",
                         products="gecko", gecko_ffi_name="mUserInput",
                         gecko_enum_prefix="StyleUserInput",
                         gecko_inexhaustive=True,
                         animation_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input)")}

${helpers.single_keyword("-moz-user-modify", "read-only read-write write-only",
                         products="gecko", gecko_ffi_name="mUserModify",
                         gecko_enum_prefix="StyleUserModify",
                         needs_conversion=True,
                         animation_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-modify)")}

${helpers.single_keyword("-moz-user-focus",
                         "none ignore normal select-after select-before select-menu select-same select-all",
                         products="gecko", gecko_ffi_name="mUserFocus",
                         gecko_enum_prefix="StyleUserFocus",
                         gecko_inexhaustive=True,
                         animation_type="none",
                         spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-focus)")}

${helpers.predefined_type("caret-color",
                          "ColorOrAuto",
                          "Either::Second(Auto)",
                          spec="https://drafts.csswg.org/css-ui/#caret-color",
                          animation_type="normal",
                          boxed=True,
                          products="gecko")}
<|endoftext|>


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

use rustc_serialize::json::{Json,Array};

pub fn path<'a>(json: &'a Json, path: &str) -> &'a Json {
    let parts = path.split(".");
    let mut cur = json;
    for p in parts {
        cur = match cur.as_object().unwrap().get(p) {
            Some(c) => c,
            None => panic!("Could not find {} in {} (lost at {})", path, json.pretty(), p)
        }
    }
    cur
}

pub fn array<'a>(json: &'a Json, path: &str) -> &'a Array {
    match self::path(json, path).as_array() {
        Some(p) => p,
        None => panic!("{} in {} is not an array", path, json.pretty())
    }
}

pub fn string<'a>(json: &'a Json, path: &str) -> &'a str{
    match self::path(json, path).as_string() {
        Some(p) => p,
        None => panic!("{} in {} is not an array", path, json.pretty())
    }
}
<commit_msg>fix a typo and add a question<commit_after>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use rustc_serialize::json::{Json,Array};

pub fn path<'a>(json: &'a Json, path: &str) -> &'a Json {
    // why not just use json.find_path ooi? -matthew
    let parts = path.split(".");
    let mut cur = json;
    for p in parts {
        cur = match cur.as_object().unwrap().get(p) {
            Some(c) => c,
            None => panic!("Could not find {} in {} (lost at {})", path, json.pretty(), p)
        }
    }
    cur
}

pub fn array<'a>(json: &'a Json, path: &str) -> &'a Array {
    match self::path(json, path).as_array() {
        Some(p) => p,
        None => panic!("{} in {} is not an array", path, json.pretty())
    }
}

pub fn string<'a>(json: &'a Json, path: &str) -> &'a str{
    match self::path(json, path).as_string() {
        Some(p) => p,
        None => panic!("{} in {} is not a string", path, json.pretty())
    }
}
<|endoftext|>


<commit_before>
import std::vec;
import std::option;
import std::option::some;
import std::option::none;
import std::int;
import std::uint;
import syntax::ast::*;
import syntax::walk;
import syntax::codemap::span;
import std::map::new_str_hash;
import util::common::log_expr_err;
import util::common::log_block_err;
import util::common::log_item_err;
import util::common::log_stmt_err;
import util::common::log_expr;
import util::common::log_block;
import util::common::log_stmt;
import aux::fn_info;
import aux::fn_info_map;
import aux::num_constraints;
import aux::get_fn_info;
import aux::crate_ctxt;
import aux::add_node;
import middle::tstate::ann::empty_ann;

fn collect_ids_expr(&@expr e, @mutable vec[node_id] rs) {
    vec::push(*rs, e.id);
}

fn collect_ids_block(&block b, @mutable vec[node_id] rs) {
    vec::push(*rs, b.node.id);
}

fn collect_ids_stmt(&@stmt s, @mutable vec[node_id] rs) {
    alt (s.node) {
        case (stmt_decl(_, ?id)) {
            log "node_id " + int::str(id);
            log_stmt(*s);
            vec::push(*rs, id);
        }
        case (stmt_expr(_, ?id)) {
            log "node_id " + int::str(id);
            log_stmt(*s);
            vec::push(*rs, id);
        }
        case (_) { }
    }
}

fn collect_ids_local(&@local l, @mutable vec[node_id] rs) {
    vec::push(*rs, l.node.id);
}

fn node_ids_in_fn(&_fn f, &vec[ty_param] tps, &span sp, &fn_ident i,
                  node_id id, @mutable vec[node_id] rs) {
    auto collect_ids = walk::default_visitor();
    collect_ids =
        rec(visit_expr_pre=bind collect_ids_expr(_, rs),
            visit_block_pre=bind collect_ids_block(_, rs),
            visit_stmt_pre=bind collect_ids_stmt(_, rs),
            visit_local_pre=bind collect_ids_local(_, rs) with collect_ids);
    walk::walk_fn(collect_ids, f, tps, sp, i, id);
}

fn init_vecs(&crate_ctxt ccx, &vec[node_id] node_ids, uint len) {
    for (node_id i in node_ids) {
        log int::str(i) + " |-> " + uint::str(len);
        add_node(ccx, i, empty_ann(len));
    }
}

fn visit_fn(&crate_ctxt ccx, uint num_constraints, &_fn f, &vec[ty_param] tps,
            &span sp, &fn_ident i, node_id id) {
    let @mutable vec[node_id] node_ids = @mutable [];
    node_ids_in_fn(f, tps, sp, i, id, node_ids);
    auto node_id_vec = *node_ids;
    init_vecs(ccx, node_id_vec, num_constraints);
}

fn annotate_in_fn(&crate_ctxt ccx, &_fn f, &vec[ty_param] tps,
                  &span sp, &fn_ident i, node_id id) {
    auto f_info = get_fn_info(ccx, id);
    visit_fn(ccx, num_constraints(f_info), f, tps, sp, i, id);
}

fn annotate_crate(&crate_ctxt ccx, &crate crate) {
    auto do_ann = walk::default_visitor();
    do_ann =
        rec(visit_fn_pre=bind annotate_in_fn(ccx, _, _, _, _, _) with do_ann);
    walk::walk_crate(do_ann, crate);
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>rustc: Move tstate::annotate over to interior vectors<commit_after>
import std::vec;
import std::option;
import std::option::some;
import std::option::none;
import std::int;
import std::uint;
import syntax::ast::*;
import syntax::walk;
import syntax::codemap::span;
import std::map::new_str_hash;
import util::common::log_expr_err;
import util::common::log_block_err;
import util::common::log_item_err;
import util::common::log_stmt_err;
import util::common::log_expr;
import util::common::log_block;
import util::common::log_stmt;
import aux::fn_info;
import aux::fn_info_map;
import aux::num_constraints;
import aux::get_fn_info;
import aux::crate_ctxt;
import aux::add_node;
import middle::tstate::ann::empty_ann;

fn collect_ids_expr(&@expr e, @mutable node_id[] rs) {
    *rs += ~[e.id];
}

fn collect_ids_block(&block b, @mutable node_id[] rs) {
    *rs += ~[b.node.id];
}

fn collect_ids_stmt(&@stmt s, @mutable node_id[] rs) {
    alt (s.node) {
        case (stmt_decl(_, ?id)) {
            log "node_id " + int::str(id);
            log_stmt(*s);
            *rs += ~[id];
        }
        case (stmt_expr(_, ?id)) {
            log "node_id " + int::str(id);
            log_stmt(*s);
            *rs += ~[id];
        }
        case (_) { }
    }
}

fn collect_ids_local(&@local l, @mutable node_id[] rs) {
    *rs += ~[l.node.id];
}

fn node_ids_in_fn(&_fn f, &vec[ty_param] tps, &span sp, &fn_ident i,
                  node_id id, @mutable node_id[] rs) {
    auto collect_ids = walk::default_visitor();
    collect_ids =
        rec(visit_expr_pre=bind collect_ids_expr(_, rs),
            visit_block_pre=bind collect_ids_block(_, rs),
            visit_stmt_pre=bind collect_ids_stmt(_, rs),
            visit_local_pre=bind collect_ids_local(_, rs) with collect_ids);
    walk::walk_fn(collect_ids, f, tps, sp, i, id);
}

fn init_vecs(&crate_ctxt ccx, &node_id[] node_ids, uint len) {
    for (node_id i in node_ids) {
        log int::str(i) + " |-> " + uint::str(len);
        add_node(ccx, i, empty_ann(len));
    }
}

fn visit_fn(&crate_ctxt ccx, uint num_constraints, &_fn f, &vec[ty_param] tps,
            &span sp, &fn_ident i, node_id id) {
    let @mutable node_id[] node_ids = @mutable ~[];
    node_ids_in_fn(f, tps, sp, i, id, node_ids);
    auto node_id_vec = *node_ids;
    init_vecs(ccx, node_id_vec, num_constraints);
}

fn annotate_in_fn(&crate_ctxt ccx, &_fn f, &vec[ty_param] tps,
                  &span sp, &fn_ident i, node_id id) {
    auto f_info = get_fn_info(ccx, id);
    visit_fn(ccx, num_constraints(f_info), f, tps, sp, i, id);
}

fn annotate_crate(&crate_ctxt ccx, &crate crate) {
    auto do_ann = walk::default_visitor();
    do_ann =
        rec(visit_fn_pre=bind annotate_in_fn(ccx, _, _, _, _, _) with do_ann);
    walk::walk_crate(do_ann, crate);
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::rt::io::Writer;
use std::cast::transmute_mut;

pub struct RustWriter {
	writer: ~Writer,
	indent: Cell<uint>,
}

impl RustWriter {
	pub fn new<W: Writer+Send>(writer: W) -> RustWriter {
		RustWriter {
			writer: ~writer as ~Writer,
			indent: Cell::new(0)
		}
	}

	#[inline]
	pub fn write(&self, s: &str){
		// This struct cannot be mutable without causing borrowck errors
		// when methods are passed closures that also reference the struct
		let w = unsafe { transmute_mut(&self.writer) };
		w.write(s.as_bytes());
	}

	pub fn write_indent(&self) {
		do self.indent.with_ref |&indent| {
			for _ in range(0, indent) {
				self.write("    ");
			}
		}
	}

	pub fn line(&self, line: &str) {
		self.write_indent();
		self.write(line);
		self.write("\n");
	}

	pub fn comment(&self, comment: &str) {
		self.write_indent();
		self.write("// ");
		self.write(comment);
		self.write("\n");

	}

	pub fn indented(&self, inner: &fn()) {
		do self.indent.with_mut_ref |i| {*i += 1;}
		inner();
		do self.indent.with_mut_ref |i| {*i -= 1;}
	}

	pub fn let_stmt(&self, varname: &str, value: &str) {
		self.write_indent();
		self.write("let ");
		self.write(varname);
		self.write(" = ");
		self.write(value);
		self.write(";\n");
	}

	pub fn let_mut_stmt(&self, varname: &str, value: &str) {
		self.write_indent();
		self.write("let mut ");
		self.write(varname);
		self.write(" = ");
		self.write(value);
		self.write(";\n");
	}

	pub fn let_block(&self, varname: &str, inner: &fn()){
		self.write_indent();
		self.write("let ");
		self.write(varname);
		self.write(" = {\n");
		self.indented(inner);
		self.write_indent();
		self.write("};\n")
	}

	pub fn block(&self, inner: &fn())  {
		self.write(" {\n");
		self.indented(inner);
		self.write_indent();
		self.write("}");
	}

	pub fn def_fn(&self, public: bool, name: &str, args: &str, retn: &str, inner: &fn()) {
		self.write_indent();
		if public { self.write("pub "); }
		self.write("fn ");
		self.write(name);
		self.write("(");
		self.write(args);
		self.write(") -> ");
		self.write(retn);
		self.block(inner);
		self.write("\n");
	}

	#[inline]
	pub fn cond_block(&self, kwd: &str, condition: &str, inner: &fn()) {
		self.write_indent();
		self.write(kwd);
		self.write(condition);
		self.block(inner);
		self.write("\n");
	}

	pub fn if_block(&self, condition: &str, inner: &fn()) {
		self.cond_block("if ", condition, inner);
	}

	pub fn if_else(&self, condition: &str, if_inner: &fn(), else_inner: &fn()) {
		self.write_indent();
		self.write("if ");
		self.write(condition);
		self.block(if_inner);
		self.write(" else");
		self.block(else_inner);
		self.write("\n");
	}

	pub fn loop_block(&self, inner: &fn()) {
		self.write_indent();
		self.write("loop");
		self.block(inner);
		self.write("\n");
	}

	pub fn while_block(&self, condition: &str, inner: &fn()) {
		self.cond_block("while ", condition, inner);
	}

	pub fn match_block(&self, expr: &str, inner: &fn()) {
		self.cond_block("match ", expr, inner);
	}

	pub fn match_inline_case(&self, m: &str, e: &str) {
		self.write_indent();
		self.write(m);
		self.write(" => ");
		self.write(e);
		self.write(",\n");
	}

	pub fn match_case(&self, m: &str, inner: &fn()) {
		self.write_indent();
		self.write(m);
		self.write(" => {\n");
		self.indented(inner);
		self.write_indent();
		self.write("}\n");
	}

	pub fn def_enum(&self, public: bool, name: &str, inner: &fn()) {
		self.write_indent();
		if public { self.write("pub "); }
		self.write("enum ");
		self.write(name);
		self.block(inner);
		self.write("\n");
	}

	pub fn enum_simple(&self, name: &str){
		self.write_indent();
		self.write(name);
		self.write(",\n");
	}

	pub fn enum_tuple(&self, name: &str, types: &[&str]) {
		self.write_indent();
		self.write(name);
		self.write("(");
		for &i in types.iter() {
			self.write(i);
			self.write(", "); // TODO: don't leave a trailing comma
		}
		self.write("),\n");
	}

	pub fn enum_struct(&self, name: &str, inner: &fn()) {
		self.write_indent();
		self.write(name);
		self.block(inner);
		self.write(",\n");
	}

	pub fn struct_field(&self, name: &str, typename: &str) {
		self.write_indent();
		self.write(name);
		self.write(": ");
		self.write(typename);
		self.write(",\n");
	}
}<commit_msg>Clean up codegen.rs with write!()<commit_after>use std::cell::Cell;
use std::rt::io::Writer;
use std::cast::transmute_mut;

pub struct RustWriter {
	writer: ~Writer,
	indent: Cell<uint>,
}

impl RustWriter {
	pub fn new<W: Writer+Send>(writer: W) -> RustWriter {
		RustWriter {
			writer: ~writer as ~Writer,
			indent: Cell::new(0)
		}
	}

	#[inline]
	pub fn write(&self, s: &str){
		self.writer().write(s.as_bytes());
	}

	#[inline]
	pub fn writer<'a>(&'a self) -> &'a mut Writer {
		// This struct cannot be mutable without causing borrowck errors
		// when methods are passed closures that also reference the struct
		unsafe { &'a mut transmute_mut(self).writer as &'a mut Writer }
	}

	pub fn write_indent(&self) {
		do self.indent.with_ref |&indent| {
			for _ in range(0, indent) {
				self.write("    ");
			}
		}
	}

	pub fn line(&self, line: &str) {
		self.write_indent();
		self.write(line);
		self.write("\n");
	}

	pub fn comment(&self, comment: &str) {
		self.write_indent();
		self.write("// ");
		self.write(comment);
		self.write("\n");

	}

	pub fn indented(&self, inner: &fn()) {
		do self.indent.with_mut_ref |i| {*i += 1;}
		inner();
		do self.indent.with_mut_ref |i| {*i -= 1;}
	}

	pub fn let_stmt(&self, varname: &str, value: &str) {
		self.write_indent();
		write!(self.writer(), "let {} = {};\n", varname, value);
	}

	pub fn let_mut_stmt(&self, varname: &str, value: &str) {
		self.write_indent();
		write!(self.writer(), "let mut {} = {};\n", varname, value);
	}

	pub fn let_block(&self, varname: &str, inner: &fn()){
		self.write_indent();
		write!(self.writer(), "let {} = \\{\n", varname);
		self.indented(inner);
		self.write_indent();
		self.write("};\n")
	}

	pub fn block(&self, inner: &fn())  {
		self.write(" {\n");
		self.indented(inner);
		self.write_indent();
		self.write("}");
	}

	pub fn def_fn(&self, public: bool, name: &str, args: &str, retn: &str, inner: &fn()) {
		self.write_indent();
		if public { self.write("pub "); }
		write!(self.writer(), "fn {}({}) -> {}", name, args, retn);
		self.block(inner);
		self.write("\n");
	}

	#[inline]
	pub fn cond_block(&self, kwd: &str, condition: &str, inner: &fn()) {
		self.write_indent();
		self.write(kwd);
		self.write(condition);
		self.block(inner);
		self.write("\n");
	}

	pub fn if_block(&self, condition: &str, inner: &fn()) {
		self.cond_block("if ", condition, inner);
	}

	pub fn if_else(&self, condition: &str, if_inner: &fn(), else_inner: &fn()) {
		self.write_indent();
		self.write("if ");
		self.write(condition);
		self.block(if_inner);
		self.write(" else");
		self.block(else_inner);
		self.write("\n");
	}

	pub fn loop_block(&self, inner: &fn()) {
		self.write_indent();
		self.write("loop");
		self.block(inner);
		self.write("\n");
	}

	pub fn while_block(&self, condition: &str, inner: &fn()) {
		self.cond_block("while ", condition, inner);
	}

	pub fn match_block(&self, expr: &str, inner: &fn()) {
		self.cond_block("match ", expr, inner);
	}

	pub fn match_inline_case(&self, m: &str, e: &str) {
		self.write_indent();
		write!(self.writer(), "{} => {},\n", m, e)
	}

	pub fn match_case(&self, m: &str, inner: &fn()) {
		self.write_indent();
		write!(self.writer(), "{} => \\{\n", m)
		self.indented(inner);
		self.write_indent();
		self.write("}\n");
	}

	pub fn struct_field(&self, name: &str, typename: &str) {
		self.write_indent();
		write!(self.writer(), "{}: {},\n", name, typename);
	}
}<|endoftext|>


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

use anyhow::Result;
use flate2::{write::GzEncoder, Compression};
use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};

use crate::{date_iso, flags, project_root};

impl flags::Dist {
    pub(crate) fn run(self) -> Result<()> {
        let stable =
            std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";

        let project_root = project_root();
        let target = Target::get(&project_root);
        let dist = project_root.join("dist");
        rm_rf(&dist)?;
        mkdir_p(&dist)?;

        let release_channel = if stable { "stable" } else { "nightly" };
        dist_server(release_channel, &target)?;

        if let Some(patch_version) = self.client_patch_version {
            let version = if stable {
                format!("0.2.{}", patch_version)
            } else {
                // A hack to make VS Code prefer nightly over stable.
                format!("0.3.{}", patch_version)
            };
            let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
            dist_client(&version, &release_tag, &target)?;
        }
        Ok(())
    }
}

fn dist_client(version: &str, release_tag: &str, target: &Target) -> Result<()> {
    let bundle_path = Path::new("editors").join("code").join("server");
    mkdir_p(&bundle_path)?;
    cp(&target.server_path, &bundle_path)?;
    if let Some(symbols_path) = &target.symbols_path {
        cp(symbols_path, &bundle_path)?;
    }

    let _d = pushd("./editors/code")?;

    let mut patch = Patch::new("./package.json")?;
    patch
        .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
        .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
        .replace(r#""$generated-start": {},"#, "")
        .replace(",\n                \"$generated-end\": {}", "")
        .replace(r#""enableProposedApi": true,"#, r#""#);
    patch.commit()?;

    Ok(())
}

fn dist_server(release_channel: &str, target: &Target) -> Result<()> {
    let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
    let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "thin");

    // Uncomment to enable debug info for releases. Note that:
    //   * debug info is split on windows and macs, so it does nothing for those platforms,
    //   * on Linux, this blows up the binary size from 8MB to 43MB, which is unreasonable.
    // let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");

    if target.name.contains("-linux-") {
        env::set_var("CC", "clang");
    }

    let target_name = &target.name;
    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} --release").run()?;

    let dst = Path::new("dist").join(&target.artifact_name);
    gzip(&target.server_path, &dst.with_extension("gz"))?;

    Ok(())
}

fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
    let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
    let mut input = io::BufReader::new(File::open(src_path)?);
    io::copy(&mut input, &mut encoder)?;
    encoder.finish()?;
    Ok(())
}

struct Target {
    name: String,
    server_path: PathBuf,
    symbols_path: Option<PathBuf>,
    artifact_name: String,
}

impl Target {
    fn get(project_root: &Path) -> Self {
        let name = match env::var("RA_TARGET") {
            Ok(target) => target,
            _ => {
                if cfg!(target_os = "linux") {
                    "x86_64-unknown-linux-gnu".to_string()
                } else if cfg!(target_os = "windows") {
                    "x86_64-pc-windows-msvc".to_string()
                } else if cfg!(target_os = "macos") {
                    "x86_64-apple-darwin".to_string()
                } else {
                    panic!("Unsupported OS, maybe try setting RA_TARGET")
                }
            }
        };
        let out_path = project_root.join("target").join(&name).join("release");
        let (exe_suffix, symbols_path) = if name.contains("-windows-") {
            (".exe".into(), Some(out_path.join("rust_analyzer.pdb")))
        } else {
            (String::new(), None)
        };
        let server_path = out_path.join(format!("rust-analyzer{}", exe_suffix));
        let artifact_name = format!("rust-analyzer-{}{}", name, exe_suffix);
        Self { name, server_path, symbols_path, artifact_name }
    }
}

struct Patch {
    path: PathBuf,
    original_contents: String,
    contents: String,
}

impl Patch {
    fn new(path: impl Into<PathBuf>) -> Result<Patch> {
        let path = path.into();
        let contents = read_file(&path)?;
        Ok(Patch { path, original_contents: contents.clone(), contents })
    }

    fn replace(&mut self, from: &str, to: &str) -> &mut Patch {
        assert!(self.contents.contains(from));
        self.contents = self.contents.replace(from, to);
        self
    }

    fn commit(&self) -> Result<()> {
        write_file(&self.path, &self.contents)?;
        Ok(())
    }
}

impl Drop for Patch {
    fn drop(&mut self) {
        // FIXME: find a way to bring this back
        let _ = &self.original_contents;
        // write_file(&self.path, &self.original_contents).unwrap();
    }
}
<commit_msg>fix: client distribution string replacement looking for wrong key<commit_after>use std::{
    env,
    fs::File,
    io,
    path::{Path, PathBuf},
};

use anyhow::Result;
use flate2::{write::GzEncoder, Compression};
use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};

use crate::{date_iso, flags, project_root};

impl flags::Dist {
    pub(crate) fn run(self) -> Result<()> {
        let stable =
            std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";

        let project_root = project_root();
        let target = Target::get(&project_root);
        let dist = project_root.join("dist");
        rm_rf(&dist)?;
        mkdir_p(&dist)?;

        let release_channel = if stable { "stable" } else { "nightly" };
        dist_server(release_channel, &target)?;

        if let Some(patch_version) = self.client_patch_version {
            let version = if stable {
                format!("0.2.{}", patch_version)
            } else {
                // A hack to make VS Code prefer nightly over stable.
                format!("0.3.{}", patch_version)
            };
            let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
            dist_client(&version, &release_tag, &target)?;
        }
        Ok(())
    }
}

fn dist_client(version: &str, release_tag: &str, target: &Target) -> Result<()> {
    let bundle_path = Path::new("editors").join("code").join("server");
    mkdir_p(&bundle_path)?;
    cp(&target.server_path, &bundle_path)?;
    if let Some(symbols_path) = &target.symbols_path {
        cp(symbols_path, &bundle_path)?;
    }

    let _d = pushd("./editors/code")?;

    let mut patch = Patch::new("./package.json")?;
    patch
        .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
        .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
        .replace(r#""$generated-start": {},"#, "")
        .replace(",\n                \"$generated-end\": {}", "")
        .replace(r#""enabledApiProposals": true,"#, r#""#);
    patch.commit()?;

    Ok(())
}

fn dist_server(release_channel: &str, target: &Target) -> Result<()> {
    let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
    let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "thin");

    // Uncomment to enable debug info for releases. Note that:
    //   * debug info is split on windows and macs, so it does nothing for those platforms,
    //   * on Linux, this blows up the binary size from 8MB to 43MB, which is unreasonable.
    // let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");

    if target.name.contains("-linux-") {
        env::set_var("CC", "clang");
    }

    let target_name = &target.name;
    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} --release").run()?;

    let dst = Path::new("dist").join(&target.artifact_name);
    gzip(&target.server_path, &dst.with_extension("gz"))?;

    Ok(())
}

fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
    let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
    let mut input = io::BufReader::new(File::open(src_path)?);
    io::copy(&mut input, &mut encoder)?;
    encoder.finish()?;
    Ok(())
}

struct Target {
    name: String,
    server_path: PathBuf,
    symbols_path: Option<PathBuf>,
    artifact_name: String,
}

impl Target {
    fn get(project_root: &Path) -> Self {
        let name = match env::var("RA_TARGET") {
            Ok(target) => target,
            _ => {
                if cfg!(target_os = "linux") {
                    "x86_64-unknown-linux-gnu".to_string()
                } else if cfg!(target_os = "windows") {
                    "x86_64-pc-windows-msvc".to_string()
                } else if cfg!(target_os = "macos") {
                    "x86_64-apple-darwin".to_string()
                } else {
                    panic!("Unsupported OS, maybe try setting RA_TARGET")
                }
            }
        };
        let out_path = project_root.join("target").join(&name).join("release");
        let (exe_suffix, symbols_path) = if name.contains("-windows-") {
            (".exe".into(), Some(out_path.join("rust_analyzer.pdb")))
        } else {
            (String::new(), None)
        };
        let server_path = out_path.join(format!("rust-analyzer{}", exe_suffix));
        let artifact_name = format!("rust-analyzer-{}{}", name, exe_suffix);
        Self { name, server_path, symbols_path, artifact_name }
    }
}

struct Patch {
    path: PathBuf,
    original_contents: String,
    contents: String,
}

impl Patch {
    fn new(path: impl Into<PathBuf>) -> Result<Patch> {
        let path = path.into();
        let contents = read_file(&path)?;
        Ok(Patch { path, original_contents: contents.clone(), contents })
    }

    fn replace(&mut self, from: &str, to: &str) -> &mut Patch {
        assert!(self.contents.contains(from));
        self.contents = self.contents.replace(from, to);
        self
    }

    fn commit(&self) -> Result<()> {
        write_file(&self.path, &self.contents)?;
        Ok(())
    }
}

impl Drop for Patch {
    fn drop(&mut self) {
        // FIXME: find a way to bring this back
        let _ = &self.original_contents;
        // write_file(&self.path, &self.original_contents).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::io::prelude::*;
use std::fs::File;
#[cfg(not(test))] use std::env::home_dir;
use yaml_rust::{YamlLoader, YamlEmitter, Yaml};

mod parser;

static MUXED_FOLDER: &'static str = "muxed";

pub fn open(project_name: String) -> Vec<Command> {
    let yaml = YamlLoader::load_from_str(&read(path_string(project_name))).unwrap();
    parser::main(&yaml)
}

pub fn path_string(project_name: String) -> String {
    format!("{}/.{}/{}.yml", homedir_string(), &MUXED_FOLDER.to_string(), project_name)
}

fn read(config_str: String) -> String {
    let path = Path::new(&config_str);
    let mut s = String::new();
    File::open(path).expect("Config Read error").read_to_string(&mut s);

    return s
}

fn parse_config() {
}

#[cfg(not(test))] fn homedir_string() -> String {
    match home_dir() {
        Some(dir) => format!("{}", dir.display()),
        None      => panic!("Impossible to get your home dir!")
    }
}

#[cfg(test)] fn homedir_string() -> String {
  String::from("/tmp")
}

#[test]
pub fn path_string_returns_muxed_inside_homedir() {
    let path = format!("{}", path_string("".to_string()));
    let new  = format!("{}", Path::new("/tmp/.muxed/").display());
    assert_eq!(path, new)
}
<commit_msg>Trivial cleanup<commit_after>use std::path::Path;
use std::io::prelude::*;
use std::fs::File;
use yaml_rust::{YamlLoader, YamlEmitter, Yaml};
use project::parser::Command;
#[cfg(not(test))] use std::env::home_dir;

mod parser;

static MUXED_FOLDER: &'static str = "muxed";

pub fn open(project_name: String) -> Vec<Command> {
    let yaml = YamlLoader::load_from_str(&read(path_string(project_name))).unwrap();
    parser::main(&yaml)
}

pub fn path_string(project_name: String) -> String {
    format!("{}/.{}/{}.yml", homedir_string(), &MUXED_FOLDER.to_string(), project_name)
}

fn read(config_str: String) -> String {
    let path = Path::new(&config_str);
    let mut s = String::new();
    File::open(path).expect("Config Read error").read_to_string(&mut s);

    return s
}

fn parse_config() {
}

#[cfg(not(test))] fn homedir_string() -> String {
    match home_dir() {
        Some(dir) => format!("{}", dir.display()),
        None      => panic!("Impossible to get your home dir!")
    }
}

#[cfg(test)] fn homedir_string() -> String {
  String::from("/tmp")
}

#[test]
pub fn path_string_returns_muxed_inside_homedir() {
    let path = format!("{}", path_string("".to_string()));
    let new  = format!("{}", Path::new("/tmp/.muxed/").display());
    assert_eq!(path, new)
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::mem;
use std::iter::repeat;

use std::default::Default;

use ops::{CommutativeOperation, Identity};

/// This data structure allows range modification and single element queries.
///
/// This tree allocates `2n * sizeof(N)` bytes of memory.
///
/// This tree is implemented using a binary tree, where each node contains the changes that need
/// to be propogated to its children.
///
///# Examples
///
/// Quickly add something to every value in some interval.
///
///```rust
///use segment_tree::PointSegment;
///use segment_tree::ops::Add;
///
///use std::iter::repeat;
///
/// // make a giant tree of zeroes
///let mut tree: PointSegment<_, Add> = PointSegment::build(repeat(0).take(1_000_000)
///                                                         .collect());
///
/// // add one to every value between 200 and 1000
///tree.modify(200, 500_000, 1);
///assert_eq!(tree.query(100), 0);
///assert_eq!(tree.query(200), 1);
///assert_eq!(tree.query(500), 1);
///assert_eq!(tree.query(499_999), 1);
///assert_eq!(tree.query(500_000), 0);
///
/// // add five to every value between 0 and 1000
///tree.modify(0, 1000, 5);
///assert_eq!(tree.query(10), 5);
///assert_eq!(tree.query(500), 6);
///assert_eq!(tree.query(10_000), 1);
///assert_eq!(tree.query(600_000), 0);
///```
pub struct PointSegment<N, O> where O: CommutativeOperation<N> + Identity<N> {
    buf: Vec<N>,
    n: usize,
    op: PhantomData<O>
}

impl<N, O: CommutativeOperation<N> + Identity<N>> PointSegment<N, O> {
    /// Builds a tree using the given buffer. If the given buffer is less than half full, this
    /// function allocates.
    /// Uses `O(len)` time.
    pub fn build(mut buf: Vec<N>) -> PointSegment<N, O> {
        let n = buf.len();
        buf.reserve_exact(n);
        for i in 0..n {
            let val = mem::replace(&mut buf[i], O::identity());
            buf.push(val);
        }
        PointSegment { buf: buf, n: n, op: PhantomData }
    }
    /// Allocate a new buffer and build the tree using the values in the slice.
    /// Uses `O(len)` time.
    pub fn build_slice(buf: &[N]) -> PointSegment<N, O> where N: Clone {
        let n = buf.len();
        PointSegment {
            buf: repeat(O::identity()).take(n).chain(buf.iter().cloned()).collect(),
            n: n, op: PhantomData
        }
    }
    /// Allocate a new buffer and build the tree using the values in the iterator.
    /// Uses `O(len)` time.
    pub fn build_iter<I: ExactSizeIterator<Item=N>>(iter: I) -> PointSegment<N, O> {
        let n = iter.len();
        let mut buf = Vec::with_capacity(2*n);
        for _ in 0..n { buf.push(O::identity()); }
        buf.extend(iter);
        PointSegment {
            buf: buf,
            n: n, op: PhantomData
        }
    }
    /// Computes the value at `p`.
    /// Uses `O(log(len))` time.
    pub fn query(&self, mut p: usize) -> N {
        p += self.n;
        let mut res = O::identity();
        while p > 0 {
            res = O::combine_left(res, &self.buf[p]);
            p >>= 1;
        }
        res
    }
    /// Combine every value in the interval with `delta`.
    /// Uses `O(log(len))` time.
    pub fn modify(&mut self, mut l: usize, mut r: usize, delta: N) {
        l += self.n; r += self.n;
        while l < r {
            if l&1 == 1 {
                O::combine_mut(&mut self.buf[l], &delta);
                l += 1;
            }
            if r&1 == 1 {
                r -= 1;
                O::combine_mut(&mut self.buf[r], &delta);
            }
            l >>= 1; r >>= 1;
        }
    }
    /// Propogate all changes to the leaves in the tree and return a mutable slice containing the
    /// leaves.
    /// Uses `O(len)` time.
    pub fn propogate(&mut self) -> &mut [N] {
        for i in 1..self.n {
            let prev = mem::replace(&mut self.buf[i], O::identity());
            O::combine_mut(&mut self.buf[i<<1], &prev);
            O::combine_mut(&mut self.buf[i<<1|1], &prev);
        }
        &mut self.buf[self.n..]
    }
    /// Returns the number of values in the underlying array.
    /// Uses `O(1)` time.
    #[inline(always)]
    pub fn len(&self) -> usize {
        self.n
    }
}

impl<N: Clone, O: Identity<N> + CommutativeOperation<N>> Clone for PointSegment<N, O> {
    #[inline]
    fn clone(&self) -> PointSegment<N, O> {
        PointSegment {
            buf: self.buf.clone(), n: self.n, op: PhantomData
        }
    }
}
impl<N, O: Identity<N> + CommutativeOperation<N>> Default for PointSegment<N, O> {
    #[inline]
    fn default() -> PointSegment<N, O> {
        PointSegment { buf: Vec::new(), n: 0, op: PhantomData }
    }
}

#[cfg(test)]
mod tests {
    use propogating::*;
    use ops::*;
    use rand::{Rng, thread_rng};
    use std::num::Wrapping;

    type Num = Wrapping<i32>;

    #[test]
    fn test() {
        let mut rng = thread_rng();
        for i in 1..130 {
            let mut buf: Vec<Num> = rng.gen_iter::<i32>().map(|i| Wrapping(i)).take(i).collect();
            let mut tree: PointSegment<_,Add> = if i&1 == 1 {
                PointSegment::build_slice(&buf[..])
            } else {
                PointSegment::build(buf.clone())
            };
            for (n, m, v) in rng.gen_iter::<(usize, usize, i32)>().take(10) {
                let n = n % i;
                let m = m % i;
                if n > m { continue; }
                for index in n..m { buf[index] += Wrapping(v); }
                tree.modify(n, m, Wrapping(v));
                for index in 0..i {
                    assert_eq!(buf[index], tree.query(index));
                }
            }
            assert_eq!(&mut buf[..], tree.propogate());
        }
    }
}
<commit_msg>change build_slice in propogating.rs to use build_iter<commit_after>use std::marker::PhantomData;
use std::mem;

use std::default::Default;

use ops::{CommutativeOperation, Identity};

/// This data structure allows range modification and single element queries.
///
/// This tree allocates `2n * sizeof(N)` bytes of memory.
///
/// This tree is implemented using a binary tree, where each node contains the changes that need
/// to be propogated to its children.
///
///# Examples
///
/// Quickly add something to every value in some interval.
///
///```rust
///use segment_tree::PointSegment;
///use segment_tree::ops::Add;
///
///use std::iter::repeat;
///
/// // make a giant tree of zeroes
///let mut tree: PointSegment<_, Add> = PointSegment::build(repeat(0).take(1_000_000)
///                                                         .collect());
///
/// // add one to every value between 200 and 1000
///tree.modify(200, 500_000, 1);
///assert_eq!(tree.query(100), 0);
///assert_eq!(tree.query(200), 1);
///assert_eq!(tree.query(500), 1);
///assert_eq!(tree.query(499_999), 1);
///assert_eq!(tree.query(500_000), 0);
///
/// // add five to every value between 0 and 1000
///tree.modify(0, 1000, 5);
///assert_eq!(tree.query(10), 5);
///assert_eq!(tree.query(500), 6);
///assert_eq!(tree.query(10_000), 1);
///assert_eq!(tree.query(600_000), 0);
///```
pub struct PointSegment<N, O> where O: CommutativeOperation<N> + Identity<N> {
    buf: Vec<N>,
    n: usize,
    op: PhantomData<O>
}

impl<N, O: CommutativeOperation<N> + Identity<N>> PointSegment<N, O> {
    /// Builds a tree using the given buffer. If the given buffer is less than half full, this
    /// function allocates.
    /// Uses `O(len)` time.
    pub fn build(mut buf: Vec<N>) -> PointSegment<N, O> {
        let n = buf.len();
        buf.reserve_exact(n);
        for i in 0..n {
            let val = mem::replace(&mut buf[i], O::identity());
            buf.push(val);
        }
        PointSegment { buf: buf, n: n, op: PhantomData }
    }
    /// Allocate a new buffer and build the tree using the values in the slice.
    /// Uses `O(len)` time.
    pub fn build_slice(buf: &[N]) -> PointSegment<N, O> where N: Clone {
        PointSegment::build_iter(buf.iter().cloned())
    }
    /// Allocate a new buffer and build the tree using the values in the iterator.
    /// Uses `O(len)` time.
    pub fn build_iter<I: ExactSizeIterator<Item=N>>(iter: I) -> PointSegment<N, O> {
        let n = iter.len();
        let mut buf = Vec::with_capacity(2*n);
        for _ in 0..n { buf.push(O::identity()); }
        buf.extend(iter);
        PointSegment {
            buf: buf,
            n: n, op: PhantomData
        }
    }
    /// Computes the value at `p`.
    /// Uses `O(log(len))` time.
    pub fn query(&self, mut p: usize) -> N {
        p += self.n;
        let mut res = O::identity();
        while p > 0 {
            res = O::combine_left(res, &self.buf[p]);
            p >>= 1;
        }
        res
    }
    /// Combine every value in the interval with `delta`.
    /// Uses `O(log(len))` time.
    pub fn modify(&mut self, mut l: usize, mut r: usize, delta: N) {
        l += self.n; r += self.n;
        while l < r {
            if l&1 == 1 {
                O::combine_mut(&mut self.buf[l], &delta);
                l += 1;
            }
            if r&1 == 1 {
                r -= 1;
                O::combine_mut(&mut self.buf[r], &delta);
            }
            l >>= 1; r >>= 1;
        }
    }
    /// Propogate all changes to the leaves in the tree and return a mutable slice containing the
    /// leaves.
    /// Uses `O(len)` time.
    pub fn propogate(&mut self) -> &mut [N] {
        for i in 1..self.n {
            let prev = mem::replace(&mut self.buf[i], O::identity());
            O::combine_mut(&mut self.buf[i<<1], &prev);
            O::combine_mut(&mut self.buf[i<<1|1], &prev);
        }
        &mut self.buf[self.n..]
    }
    /// Returns the number of values in the underlying array.
    /// Uses `O(1)` time.
    #[inline(always)]
    pub fn len(&self) -> usize {
        self.n
    }
}

impl<N: Clone, O: Identity<N> + CommutativeOperation<N>> Clone for PointSegment<N, O> {
    #[inline]
    fn clone(&self) -> PointSegment<N, O> {
        PointSegment {
            buf: self.buf.clone(), n: self.n, op: PhantomData
        }
    }
}
impl<N, O: Identity<N> + CommutativeOperation<N>> Default for PointSegment<N, O> {
    #[inline]
    fn default() -> PointSegment<N, O> {
        PointSegment { buf: Vec::new(), n: 0, op: PhantomData }
    }
}

#[cfg(test)]
mod tests {
    use propogating::*;
    use ops::*;
    use rand::{Rng, thread_rng};
    use std::num::Wrapping;

    type Num = Wrapping<i32>;

    #[test]
    fn test() {
        let mut rng = thread_rng();
        for i in 1..130 {
            let mut buf: Vec<Num> = rng.gen_iter::<i32>().map(|i| Wrapping(i)).take(i).collect();
            let mut tree: PointSegment<_,Add> = match i%3 {
                0 => PointSegment::build_slice(&buf[..]),
                1 => PointSegment::build_iter(buf.iter().cloned()),
                2 => PointSegment::build(buf.clone()),
                _ => unreachable!()
            };
            for (n, m, v) in rng.gen_iter::<(usize, usize, i32)>().take(10) {
                let n = n % i;
                let m = m % i;
                if n > m { continue; }
                for index in n..m { buf[index] += Wrapping(v); }
                tree.modify(n, m, Wrapping(v));
                for index in 0..i {
                    assert_eq!(buf[index], tree.query(index));
                }
            }
            assert_eq!(&mut buf[..], tree.propogate());
        }
    }
}
<|endoftext|>


<commit_before>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;
pub type wchar_t = u32;
<commit_msg>Correct the type of c_char.<commit_after>pub type c_char = u8;
pub type c_long = i64;
pub type c_ulong = u64;
pub type wchar_t = u32;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs;
use std::path::*;
use std::io::{Result, Write};
use case::CaseExt;

use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::ffi_type::ffi_type;
use super::functions;
use super::statics;
use super::super::general::{self, tabs};
use traits::*;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys("lib"));

    let parent = path.parent().unwrap();
    //TODO: do only if not exists
    let _ = fs::create_dir(parent);

    println!("Generating file {:?}", path);
    save_to_file(&path, &mut |w| generate_lib(w, env));
}

fn generate_lib<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));
    try!(statics::begin(w));

    try!(generate_extern_crates(w, env));
    try!(statics::after_extern_crates(w));

    if env.config.library_name != "GLib" {
        try!(statics::use_glib_ffi(w));
    } else {
        try!(statics::only_for_glib(w));
    }
    if env.config.library_name == "Gtk" {
        try!(statics::only_for_gtk(w));
    }

    let ns = env.library.namespace(library::MAIN_NAMESPACE);
    let classes = prepare(ns);
    let interfaces = prepare(ns);

    try!(generate_aliases(w, env, &prepare(ns)));
    try!(generate_enums(w, &ns.name, &prepare(ns)));
    try!(generate_bitfields(w, &ns.name, &prepare(ns)));
    try!(generate_unions(w, &prepare(ns)));
    try!(functions::generate_callbacks(w, env, &prepare(ns)));
    try!(generate_records(w, env, &prepare(ns)));
    try!(generate_classes_structs(w, &classes));
    try!(generate_interfaces_structs(w, &interfaces));

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(functions::generate_classes_funcs(w, env, &classes));
    try!(functions::generate_interfaces_funcs(w, env, &interfaces));

    //TODO: other functions
    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn generate_extern_crates<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    for library_name in &env.config.external_libraries {
        try!(writeln!(w, "extern crate {0}_sys as {0}_ffi;", crate_name(library_name)));
    }

    Ok(())
}

fn prepare<T: Ord>(ns: &library::Namespace) -> Vec<&T>
where library::Type: MaybeRef<T> {
    let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len());
    for typ in ns.types.iter().filter_map(|t| t.as_ref()) {
        if let Some(ref x) = typ.maybe_ref() {
            vec.push(x);
        }
    }
    vec.sort();
    vec
}

fn generate_aliases<W: Write>(w: &mut W, env: &Env, items: &[&library::Alias])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        let (comment, c_type) = match ffi_type(env, item.typ, &item.target_c_type) {
            Ok(x) => ("", x),
            Err(x) => ("//", x),
        };
        try!(writeln!(w, "{}pub type {} = {};", comment, item.c_identifier, c_type));
    }

    Ok(())
}

fn generate_bitfields<W: Write>(w: &mut W, ns_name: &str, items: &[&library::Bitfield])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        try!(writeln!(w, "bitflags! {{\n{}#[repr(C)]\n{0}flags {}: c_uint {{", tabs(1), item.name));
        for member in &item.members {
            let val: i64 = member.value.parse().unwrap();
            try!(writeln!(w, "{}const {} = {},",
                          tabs(2), strip_prefix(ns_name, &member.c_identifier), val as u32));
        }
        try!(writeln!(w, "{}}}\n}}", tabs(1)));
        try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_enums<W: Write>(w: &mut W, ns_name: &str, items: &[&library::Enumeration])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if item.members.len() == 1 {
            try!(writeln!(w, "pub type {} = c_int;", item.name));
            try!(writeln!(w, "pub const {}: {} = {};",
                          item.members[0].c_identifier, item.name, item.members[0].value));
            try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
            try!(writeln!(w, ""));
            continue;
        }

        let mut vals = HashMap::new();
        try!(writeln!(w, "#[derive(Clone, Copy, Debug, Eq, PartialEq)]\n#[repr(C)]"));
        try!(writeln!(w, "pub enum {} {{", item.name));
        for member in &item.members {
            if vals.get(&member.value).is_some() {
                continue;
            }
            try!(writeln!(w, "{}{} = {},",
                          tabs(1), &prepare_enum_member_name(&member.name), member.value));
            vals.insert(member.value.clone(), member.name.clone());
        }
        try!(writeln!(w, "}}"));
        for member in &item.members {
            try!(writeln!(w, "pub const {}: {} = {1}::{};",
                          strip_prefix(ns_name, &member.c_identifier),
                          item.name, &prepare_enum_member_name(vals.get(&member.value).unwrap())));
        }
        try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_unions<W: Write>(w: &mut W, items: &[&library::Union])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        try!(writeln!(w, "pub type {} = c_void;", item.name));
        if let Some(ref c_type) = item.c_type {
            try!(writeln!(w, "pub type {} = {};", c_type, item.name));
        }
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn prepare_enum_member_name(name: &str) -> String {
    let cameled = name.to_camel();
    if name.chars().next().unwrap().is_digit(10) {
        format!("_{}", cameled)
    } else {
        cameled
    }
}

fn generate_classes_structs<W: Write>(w: &mut W, classes: &[&library::Class]) -> Result<()> {
    try!(writeln!(w, ""));
    for klass in classes {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", klass.c_type));
    }

    Ok(())
}

fn generate_interfaces_structs<W: Write>(w: &mut W, interfaces: &[&library::Interface]) -> Result<()> {
    try!(writeln!(w, ""));
    for interface in interfaces {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", interface.c_type));
    }

    Ok(())
}

fn generate_records<W: Write>(w: &mut W, env: &Env, records: &[&library::Record]) -> Result<()> {
    try!(writeln!(w, ""));
    for record in records {
        let mut lines = Vec::new();
        let mut commented = false;
        for field in &record.fields {
            if env.library.type_(field.typ).maybe_ref_as::<library::Union>().is_some()
                    || field.bits.is_some() {
                warn!("Record `{}` field `{}` not expressible in Rust, truncated",
                      record.name, field.name);
                lines.push(format!("{}_truncated_record_marker: (),", tabs(1)));
                break;
            }
            let vis = if field.private { "" } else { "pub " };

            if let Some(ref c_type) = field.c_type {
                let name = mangle_keywords(&*field.name);
                let c_type = ffi_type(env, field.typ, c_type);
                lines.push(format!("{}{}{}: {},", tabs(1), vis, name, c_type.as_str()));
                if c_type.is_err() {
                    commented = true;
                }
            }
            else {
                let name = mangle_keywords(&*field.name);
                if let Some(ref func) =
                        env.library.type_(field.typ).maybe_ref_as::<library::Function>() {
                    let (com, sig) = functions::function_signature(env, func, true);
                    lines.push(format!("{}{}{}: fn{},", tabs(1), vis, name, sig));
                    commented |= com;
                }
                else {
                    lines.push(format!("{}{}{}: [{:?}],", tabs(1), vis, name, field.typ));
                    commented = true;
                }
            }
        }
        let comment = if commented { "//" } else { "" };
        if lines.is_empty() {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {};\n", comment, record.c_type));
        }
        else {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {} {{", comment, record.c_type));
            for line in lines {
                try!(writeln!(w, "{}{}", comment, line));
            }
            try!(writeln!(w, "{}}}\n", comment));
        }
    }
    Ok(())
}
<commit_msg>Fix enum consts starting with digits<commit_after>use std::collections::HashMap;
use std::fs;
use std::path::*;
use std::io::{Result, Write};
use case::CaseExt;

use env::Env;
use file_saver::*;
use library;
use nameutil::*;
use super::ffi_type::ffi_type;
use super::functions;
use super::statics;
use super::super::general::{self, tabs};
use traits::*;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  PathBuf::from(&env.config.target_path)
        .join(file_name_sys("lib"));

    let parent = path.parent().unwrap();
    //TODO: do only if not exists
    let _ = fs::create_dir(parent);

    println!("Generating file {:?}", path);
    save_to_file(&path, &mut |w| generate_lib(w, env));
}

fn generate_lib<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));
    try!(statics::begin(w));

    try!(generate_extern_crates(w, env));
    try!(statics::after_extern_crates(w));

    if env.config.library_name != "GLib" {
        try!(statics::use_glib_ffi(w));
    } else {
        try!(statics::only_for_glib(w));
    }
    if env.config.library_name == "Gtk" {
        try!(statics::only_for_gtk(w));
    }

    let ns = env.library.namespace(library::MAIN_NAMESPACE);
    let classes = prepare(ns);
    let interfaces = prepare(ns);

    try!(generate_aliases(w, env, &prepare(ns)));
    try!(generate_enums(w, &ns.name, &prepare(ns)));
    try!(generate_bitfields(w, &ns.name, &prepare(ns)));
    try!(generate_unions(w, &prepare(ns)));
    try!(functions::generate_callbacks(w, env, &prepare(ns)));
    try!(generate_records(w, env, &prepare(ns)));
    try!(generate_classes_structs(w, &classes));
    try!(generate_interfaces_structs(w, &interfaces));

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(functions::generate_classes_funcs(w, env, &classes));
    try!(functions::generate_interfaces_funcs(w, env, &interfaces));

    //TODO: other functions
    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn generate_extern_crates<W: Write>(w: &mut W, env: &Env) -> Result<()>{
    for library_name in &env.config.external_libraries {
        try!(writeln!(w, "extern crate {0}_sys as {0}_ffi;", crate_name(library_name)));
    }

    Ok(())
}

fn prepare<T: Ord>(ns: &library::Namespace) -> Vec<&T>
where library::Type: MaybeRef<T> {
    let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len());
    for typ in ns.types.iter().filter_map(|t| t.as_ref()) {
        if let Some(ref x) = typ.maybe_ref() {
            vec.push(x);
        }
    }
    vec.sort();
    vec
}

fn generate_aliases<W: Write>(w: &mut W, env: &Env, items: &[&library::Alias])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        let (comment, c_type) = match ffi_type(env, item.typ, &item.target_c_type) {
            Ok(x) => ("", x),
            Err(x) => ("//", x),
        };
        try!(writeln!(w, "{}pub type {} = {};", comment, item.c_identifier, c_type));
    }

    Ok(())
}

fn generate_bitfields<W: Write>(w: &mut W, ns_name: &str, items: &[&library::Bitfield])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        try!(writeln!(w, "bitflags! {{\n{}#[repr(C)]\n{0}flags {}: c_uint {{", tabs(1), item.name));
        for member in &item.members {
            let val: i64 = member.value.parse().unwrap();
            try!(writeln!(w, "{}const {} = {},",
                          tabs(2), strip_prefix(ns_name, &member.c_identifier), val as u32));
        }
        try!(writeln!(w, "{}}}\n}}", tabs(1)));
        try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_enums<W: Write>(w: &mut W, ns_name: &str, items: &[&library::Enumeration])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if item.members.len() == 1 {
            try!(writeln!(w, "pub type {} = c_int;", item.name));
            try!(writeln!(w, "pub const {}: {} = {};",
                          item.members[0].c_identifier, item.name, item.members[0].value));
            try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
            try!(writeln!(w, ""));
            continue;
        }

        let mut vals = HashMap::new();
        try!(writeln!(w, "#[derive(Clone, Copy, Debug, Eq, PartialEq)]\n#[repr(C)]"));
        try!(writeln!(w, "pub enum {} {{", item.name));
        for member in &item.members {
            if vals.get(&member.value).is_some() {
                continue;
            }
            try!(writeln!(w, "{}{} = {},",
                          tabs(1), &prepare_enum_member_name(&member.name), member.value));
            vals.insert(member.value.clone(), member.name.clone());
        }
        try!(writeln!(w, "}}"));
        for member in &item.members {
            try!(writeln!(w, "pub const {}: {} = {1}::{};",
                          prepare_enum_member_name(strip_prefix(ns_name, &member.c_identifier)),
                          item.name, &prepare_enum_member_name(vals.get(&member.value).unwrap())));
        }
        try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_unions<W: Write>(w: &mut W, items: &[&library::Union])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        try!(writeln!(w, "pub type {} = c_void;", item.name));
        if let Some(ref c_type) = item.c_type {
            try!(writeln!(w, "pub type {} = {};", c_type, item.name));
        }
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn prepare_enum_member_name(name: &str) -> String {
    let cameled = name.to_camel();
    if name.chars().next().unwrap().is_digit(10) {
        format!("_{}", cameled)
    } else {
        cameled
    }
}

fn generate_classes_structs<W: Write>(w: &mut W, classes: &[&library::Class]) -> Result<()> {
    try!(writeln!(w, ""));
    for klass in classes {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", klass.c_type));
    }

    Ok(())
}

fn generate_interfaces_structs<W: Write>(w: &mut W, interfaces: &[&library::Interface]) -> Result<()> {
    try!(writeln!(w, ""));
    for interface in interfaces {
        try!(writeln!(w, "#[repr(C)]\npub struct {};", interface.c_type));
    }

    Ok(())
}

fn generate_records<W: Write>(w: &mut W, env: &Env, records: &[&library::Record]) -> Result<()> {
    try!(writeln!(w, ""));
    for record in records {
        let mut lines = Vec::new();
        let mut commented = false;
        for field in &record.fields {
            if env.library.type_(field.typ).maybe_ref_as::<library::Union>().is_some()
                    || field.bits.is_some() {
                warn!("Record `{}` field `{}` not expressible in Rust, truncated",
                      record.name, field.name);
                lines.push(format!("{}_truncated_record_marker: (),", tabs(1)));
                break;
            }
            let vis = if field.private { "" } else { "pub " };

            if let Some(ref c_type) = field.c_type {
                let name = mangle_keywords(&*field.name);
                let c_type = ffi_type(env, field.typ, c_type);
                lines.push(format!("{}{}{}: {},", tabs(1), vis, name, c_type.as_str()));
                if c_type.is_err() {
                    commented = true;
                }
            }
            else {
                let name = mangle_keywords(&*field.name);
                if let Some(ref func) =
                        env.library.type_(field.typ).maybe_ref_as::<library::Function>() {
                    let (com, sig) = functions::function_signature(env, func, true);
                    lines.push(format!("{}{}{}: fn{},", tabs(1), vis, name, sig));
                    commented |= com;
                }
                else {
                    lines.push(format!("{}{}{}: [{:?}],", tabs(1), vis, name, field.typ));
                    commented = true;
                }
            }
        }
        let comment = if commented { "//" } else { "" };
        if lines.is_empty() {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {};\n", comment, record.c_type));
        }
        else {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {} {{", comment, record.c_type));
            for line in lines {
                try!(writeln!(w, "{}{}", comment, line));
            }
            try!(writeln!(w, "{}}}\n", comment));
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use alloc::arc::{Arc, Weak};
use collections::{BTreeMap, VecDeque};
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId};

use sync::WaitCondition;
use syscall::error::{Error, Result, EAGAIN, EBADF, EINVAL, EPIPE};
use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK, MODE_CHR};
use syscall::scheme::Scheme;
use syscall::data::Stat;

/// Pipes list
pub static PIPE_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;
static PIPE_NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
static PIPES: Once<RwLock<(BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)>> = Once::new();

/// Initialize pipes, called if needed
fn init_pipes() -> RwLock<(BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)> {
    RwLock::new((BTreeMap::new(), BTreeMap::new()))
}

/// Get the global pipes list, const
fn pipes() -> RwLockReadGuard<'static, (BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)> {
    PIPES.call_once(init_pipes).read()
}

/// Get the global schemes list, mutable
fn pipes_mut() -> RwLockWriteGuard<'static, (BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)> {
    PIPES.call_once(init_pipes).write()
}

pub fn pipe(flags: usize) -> (usize, usize) {
    let mut pipes = pipes_mut();
    let read_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
    let write_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
    let read = PipeRead::new(flags);
    let write = PipeWrite::new(flags, &read);
    pipes.0.insert(read_id, Arc::new(read));
    pipes.1.insert(write_id, Arc::new(write));
    (read_id, write_id)
}

pub struct PipeScheme;

impl PipeScheme {
    pub fn new(scheme_id: SchemeId) -> PipeScheme {
        PIPE_SCHEME_ID.store(scheme_id, Ordering::SeqCst);
        PipeScheme
    }
}

impl Scheme for PipeScheme {
    fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
        let mut pipes = pipes_mut();

        let read_option = if let Some(pipe) = pipes.0.get(&id) {
            Some(pipe.dup()?)
        } else {
            None
        };
        if let Some(pipe) = read_option {
            let pipe_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
            pipes.0.insert(pipe_id, Arc::new(pipe));
            return Ok(pipe_id);
        }

        let write_option = if let Some(pipe) = pipes.1.get(&id) {
            Some(pipe.dup()?)
        } else {
            None
        };
        if let Some(pipe) = write_option {
            let pipe_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
            pipes.1.insert(pipe_id, Arc::new(pipe));
            return Ok(pipe_id);
        }

        Err(Error::new(EBADF))
    }

    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        // Clone to prevent deadlocks
        let pipe = {
            let pipes = pipes();
            pipes.0.get(&id).map(|pipe| pipe.clone()).ok_or(Error::new(EBADF))?
        };

        pipe.read(buf)
    }

    fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
        // Clone to prevent deadlocks
        let pipe = {
            let pipes = pipes();
            pipes.1.get(&id).map(|pipe| pipe.clone()).ok_or(Error::new(EBADF))?
        };

        pipe.write(buf)
    }

    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
        let pipes = pipes();

        if let Some(pipe) = pipes.0.get(&id) {
            return pipe.fcntl(cmd, arg);
        }

        if let Some(pipe) = pipes.1.get(&id) {
            return pipe.fcntl(cmd, arg);
        }

        Err(Error::new(EBADF))
    }

    fn fpath(&self, _id: usize, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        let scheme_path = b"pipe:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }
        Ok(i)
    }

    fn fstat(&self, _id: usize, stat: &mut Stat) -> Result<usize> {
        *stat = Stat {
            st_mode: MODE_CHR | 0o666,
            ..Default::default()
        };

        Ok(0)
    }

    fn fsync(&self, _id: usize) -> Result<usize> {
        Ok(0)
    }

    fn close(&self, id: usize) -> Result<usize> {
        let mut pipes = pipes_mut();

        drop(pipes.0.remove(&id));
        drop(pipes.1.remove(&id));

        Ok(0)
    }
}

/// Read side of a pipe
pub struct PipeRead {
    flags: AtomicUsize,
    condition: Arc<WaitCondition>,
    vec: Arc<Mutex<VecDeque<u8>>>
}

impl PipeRead {
    pub fn new(flags: usize) -> Self {
        PipeRead {
            flags: AtomicUsize::new(flags),
            condition: Arc::new(WaitCondition::new()),
            vec: Arc::new(Mutex::new(VecDeque::new())),
        }
    }

    fn dup(&self) -> Result<Self> {
        Ok(PipeRead {
            flags: AtomicUsize::new(self.flags.load(Ordering::SeqCst)),
            condition: self.condition.clone(),
            vec: self.vec.clone()
        })
    }

    fn fcntl(&self, cmd: usize, arg: usize) -> Result<usize> {
        match cmd {
            F_GETFL => Ok(self.flags.load(Ordering::SeqCst)),
            F_SETFL => {
                self.flags.store(arg & ! O_ACCMODE, Ordering::SeqCst);
                Ok(0)
            },
            _ => Err(Error::new(EINVAL))
        }
    }

    fn read(&self, buf: &mut [u8]) -> Result<usize> {
        loop {
            {
                let mut vec = self.vec.lock();

                let mut i = 0;
                while i < buf.len() {
                    if let Some(b) = vec.pop_front() {
                        buf[i] = b;
                        i += 1;
                    } else {
                        break;
                    }
                }

                if i > 0 {
                    return Ok(i);
                }
            }

            if Arc::weak_count(&self.vec) == 0 {
                return Ok(0);
            } else if self.flags.load(Ordering::SeqCst) & O_NONBLOCK == O_NONBLOCK {
                return Err(Error::new(EAGAIN));
            } else {
                self.condition.wait();
            }
        }
    }
}

/// Read side of a pipe
pub struct PipeWrite {
    flags: AtomicUsize,
    condition: Arc<WaitCondition>,
    vec: Option<Weak<Mutex<VecDeque<u8>>>>
}

impl PipeWrite {
    pub fn new(flags: usize, read: &PipeRead) -> Self {
        PipeWrite {
            flags: AtomicUsize::new(flags),
            condition: read.condition.clone(),
            vec: Some(Arc::downgrade(&read.vec)),
        }
    }

    fn dup(&self) -> Result<Self> {
        Ok(PipeWrite {
            flags: AtomicUsize::new(self.flags.load(Ordering::SeqCst)),
            condition: self.condition.clone(),
            vec: self.vec.clone()
        })
    }

    fn fcntl(&self, cmd: usize, arg: usize) -> Result<usize> {
        match cmd {
            F_GETFL => Ok(self.flags.load(Ordering::SeqCst)),
            F_SETFL => {
                self.flags.store(arg & ! O_ACCMODE, Ordering::SeqCst);
                Ok(0)
            },
            _ => Err(Error::new(EINVAL))
        }
    }

    fn write(&self, buf: &[u8]) -> Result<usize> {
        if let Some(ref vec_weak) = self.vec {
            if let Some(vec_lock) = vec_weak.upgrade() {
                let mut vec = vec_lock.lock();

                for &b in buf.iter() {
                    vec.push_back(b);
                }

                self.condition.notify();

                Ok(buf.len())
            } else {
                Err(Error::new(EPIPE))
            }
        } else {
            panic!("PipeWrite dropped before write");
        }
    }
}

impl Drop for PipeWrite {
    fn drop(&mut self) {
        drop(self.vec.take());
        self.condition.notify();
    }
}
<commit_msg>Make seek on pipe return ESPIPE<commit_after>use alloc::arc::{Arc, Weak};
use collections::{BTreeMap, VecDeque};
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId};

use sync::WaitCondition;
use syscall::error::{Error, Result, EAGAIN, EBADF, EINVAL, EPIPE, ESPIPE};
use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK, MODE_CHR};
use syscall::scheme::Scheme;
use syscall::data::Stat;

/// Pipes list
pub static PIPE_SCHEME_ID: AtomicSchemeId = ATOMIC_SCHEMEID_INIT;
static PIPE_NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
static PIPES: Once<RwLock<(BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)>> = Once::new();

/// Initialize pipes, called if needed
fn init_pipes() -> RwLock<(BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)> {
    RwLock::new((BTreeMap::new(), BTreeMap::new()))
}

/// Get the global pipes list, const
fn pipes() -> RwLockReadGuard<'static, (BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)> {
    PIPES.call_once(init_pipes).read()
}

/// Get the global schemes list, mutable
fn pipes_mut() -> RwLockWriteGuard<'static, (BTreeMap<usize, Arc<PipeRead>>, BTreeMap<usize, Arc<PipeWrite>>)> {
    PIPES.call_once(init_pipes).write()
}

pub fn pipe(flags: usize) -> (usize, usize) {
    let mut pipes = pipes_mut();
    let read_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
    let write_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
    let read = PipeRead::new(flags);
    let write = PipeWrite::new(flags, &read);
    pipes.0.insert(read_id, Arc::new(read));
    pipes.1.insert(write_id, Arc::new(write));
    (read_id, write_id)
}

pub struct PipeScheme;

impl PipeScheme {
    pub fn new(scheme_id: SchemeId) -> PipeScheme {
        PIPE_SCHEME_ID.store(scheme_id, Ordering::SeqCst);
        PipeScheme
    }
}

impl Scheme for PipeScheme {
    fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> {
        let mut pipes = pipes_mut();

        let read_option = if let Some(pipe) = pipes.0.get(&id) {
            Some(pipe.dup()?)
        } else {
            None
        };
        if let Some(pipe) = read_option {
            let pipe_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
            pipes.0.insert(pipe_id, Arc::new(pipe));
            return Ok(pipe_id);
        }

        let write_option = if let Some(pipe) = pipes.1.get(&id) {
            Some(pipe.dup()?)
        } else {
            None
        };
        if let Some(pipe) = write_option {
            let pipe_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
            pipes.1.insert(pipe_id, Arc::new(pipe));
            return Ok(pipe_id);
        }

        Err(Error::new(EBADF))
    }

    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        // Clone to prevent deadlocks
        let pipe = {
            let pipes = pipes();
            pipes.0.get(&id).map(|pipe| pipe.clone()).ok_or(Error::new(EBADF))?
        };

        pipe.read(buf)
    }

    fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
        // Clone to prevent deadlocks
        let pipe = {
            let pipes = pipes();
            pipes.1.get(&id).map(|pipe| pipe.clone()).ok_or(Error::new(EBADF))?
        };

        pipe.write(buf)
    }

    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
        let pipes = pipes();

        if let Some(pipe) = pipes.0.get(&id) {
            return pipe.fcntl(cmd, arg);
        }

        if let Some(pipe) = pipes.1.get(&id) {
            return pipe.fcntl(cmd, arg);
        }

        Err(Error::new(EBADF))
    }

    fn fpath(&self, _id: usize, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        let scheme_path = b"pipe:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }
        Ok(i)
    }

    fn fstat(&self, _id: usize, stat: &mut Stat) -> Result<usize> {
        *stat = Stat {
            st_mode: MODE_CHR | 0o666,
            ..Default::default()
        };

        Ok(0)
    }

    fn fsync(&self, _id: usize) -> Result<usize> {
        Ok(0)
    }

    fn close(&self, id: usize) -> Result<usize> {
        let mut pipes = pipes_mut();

        drop(pipes.0.remove(&id));
        drop(pipes.1.remove(&id));

        Ok(0)
    }

    fn seek(&self, _id: usize, _pos: usize, _whence: usize) -> Result<usize> {
        Err(Error::new(ESPIPE))
    }
}

/// Read side of a pipe
pub struct PipeRead {
    flags: AtomicUsize,
    condition: Arc<WaitCondition>,
    vec: Arc<Mutex<VecDeque<u8>>>
}

impl PipeRead {
    pub fn new(flags: usize) -> Self {
        PipeRead {
            flags: AtomicUsize::new(flags),
            condition: Arc::new(WaitCondition::new()),
            vec: Arc::new(Mutex::new(VecDeque::new())),
        }
    }

    fn dup(&self) -> Result<Self> {
        Ok(PipeRead {
            flags: AtomicUsize::new(self.flags.load(Ordering::SeqCst)),
            condition: self.condition.clone(),
            vec: self.vec.clone()
        })
    }

    fn fcntl(&self, cmd: usize, arg: usize) -> Result<usize> {
        match cmd {
            F_GETFL => Ok(self.flags.load(Ordering::SeqCst)),
            F_SETFL => {
                self.flags.store(arg & ! O_ACCMODE, Ordering::SeqCst);
                Ok(0)
            },
            _ => Err(Error::new(EINVAL))
        }
    }

    fn read(&self, buf: &mut [u8]) -> Result<usize> {
        loop {
            {
                let mut vec = self.vec.lock();

                let mut i = 0;
                while i < buf.len() {
                    if let Some(b) = vec.pop_front() {
                        buf[i] = b;
                        i += 1;
                    } else {
                        break;
                    }
                }

                if i > 0 {
                    return Ok(i);
                }
            }

            if Arc::weak_count(&self.vec) == 0 {
                return Ok(0);
            } else if self.flags.load(Ordering::SeqCst) & O_NONBLOCK == O_NONBLOCK {
                return Err(Error::new(EAGAIN));
            } else {
                self.condition.wait();
            }
        }
    }
}

/// Read side of a pipe
pub struct PipeWrite {
    flags: AtomicUsize,
    condition: Arc<WaitCondition>,
    vec: Option<Weak<Mutex<VecDeque<u8>>>>
}

impl PipeWrite {
    pub fn new(flags: usize, read: &PipeRead) -> Self {
        PipeWrite {
            flags: AtomicUsize::new(flags),
            condition: read.condition.clone(),
            vec: Some(Arc::downgrade(&read.vec)),
        }
    }

    fn dup(&self) -> Result<Self> {
        Ok(PipeWrite {
            flags: AtomicUsize::new(self.flags.load(Ordering::SeqCst)),
            condition: self.condition.clone(),
            vec: self.vec.clone()
        })
    }

    fn fcntl(&self, cmd: usize, arg: usize) -> Result<usize> {
        match cmd {
            F_GETFL => Ok(self.flags.load(Ordering::SeqCst)),
            F_SETFL => {
                self.flags.store(arg & ! O_ACCMODE, Ordering::SeqCst);
                Ok(0)
            },
            _ => Err(Error::new(EINVAL))
        }
    }

    fn write(&self, buf: &[u8]) -> Result<usize> {
        if let Some(ref vec_weak) = self.vec {
            if let Some(vec_lock) = vec_weak.upgrade() {
                let mut vec = vec_lock.lock();

                for &b in buf.iter() {
                    vec.push_back(b);
                }

                self.condition.notify();

                Ok(buf.len())
            } else {
                Err(Error::new(EPIPE))
            }
        } else {
            panic!("PipeWrite dropped before write");
        }
    }
}

impl Drop for PipeWrite {
    fn drop(&mut self) {
        drop(self.vec.take());
        self.condition.notify();
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::char;
use std::vec::Vec;

use super::*;

#[derive(Debug, Default, PartialEq, Clone)]
pub struct Color {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
}

#[derive(Debug, Default, PartialEq, Clone)]
pub struct ScreenCellAttr {
    pub bold:       bool,
    pub underline:  u8, // 0 to 3
    pub italic:     bool,
    pub blink:      bool,
    pub reverse:    bool,
    pub strike:     bool,
    pub font:       u8, // 0 to 9
    pub dwl:        bool, // On a DECDWL or DECDHL line
    pub dhl:        u8, // On a DECDHL line (1=top 2=bottom)
}

#[derive(Debug, PartialEq)]
pub struct ScreenCell {
    /// Where the cell is located
    pub pos: Pos,
    /// The characters in the cell. I believe there are more than one to support overstrike.
    pub chars: Vec<char>,
    /// I think this is How wide the cell is in columns.
    pub width: u8,
    pub attrs: ScreenCellAttr,
    /// foreground color
    pub fg: Color,
    /// background color
    pub bg: Color,
}

impl ScreenCell {
    // Copies data from the given pointer. Doesn't free the pointer or anything.
    pub fn from_ptr(ptr: *const ffi::VTermScreenCell, pos: Pos) -> ScreenCell {
        let fg = unsafe { ffi::vterm_cell_get_fg(ptr) };
        let bg = unsafe { ffi::vterm_cell_get_bg(ptr) };

        let mut buf = [0 as libc::uint32_t; ffi::VTERM_MAX_CHARS_PER_CELL];
        let chars_count = unsafe { ffi::vterm_cell_get_chars(ptr, buf.as_mut_ptr(), ffi::VTERM_MAX_CHARS_PER_CELL as u64) };

        let mut chars: Vec<char> = Vec::with_capacity(ffi::VTERM_MAX_CHARS_PER_CELL);

        for i in 0..(chars_count as usize) {
            let ch = match char::from_u32(buf[i]) {
                Some(ch) => ch,
                None => '\u{2764}',
            };

            chars.push(ch);
        }

        unsafe {
            ScreenCell {
                pos:   pos,
                chars: chars,
                width: ffi::vterm_cell_get_width(ptr) as u8,
                attrs: ScreenCellAttr {
                    bold:       int_to_bool(ffi::vterm_cell_get_bold(ptr) as i32),
                    underline:  ffi::vterm_cell_get_underline(ptr) as u8,
                    italic:     int_to_bool(ffi::vterm_cell_get_italic(ptr) as i32),
                    blink:      int_to_bool(ffi::vterm_cell_get_blink(ptr) as i32),
                    reverse:    int_to_bool(ffi::vterm_cell_get_reverse(ptr) as i32),
                    strike:     int_to_bool(ffi::vterm_cell_get_strike(ptr) as i32),
                    font:       ffi::vterm_cell_get_font(ptr) as u8,
                    dwl:        int_to_bool(ffi::vterm_cell_get_dwl(ptr) as i32),
                    dhl:        ffi::vterm_cell_get_dhl(ptr) as u8,
                },
                fg: Color {
                    red:    fg.red,
                    green:  fg.green,
                    blue:   fg.blue,
                },
                bg: Color {
                    red:    bg.red,
                    green:  bg.green,
                    blue:   bg.blue,
                }
            }
        }
    }

    pub fn chars_as_utf8_bytes(&self) -> Vec<u8> {
        const MAX_BYTES_PER_UTF8_CHAR: usize = 6; // wikipedia says so
        let mut output: Vec<u8> = Vec::with_capacity(ffi::VTERM_MAX_CHARS_PER_CELL * MAX_BYTES_PER_UTF8_CHAR);

        for ch in &self.chars {
            let mut bytes = [0 as u8; MAX_BYTES_PER_UTF8_CHAR];
            match ch.encode_utf8(&mut bytes) {
                Some(size) => {
                    for byte in &bytes[0..size] {
                        output.push(*byte);
                    }
                },
                None => panic!("char couldn't be encoded as utf8: {:?}", ch),
            }
        }

        output
    }
}

impl Default for ScreenCell {
    fn default() -> ScreenCell {
        ScreenCell {
            pos: Default::default(),
            chars: vec!(),
            width: 1,
            attrs: Default::default(),
            fg: Color { red: 230, green: 230, blue: 230 },
            bg: Color { red: 5, green: 5, blue: 5 },
        }
    }
}

mod tests {
    use super::super::*;
}
<commit_msg>Allow screencells to be cloned<commit_after>extern crate libc;

use std::char;
use std::vec::Vec;

use super::*;

#[derive(Debug, Default, PartialEq, Clone)]
pub struct Color {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
}

#[derive(Debug, Default, PartialEq, Clone)]
pub struct ScreenCellAttr {
    pub bold:       bool,
    pub underline:  u8, // 0 to 3
    pub italic:     bool,
    pub blink:      bool,
    pub reverse:    bool,
    pub strike:     bool,
    pub font:       u8, // 0 to 9
    pub dwl:        bool, // On a DECDWL or DECDHL line
    pub dhl:        u8, // On a DECDHL line (1=top 2=bottom)
}

#[derive(Debug, PartialEq, Clone)]
pub struct ScreenCell {
    /// Where the cell is located
    pub pos: Pos,
    /// The characters in the cell. I believe there are more than one to support overstrike.
    pub chars: Vec<char>,
    /// I think this is How wide the cell is in columns.
    pub width: u8,
    pub attrs: ScreenCellAttr,
    /// foreground color
    pub fg: Color,
    /// background color
    pub bg: Color,
}

impl ScreenCell {
    // Copies data from the given pointer. Doesn't free the pointer or anything.
    pub fn from_ptr(ptr: *const ffi::VTermScreenCell, pos: Pos) -> ScreenCell {
        let fg = unsafe { ffi::vterm_cell_get_fg(ptr) };
        let bg = unsafe { ffi::vterm_cell_get_bg(ptr) };

        let mut buf = [0 as libc::uint32_t; ffi::VTERM_MAX_CHARS_PER_CELL];
        let chars_count = unsafe { ffi::vterm_cell_get_chars(ptr, buf.as_mut_ptr(), ffi::VTERM_MAX_CHARS_PER_CELL as u64) };

        let mut chars: Vec<char> = Vec::with_capacity(ffi::VTERM_MAX_CHARS_PER_CELL);

        for i in 0..(chars_count as usize) {
            let ch = match char::from_u32(buf[i]) {
                Some(ch) => ch,
                None => '\u{2764}',
            };

            chars.push(ch);
        }

        unsafe {
            ScreenCell {
                pos:   pos,
                chars: chars,
                width: ffi::vterm_cell_get_width(ptr) as u8,
                attrs: ScreenCellAttr {
                    bold:       int_to_bool(ffi::vterm_cell_get_bold(ptr) as i32),
                    underline:  ffi::vterm_cell_get_underline(ptr) as u8,
                    italic:     int_to_bool(ffi::vterm_cell_get_italic(ptr) as i32),
                    blink:      int_to_bool(ffi::vterm_cell_get_blink(ptr) as i32),
                    reverse:    int_to_bool(ffi::vterm_cell_get_reverse(ptr) as i32),
                    strike:     int_to_bool(ffi::vterm_cell_get_strike(ptr) as i32),
                    font:       ffi::vterm_cell_get_font(ptr) as u8,
                    dwl:        int_to_bool(ffi::vterm_cell_get_dwl(ptr) as i32),
                    dhl:        ffi::vterm_cell_get_dhl(ptr) as u8,
                },
                fg: Color {
                    red:    fg.red,
                    green:  fg.green,
                    blue:   fg.blue,
                },
                bg: Color {
                    red:    bg.red,
                    green:  bg.green,
                    blue:   bg.blue,
                }
            }
        }
    }

    pub fn chars_as_utf8_bytes(&self) -> Vec<u8> {
        const MAX_BYTES_PER_UTF8_CHAR: usize = 6; // wikipedia says so
        let mut output: Vec<u8> = Vec::with_capacity(ffi::VTERM_MAX_CHARS_PER_CELL * MAX_BYTES_PER_UTF8_CHAR);

        for ch in &self.chars {
            let mut bytes = [0 as u8; MAX_BYTES_PER_UTF8_CHAR];
            match ch.encode_utf8(&mut bytes) {
                Some(size) => {
                    for byte in &bytes[0..size] {
                        output.push(*byte);
                    }
                },
                None => panic!("char couldn't be encoded as utf8: {:?}", ch),
            }
        }

        output
    }
}

impl Default for ScreenCell {
    fn default() -> ScreenCell {
        ScreenCell {
            pos: Default::default(),
            chars: vec!(),
            width: 1,
            attrs: Default::default(),
            fg: Color { red: 230, green: 230, blue: 230 },
            bg: Color { red: 5, green: 5, blue: 5 },
        }
    }
}

mod tests {
    use super::super::*;
}
<|endoftext|>