<commit_before>//! Tab-delimited flat file helpers

use std::io::Read;
use csv::Reader;

error_chain! {
  foreign_links {
    ParseFile(::csv::Error);
  }

  errors {
    InvalidHeaderSize

    ParseString(what: String, message: String) {
      description("parse string error")
      display("parse string error: {} : {}", what, message)
    }
  }
}

pub trait FromTdff<R: Read> : Sized {
  fn from_tdff(source: R) -> Result<Self>;
}

pub struct TdffScanner<R: Read> {
  headers: Vec<String>,
  reader: Reader<R>,
}

impl<R: Read> TdffScanner<R> {
  pub fn new(source: R) -> Result<TdffScanner<R>> {
    let mut reader = Reader::from_reader(source).delimiter(b'\t');
    Ok(TdffScanner {
      headers: reader.headers()?,
      reader: reader,
    })
  }
}

pub type TdffRow<'a> = Vec<(&'a str, String)>;

impl<R: Read> TdffScanner<R> {
  pub fn for_each_row<'a, F>(&'a mut self, mut f: F) -> Result<()> where F: FnMut(usize, TdffRow<'a>) -> Result<()> + 'a {
    let size = self.headers.len();
    for (row_i, row) in self.reader.records().enumerate() {
      let mut row_container = Vec::with_capacity(size);
      for (i, value) in row?.into_iter().enumerate() {
        match self.headers.get(i) {
          Some(key) => {
            row_container.push((key.as_ref() as &str, value));
          },
          None => {}
        }
      }
      f(row_i, row_container)?;
    }
    Ok(())
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use std::io::Cursor;

  #[test]
  fn test_tdff() {
    let source = Cursor::new(r#"settlement-id	settlement-start-date	settlement-end-date	deposit-date	total-amount	currency	transaction-type	order-id	merchant-order-id	adjustment-id	shipment-id	marketplace-name	shipment-fee-type	shipment-fee-amount	order-fee-type	order-fee-amount	fulfillment-id	posted-date	order-item-code	merchant-order-item-id	merchant-adjustment-item-id	sku	quantity-purchased	price-type	price-amount	item-related-fee-type	item-related-fee-amount	misc-fee-amount	other-fee-amount	other-fee-reason-description	promotion-id	promotion-type	promotion-amount	direct-payment-type	direct-payment-amount	other-amount
6016502941	2015-12-02T03:27:08+00:00	2015-12-16T03:27:08+00:00	2015-12-18T03:27:08+00:00	16630.13	USD
6016502941						Order	112-8095165-5463447	112-8095165-5463447		D1FyNyr6b	Amazon.com					AFN	2015-12-02T04:15:26+00:00	62538071274626			edifier-p270-gold	1
6016502941						Order	112-8095165-5463447	112-8095165-5463447		D1FyNyr6b	Amazon.com					AFN	2015-12-02T04:15:26+00:00	62538071274626			edifier-p270-gold		Principal	27.99
6016502941						Order	112-8095165-5463447	112-8095165-5463447		D1FyNyr6b	Amazon.com					AFN	2015-12-02T04:15:26+00:00	62538071274626			edifier-p270-gold				FBAPerOrderFulfillmentFee	-1.00
"#);
    let mut scanner = TdffScanner::new(source).expect("new scanner");
    let mut rows = vec![];
    scanner.for_each_row(|_, row| {
      rows.push(row.into_iter().map(|(k, v)| (k.to_string(), v.clone())).collect::<Vec<_>>());
      Ok(())
    }).expect("for_each_row");
    assert_eq!(rows.len(), 4);
    assert_eq!(rows[0][0], ("settlement-id".to_string(), "6016502941".to_string()));
    assert_eq!(rows[1][6], ("transaction-type".to_string(), "Order".to_string()));
    assert_eq!(rows[3].iter().find(|t| t.0 == "sku").expect("sku column").1, "edifier-p270-gold".to_string());
  }
}<commit_msg>trait FromTdffField<commit_after>//! Tab-delimited flat file helpers

use std::io::Read;
use csv::Reader;

error_chain! {
  foreign_links {
    ParseFile(::csv::Error);
  }

  errors {
    InvalidHeaderSize

    ParseString(what: String, message: String) {
      description("parse string error")
      display("parse string error: {} : {}", what, message)
    }
  }
}

pub trait FromTdff<R: Read> : Sized {
  fn from_tdff(source: R) -> Result<Self>;
}

pub struct TdffScanner<R: Read> {
  headers: Vec<String>,
  reader: Reader<R>,
}

impl<R: Read> TdffScanner<R> {
  pub fn new(source: R) -> Result<TdffScanner<R>> {
    let mut reader = Reader::from_reader(source).delimiter(b'\t');
    Ok(TdffScanner {
      headers: reader.headers()?,
      reader: reader,
    })
  }
}

pub type TdffRow<'a> = Vec<(&'a str, String)>;

impl<R: Read> TdffScanner<R> {
  pub fn for_each_row<'a, F>(&'a mut self, mut f: F) -> Result<()> where F: FnMut(usize, TdffRow<'a>) -> Result<()> + 'a {
    let size = self.headers.len();
    for (row_i, row) in self.reader.records().enumerate() {
      let mut row_container = Vec::with_capacity(size);
      for (i, value) in row?.into_iter().enumerate() {
        match self.headers.get(i) {
          Some(key) => {
            row_container.push((key.as_ref() as &str, value));
          },
          None => {}
        }
      }
      f(row_i, row_container)?;
    }
    Ok(())
  }
}

pub trait FromTdffField: Sized {
  fn parse_tdff_field(key:&str, v: &str) -> Result<Self>;
}

impl<T, Err> FromTdffField for T
  where T: ::std::str::FromStr<Err = Err>,
        Err: ::std::error::Error
{
  fn parse_tdff_field(key:&str, v: &str) -> Result<Self> {
    let trimmed = v.trim();
    if !trimmed.is_empty() {
      trimmed.parse()
        .map_err(|err| -> Error {
          ErrorKind::ParseString(key.to_string(), format!("{}: '{}'", err, v)).into()
        })
    } else {
      Err(ErrorKind::ParseString(key.to_string(), "value is empty".to_string()).into())
    }
  }
}

#[cfg(test)]
mod test {
  use super::*;
  use std::io::Cursor;

  #[test]
  fn test_tdff() {
    let source = Cursor::new(r#"settlement-id	settlement-start-date	settlement-end-date	deposit-date	total-amount	currency	transaction-type	order-id	merchant-order-id	adjustment-id	shipment-id	marketplace-name	shipment-fee-type	shipment-fee-amount	order-fee-type	order-fee-amount	fulfillment-id	posted-date	order-item-code	merchant-order-item-id	merchant-adjustment-item-id	sku	quantity-purchased	price-type	price-amount	item-related-fee-type	item-related-fee-amount	misc-fee-amount	other-fee-amount	other-fee-reason-description	promotion-id	promotion-type	promotion-amount	direct-payment-type	direct-payment-amount	other-amount
6016502941	2015-12-02T03:27:08+00:00	2015-12-16T03:27:08+00:00	2015-12-18T03:27:08+00:00	16630.13	USD
6016502941						Order	112-8095165-5463447	112-8095165-5463447		D1FyNyr6b	Amazon.com					AFN	2015-12-02T04:15:26+00:00	62538071274626			edifier-p270-gold	1
6016502941						Order	112-8095165-5463447	112-8095165-5463447		D1FyNyr6b	Amazon.com					AFN	2015-12-02T04:15:26+00:00	62538071274626			edifier-p270-gold		Principal	27.99
6016502941						Order	112-8095165-5463447	112-8095165-5463447		D1FyNyr6b	Amazon.com					AFN	2015-12-02T04:15:26+00:00	62538071274626			edifier-p270-gold				FBAPerOrderFulfillmentFee	-1.00
"#);
    let mut scanner = TdffScanner::new(source).expect("new scanner");
    let mut rows = vec![];
    scanner.for_each_row(|_, row| {
      rows.push(row.into_iter().map(|(k, v)| (k.to_string(), v.clone())).collect::<Vec<_>>());
      Ok(())
    }).expect("for_each_row");
    assert_eq!(rows.len(), 4);
    assert_eq!(rows[0][0], ("settlement-id".to_string(), "6016502941".to_string()));
    assert_eq!(rows[1][6], ("transaction-type".to_string(), "Order".to_string()));
    assert_eq!(rows[3].iter().find(|t| t.0 == "sku").expect("sku column").1, "edifier-p270-gold".to_string());
  }
}<|endoftext|>


<commit_before>use std::collections::HashSet;

use executor::Variables;
use schema::model::RootNode;
use tests::model::Database;
use types::scalars::EmptyMutation;
use value::Value;

#[test]
fn test_query_type_name() {
    let doc = r#"
        query IntrospectionQueryTypeQuery {
          __schema {
            queryType {
              name
            }
          }
        }"#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            Value::object(
                vec![(
                    "__schema",
                    Value::object(
                        vec![(
                            "queryType",
                            Value::object(
                                vec![("name", Value::scalar("Query"))].into_iter().collect(),
                            ),
                        )]
                        .into_iter()
                        .collect(),
                    ),
                )]
                .into_iter()
                .collect()
            ),
            vec![]
        ))
    );
}

#[test]
fn test_specific_type_name() {
    let doc = r#"
        query IntrospectionQueryTypeQuery {
          __type(name: "Droid") {
            name
          }
        }"#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            Value::object(
                vec![(
                    "__type",
                    Value::object(vec![("name", Value::scalar("Droid"))].into_iter().collect()),
                )]
                .into_iter()
                .collect()
            ),
            vec![]
        ))
    );
}

#[test]
fn test_specific_object_type_name_and_kind() {
    let doc = r#"
        query IntrospectionDroidKindQuery {
          __type(name: "Droid") {
            name
            kind
          }
        }
        "#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            Value::object(
                vec![(
                    "__type",
                    Value::object(
                        vec![
                            ("name", Value::scalar("Droid")),
                            ("kind", Value::scalar("OBJECT")),
                        ]
                        .into_iter()
                        .collect(),
                    ),
                )]
                .into_iter()
                .collect()
            ),
            vec![]
        ))
    );
}

#[test]
fn test_specific_interface_type_name_and_kind() {
    let doc = r#"
        query IntrospectionDroidKindQuery {
          __type(name: "Character") {
            name
            kind
          }
        }
        "#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            Value::object(
                vec![(
                    "__type",
                    Value::object(
                        vec![
                            ("name", Value::scalar("Character")),
                            ("kind", Value::scalar("INTERFACE")),
                        ]
                        .into_iter()
                        .collect(),
                    ),
                )]
                .into_iter()
                .collect()
            ),
            vec![]
        ))
    );
}

#[test]
fn test_documentation() {
    let doc = r#"
        query IntrospectionDroidDescriptionQuery {
          __type(name: "Droid") {
            name
            description
          }
        }
        "#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            Value::object(
                vec![(
                    "__type",
                    Value::object(
                        vec![
                            ("name", Value::scalar("Droid")),
                            (
                                "description",
                                Value::scalar("A mechanical creature in the Star Wars universe."),
                            ),
                        ]
                        .into_iter()
                        .collect(),
                    ),
                )]
                .into_iter()
                .collect()
            ),
            vec![]
        ))
    );
}

#[test]
fn test_possible_types() {
    let doc = r#"
        query IntrospectionDroidDescriptionQuery {
          __type(name: "Character") {
            possibleTypes {
              name
            }
          }
        }
        "#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    let result = ::execute(doc, None, &schema, &Variables::new(), &database);

    println!("Result: {:#?}", result);

    let (result, errors) = result.ok().expect("Query returned error");

    assert_eq!(errors, vec![]);

    let possible_types = result
        .as_object_value()
        .expect("execution result not an object")
        .get_field_value("__type")
        .expect("'__type' not present in result")
        .as_object_value()
        .expect("'__type' not an object")
        .get_field_value("possibleTypes")
        .expect("'possibleTypes' not present in '__type'")
        .as_list_value()
        .expect("'possibleTypes' not a list")
        .iter()
        .map(|t| {
            t.as_object_value()
                .expect("possible type not an object")
                .get_field_value("name")
                .expect("'name' not present in type")
                .as_scalar_value::<String>()
                .expect("'name' not a string") as &str
        })
        .collect::<HashSet<_>>();

    assert_eq!(possible_types, vec!["Human", "Droid"].into_iter().collect());
}
<commit_msg>Clean up introspection tests<commit_after>use std::collections::HashSet;

use executor::Variables;
use schema::model::RootNode;
use tests::model::Database;
use types::scalars::EmptyMutation;
use value::Value;

#[test]
fn test_introspection_query_type_name() {
    let doc = r#"
        query IntrospectionQueryTypeQuery {
          __schema {
            queryType {
              name
            }
          }
        }"#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            graphql_value!({
                "__schema": {
                    "queryType": {
                        "name": "Query"
                    }
                }

            }),
            vec![]
        ))
    );
}

#[test]
fn test_introspection_type_name() {
    let doc = r#"
        query IntrospectionQueryTypeQuery {
          __type(name: "Droid") {
            name
          }
        }"#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            graphql_value!({
                "__type": {
                    "name": "Droid",
                },
            }),
            vec![]
        ))
    );
}

#[test]
fn test_introspection_specific_object_type_name_and_kind() {
    let doc = r#"
        query IntrospectionDroidKindQuery {
          __type(name: "Droid") {
            name
            kind
          }
        }
        "#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            graphql_value!({
                "__type": {
                    "name": "Droid",
                    "kind": "OBJECT",
                }
            }),
            vec![],
        ))
    );
}

#[test]
fn test_introspection_specific_interface_type_name_and_kind() {
    let doc = r#"
        query IntrospectionDroidKindQuery {
          __type(name: "Character") {
            name
            kind
          }
        }
        "#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            graphql_value!({
                "__type": {
                    "name": "Character",
                    "kind": "INTERFACE",
                }
            }),
            vec![]
        ))
    );
}

#[test]
fn test_introspection_documentation() {
    let doc = r#"
        query IntrospectionDroidDescriptionQuery {
          __type(name: "Droid") {
            name
            description
          }
        }
        "#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    assert_eq!(
        ::execute(doc, None, &schema, &Variables::new(), &database),
        Ok((
            graphql_value!({
                "__type": {
                    "name": "Droid",
                    "description": "A mechanical creature in the Star Wars universe.",
                },
            }),
            vec![]
        ))
    );
}

#[test]
fn test_introspection_possible_types() {
    let doc = r#"
        query IntrospectionDroidDescriptionQuery {
          __type(name: "Character") {
            possibleTypes {
              name
            }
          }
        }
        "#;
    let database = Database::new();
    let schema = RootNode::new(&database, EmptyMutation::<Database>::new());

    let result = ::execute(doc, None, &schema, &Variables::new(), &database);

    println!("Result: {:#?}", result);

    let (result, errors) = result.ok().expect("Query returned error");

    assert_eq!(errors, vec![]);

    let possible_types = result
        .as_object_value()
        .expect("execution result not an object")
        .get_field_value("__type")
        .expect("'__type' not present in result")
        .as_object_value()
        .expect("'__type' not an object")
        .get_field_value("possibleTypes")
        .expect("'possibleTypes' not present in '__type'")
        .as_list_value()
        .expect("'possibleTypes' not a list")
        .iter()
        .map(|t| {
            t.as_object_value()
                .expect("possible type not an object")
                .get_field_value("name")
                .expect("'name' not present in type")
                .as_scalar_value::<String>()
                .expect("'name' not a string") as &str
        })
        .collect::<HashSet<_>>();

    assert_eq!(possible_types, vec!["Human", "Droid"].into_iter().collect());
}
<|endoftext|>


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

/// Implementation of Quartz (CoreGraphics) fonts.

extern crate core_foundation;
extern crate core_graphics;
extern crate core_text;

use font::{FontHandleMethods, FontMetrics, FontTableMethods};
use font::FontTableTag;
use font::FractionalPixel;
use util::geometry::{Au, px_to_pt};
use platform::macos::font_context::FontContextHandle;
use text::glyph::GlyphId;
use style::computed_values::{font_stretch, font_weight};
use platform::font_template::FontTemplateData;

use core_foundation::base::CFIndex;
use core_foundation::data::CFData;
use core_foundation::string::UniChar;
use core_graphics::font::CGGlyph;
use core_graphics::geometry::CGRect;
use core_text::font::CTFont;
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
use core_text::font_descriptor::{kCTFontDefaultOrientation};

use std::ptr;
use std::sync::Arc;

pub struct FontTable {
    data: CFData,
}

// Noncopyable.
impl Drop for FontTable {
    fn drop(&mut self) {}
}

impl FontTable {
    pub fn wrap(data: CFData) -> FontTable {
        FontTable { data: data }
    }
}

impl FontTableMethods for FontTable {
    fn with_buffer<F>(&self, blk: F) where F: FnOnce(*const u8, usize) {
        blk(self.data.bytes().as_ptr(), self.data.len() as usize);
    }
}

pub struct FontHandle {
    pub font_data: Arc<FontTemplateData>,
    pub ctfont: CTFont,
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(_fctx: &FontContextHandle,
                         template: Arc<FontTemplateData>,
                         pt_size: Option<Au>)
                         -> Result<FontHandle, ()> {
        let size = match pt_size {
            Some(s) => s.to_f64_px(),
            None => 0.0
        };
        match template.ctfont() {
            Some(ref ctfont) => {
                Ok(FontHandle {
                    font_data: template.clone(),
                    ctfont: ctfont.clone_with_font_size(size),
                })
            }
            None => {
                Err(())
            }
        }
    }

    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }

    fn family_name(&self) -> String {
        self.ctfont.family_name()
    }

    fn face_name(&self) -> String {
        self.ctfont.face_name()
    }

    fn is_italic(&self) -> bool {
        self.ctfont.symbolic_traits().is_italic()
    }

    fn boldness(&self) -> font_weight::T {
        // -1.0 to 1.0
        let normalized = self.ctfont.all_traits().normalized_weight();
        // 0.0 to 9.0
        let normalized = (normalized + 1.0) / 2.0 * 9.0;
        if normalized < 1.0 { return font_weight::T::Weight100; }
        if normalized < 2.0 { return font_weight::T::Weight200; }
        if normalized < 3.0 { return font_weight::T::Weight300; }
        if normalized < 4.0 { return font_weight::T::Weight400; }
        if normalized < 5.0 { return font_weight::T::Weight500; }
        if normalized < 6.0 { return font_weight::T::Weight600; }
        if normalized < 7.0 { return font_weight::T::Weight700; }
        if normalized < 8.0 { return font_weight::T::Weight800; }
        return font_weight::T::Weight900;
    }

    fn stretchiness(&self) -> font_stretch::T {
        let normalized = self.ctfont.all_traits().normalized_width();   // [-1.0, 1.0]
        match (normalized + 1.0) / 2.0 * 9.0 {  // [0.0, 9.0]
            v if v < 1.0 => font_stretch::T::ultra_condensed,
            v if v < 2.0 => font_stretch::T::extra_condensed,
            v if v < 3.0 => font_stretch::T::condensed,
            v if v < 4.0 => font_stretch::T::semi_condensed,
            v if v < 5.0 => font_stretch::T::normal,
            v if v < 6.0 => font_stretch::T::semi_expanded,
            v if v < 7.0 => font_stretch::T::expanded,
            v if v < 8.0 => font_stretch::T::extra_expanded,
            _ => font_stretch::T::ultra_expanded,
        }
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        let characters: [UniChar; 1] = [codepoint as UniChar];
        let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
        let count: CFIndex = 1;

        let result = self.ctfont.get_glyphs_for_characters(&characters[0],
                                                           &mut glyphs[0],
                                                           count);

        if !result {
            // No glyph for this character
            return None;
        }

        assert!(glyphs[0] != 0); // FIXME: error handling
        return Some(glyphs[0] as GlyphId);
    }

    fn glyph_h_kerning(&self, _first_glyph: GlyphId, _second_glyph: GlyphId)
                        -> FractionalPixel {
        // TODO: Implement on mac
        0.0
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        let glyphs = [glyph as CGGlyph];
        let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
                                                          &glyphs[0],
                                                          ptr::null_mut(),
                                                          1);
        Some(advance as FractionalPixel)
    }

    fn metrics(&self) -> FontMetrics {
        let bounding_rect: CGRect = self.ctfont.bounding_box();
        let ascent = self.ctfont.ascent() as f64;
        let descent = self.ctfont.descent() as f64;
        let em_size = Au::from_f64_px(self.ctfont.pt_size() as f64);
        let leading = self.ctfont.leading() as f64;

        let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent);
        let line_gap = (ascent + descent + leading + 0.5).floor();

        let max_advance_width = Au::from_pt(bounding_rect.size.width as f64);
        let average_advance = self.glyph_index('0')
                                  .and_then(|idx| self.glyph_h_advance(idx))
                                  .map(|advance| Au::from_f64_px(advance))
                                  .unwrap_or(max_advance_width);

        let metrics =  FontMetrics {
            underline_size:   Au::from_pt(self.ctfont.underline_thickness() as f64),
            // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
            // directly.
            //
            // see also: https://bugs.webkit.org/show_bug.cgi?id=16768
            // see also: https://bugreports.qt-project.org/browse/QTBUG-13364
            underline_offset: Au::from_pt(self.ctfont.underline_position() as f64),
            strikeout_size:   Au(0), // FIXME(Issue #942)
            strikeout_offset: Au(0), // FIXME(Issue #942)
            leading:          Au::from_pt(leading),
            x_height:         Au::from_pt(self.ctfont.x_height() as f64),
            em_size:          em_size,
            ascent:           Au::from_pt(ascent * scale),
            descent:          Au::from_pt(descent * scale),
            max_advance:      max_advance_width,
            average_advance:  average_advance,
            line_gap:         Au::from_f64_px(line_gap),
        };
        debug!("Font metrics (@{} pt): {:?}", self.ctfont.pt_size() as f64, metrics);
        return metrics;
    }

    fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        let result: Option<CFData> = self.ctfont.get_font_table(tag);
        result.and_then(|data| {
            Some(FontTable::wrap(data))
        })
    }
}
<commit_msg>Auto merge of #6867 - frewsxcv:match-guard-and-similar, r=jdm<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/. */

/// Implementation of Quartz (CoreGraphics) fonts.

extern crate core_foundation;
extern crate core_graphics;
extern crate core_text;

use font::{FontHandleMethods, FontMetrics, FontTableMethods};
use font::FontTableTag;
use font::FractionalPixel;
use util::geometry::{Au, px_to_pt};
use platform::macos::font_context::FontContextHandle;
use text::glyph::GlyphId;
use style::computed_values::{font_stretch, font_weight};
use platform::font_template::FontTemplateData;

use core_foundation::base::CFIndex;
use core_foundation::data::CFData;
use core_foundation::string::UniChar;
use core_graphics::font::CGGlyph;
use core_graphics::geometry::CGRect;
use core_text::font::CTFont;
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
use core_text::font_descriptor::{kCTFontDefaultOrientation};

use std::ptr;
use std::sync::Arc;

pub struct FontTable {
    data: CFData,
}

// Noncopyable.
impl Drop for FontTable {
    fn drop(&mut self) {}
}

impl FontTable {
    pub fn wrap(data: CFData) -> FontTable {
        FontTable { data: data }
    }
}

impl FontTableMethods for FontTable {
    fn with_buffer<F>(&self, blk: F) where F: FnOnce(*const u8, usize) {
        blk(self.data.bytes().as_ptr(), self.data.len() as usize);
    }
}

pub struct FontHandle {
    pub font_data: Arc<FontTemplateData>,
    pub ctfont: CTFont,
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(_fctx: &FontContextHandle,
                         template: Arc<FontTemplateData>,
                         pt_size: Option<Au>)
                         -> Result<FontHandle, ()> {
        let size = match pt_size {
            Some(s) => s.to_f64_px(),
            None => 0.0
        };
        match template.ctfont() {
            Some(ref ctfont) => {
                Ok(FontHandle {
                    font_data: template.clone(),
                    ctfont: ctfont.clone_with_font_size(size),
                })
            }
            None => {
                Err(())
            }
        }
    }

    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }

    fn family_name(&self) -> String {
        self.ctfont.family_name()
    }

    fn face_name(&self) -> String {
        self.ctfont.face_name()
    }

    fn is_italic(&self) -> bool {
        self.ctfont.symbolic_traits().is_italic()
    }

    fn boldness(&self) -> font_weight::T {
        let normalized = self.ctfont.all_traits().normalized_weight();  // [-1.0, 1.0]
        let normalized = (normalized + 1.0) / 2.0 * 9.0;  // [0.0, 9.0]
        match normalized {
            v if v < 1.0 => font_weight::T::Weight100,
            v if v < 2.0 => font_weight::T::Weight200,
            v if v < 3.0 => font_weight::T::Weight300,
            v if v < 4.0 => font_weight::T::Weight400,
            v if v < 5.0 => font_weight::T::Weight500,
            v if v < 6.0 => font_weight::T::Weight600,
            v if v < 7.0 => font_weight::T::Weight700,
            v if v < 8.0 => font_weight::T::Weight800,
            _ => font_weight::T::Weight900,
        }
    }

    fn stretchiness(&self) -> font_stretch::T {
        let normalized = self.ctfont.all_traits().normalized_width();  // [-1.0, 1.0]
        let normalized = (normalized + 1.0) / 2.0 * 9.0;  // [0.0, 9.0]
        match normalized {
            v if v < 1.0 => font_stretch::T::ultra_condensed,
            v if v < 2.0 => font_stretch::T::extra_condensed,
            v if v < 3.0 => font_stretch::T::condensed,
            v if v < 4.0 => font_stretch::T::semi_condensed,
            v if v < 5.0 => font_stretch::T::normal,
            v if v < 6.0 => font_stretch::T::semi_expanded,
            v if v < 7.0 => font_stretch::T::expanded,
            v if v < 8.0 => font_stretch::T::extra_expanded,
            _ => font_stretch::T::ultra_expanded,
        }
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        let characters: [UniChar; 1] = [codepoint as UniChar];
        let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
        let count: CFIndex = 1;

        let result = self.ctfont.get_glyphs_for_characters(&characters[0],
                                                           &mut glyphs[0],
                                                           count);

        if !result {
            // No glyph for this character
            return None;
        }

        assert!(glyphs[0] != 0); // FIXME: error handling
        return Some(glyphs[0] as GlyphId);
    }

    fn glyph_h_kerning(&self, _first_glyph: GlyphId, _second_glyph: GlyphId)
                        -> FractionalPixel {
        // TODO: Implement on mac
        0.0
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        let glyphs = [glyph as CGGlyph];
        let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
                                                          &glyphs[0],
                                                          ptr::null_mut(),
                                                          1);
        Some(advance as FractionalPixel)
    }

    fn metrics(&self) -> FontMetrics {
        let bounding_rect: CGRect = self.ctfont.bounding_box();
        let ascent = self.ctfont.ascent() as f64;
        let descent = self.ctfont.descent() as f64;
        let em_size = Au::from_f64_px(self.ctfont.pt_size() as f64);
        let leading = self.ctfont.leading() as f64;

        let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent);
        let line_gap = (ascent + descent + leading + 0.5).floor();

        let max_advance_width = Au::from_pt(bounding_rect.size.width as f64);
        let average_advance = self.glyph_index('0')
                                  .and_then(|idx| self.glyph_h_advance(idx))
                                  .map(|advance| Au::from_f64_px(advance))
                                  .unwrap_or(max_advance_width);

        let metrics =  FontMetrics {
            underline_size:   Au::from_pt(self.ctfont.underline_thickness() as f64),
            // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
            // directly.
            //
            // see also: https://bugs.webkit.org/show_bug.cgi?id=16768
            // see also: https://bugreports.qt-project.org/browse/QTBUG-13364
            underline_offset: Au::from_pt(self.ctfont.underline_position() as f64),
            strikeout_size:   Au(0), // FIXME(Issue #942)
            strikeout_offset: Au(0), // FIXME(Issue #942)
            leading:          Au::from_pt(leading),
            x_height:         Au::from_pt(self.ctfont.x_height() as f64),
            em_size:          em_size,
            ascent:           Au::from_pt(ascent * scale),
            descent:          Au::from_pt(descent * scale),
            max_advance:      max_advance_width,
            average_advance:  average_advance,
            line_gap:         Au::from_f64_px(line_gap),
        };
        debug!("Font metrics (@{} pt): {:?}", self.ctfont.pt_size() as f64, metrics);
        return metrics;
    }

    fn get_table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        let result: Option<CFData> = self.ctfont.get_font_table(tag);
        result.and_then(|data| {
            Some(FontTable::wrap(data))
        })
    }
}
<|endoftext|>


<commit_before>use crate::core::compiler::CompileKind;
use crate::util::interning::InternedString;
use crate::util::ProcessBuilder;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
use anyhow::bail;
use serde::ser;
use std::cell::RefCell;
use std::path::PathBuf;

/// Configuration information for a rustc build.
#[derive(Debug)]
pub struct BuildConfig {
    /// The requested kind of compilation for this session
    pub requested_kinds: Vec<CompileKind>,
    /// Number of rustc jobs to run in parallel.
    pub jobs: u32,
    /// Build profile
    pub requested_profile: InternedString,
    /// The mode we are compiling in.
    pub mode: CompileMode,
    /// `true` to print stdout in JSON format (for machine reading).
    pub message_format: MessageFormat,
    /// Force Cargo to do a full rebuild and treat each target as changed.
    pub force_rebuild: bool,
    /// Output a build plan to stdout instead of actually compiling.
    pub build_plan: bool,
    /// Output the unit graph to stdout instead of actually compiling.
    pub unit_graph: bool,
    /// An optional override of the rustc process for primary units
    pub primary_unit_rustc: Option<ProcessBuilder>,
    /// A thread used by `cargo fix` to receive messages on a socket regarding
    /// the success/failure of applying fixes.
    pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
    /// The directory to copy final artifacts to. Note that even if `out_dir` is
    /// set, a copy of artifacts still could be found a `target/(debug\release)`
    /// as usual.
    // Note that, although the cmd-line flag name is `out-dir`, in code we use
    // `export_dir`, to avoid confusion with out dir at `target/debug/deps`.
    pub export_dir: Option<PathBuf>,
}

impl BuildConfig {
    /// Parses all config files to learn about build configuration. Currently
    /// configured options are:
    ///
    /// * `build.jobs`
    /// * `build.target`
    /// * `target.$target.ar`
    /// * `target.$target.linker`
    /// * `target.$target.libfoo.metadata`
    pub fn new(
        config: &Config,
        jobs: Option<u32>,
        requested_targets: &[String],
        mode: CompileMode,
    ) -> CargoResult<BuildConfig> {
        let cfg = config.build_config()?;
        let requested_kinds = CompileKind::from_requested_targets(config, requested_targets)?;
        if jobs == Some(0) {
            anyhow::bail!("jobs must be at least 1")
        }
        if jobs.is_some() && config.jobserver_from_env().is_some() {
            config.shell().warn(
                "a `-j` argument was passed to Cargo but Cargo is \
                 also configured with an external jobserver in \
                 its environment, ignoring the `-j` parameter",
            )?;
        }
        let jobs = jobs.or(cfg.jobs).unwrap_or(::num_cpus::get() as u32);

        Ok(BuildConfig {
            requested_kinds,
            jobs,
            requested_profile: InternedString::new("dev"),
            mode,
            message_format: MessageFormat::Human,
            force_rebuild: false,
            build_plan: false,
            unit_graph: false,
            primary_unit_rustc: None,
            rustfix_diagnostic_server: RefCell::new(None),
            export_dir: None,
        })
    }

    /// Whether or not the *user* wants JSON output. Whether or not rustc
    /// actually uses JSON is decided in `add_error_format`.
    pub fn emit_json(&self) -> bool {
        match self.message_format {
            MessageFormat::Json { .. } => true,
            _ => false,
        }
    }

    pub fn test(&self) -> bool {
        self.mode == CompileMode::Test || self.mode == CompileMode::Bench
    }

    pub fn single_requested_kind(&self) -> CargoResult<CompileKind> {
        match self.requested_kinds.len() {
            1 => Ok(self.requested_kinds[0]),
            _ => bail!("only one `--target` argument is supported"),
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MessageFormat {
    Human,
    Json {
        /// Whether rustc diagnostics are rendered by cargo or included into the
        /// output stream.
        render_diagnostics: bool,
        /// Whether the `rendered` field of rustc diagnostics are using the
        /// "short" rendering.
        short: bool,
        /// Whether the `rendered` field of rustc diagnostics embed ansi color
        /// codes.
        ansi: bool,
    },
    Short,
}

/// The general "mode" for what to do.
/// This is used for two purposes. The commands themselves pass this in to
/// `compile_ws` to tell it the general execution strategy. This influences
/// the default targets selected. The other use is in the `Unit` struct
/// to indicate what is being done with a specific target.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum CompileMode {
    /// A target being built for a test.
    Test,
    /// Building a target with `rustc` (lib or bin).
    Build,
    /// Building a target with `rustc` to emit `rmeta` metadata only. If
    /// `test` is true, then it is also compiled with `--test` to check it like
    /// a test.
    Check { test: bool },
    /// Used to indicate benchmarks should be built. This is not used in
    /// `Unit`, because it is essentially the same as `Test` (indicating
    /// `--test` should be passed to rustc) and by using `Test` instead it
    /// allows some de-duping of Units to occur.
    Bench,
    /// A target that will be documented with `rustdoc`.
    /// If `deps` is true, then it will also document all dependencies.
    Doc { deps: bool },
    /// A target that will be tested with `rustdoc`.
    Doctest,
    /// A marker for Units that represent the execution of a `build.rs` script.
    RunCustomBuild,
}

impl ser::Serialize for CompileMode {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        use self::CompileMode::*;
        match *self {
            Test => "test".serialize(s),
            Build => "build".serialize(s),
            Check { .. } => "check".serialize(s),
            Bench => "bench".serialize(s),
            Doc { .. } => "doc".serialize(s),
            Doctest => "doctest".serialize(s),
            RunCustomBuild => "run-custom-build".serialize(s),
        }
    }
}

impl CompileMode {
    /// Returns `true` if the unit is being checked.
    pub fn is_check(self) -> bool {
        match self {
            CompileMode::Check { .. } => true,
            _ => false,
        }
    }

    /// Returns `true` if this is generating documentation.
    pub fn is_doc(self) -> bool {
        match self {
            CompileMode::Doc { .. } => true,
            _ => false,
        }
    }

    /// Returns `true` if this a doc test.
    pub fn is_doc_test(self) -> bool {
        self == CompileMode::Doctest
    }

    /// Returns `true` if this is any type of test (test, benchmark, doc test, or
    /// check test).
    pub fn is_any_test(self) -> bool {
        match self {
            CompileMode::Test
            | CompileMode::Bench
            | CompileMode::Check { test: true }
            | CompileMode::Doctest => true,
            _ => false,
        }
    }

    /// Returns `true` if this is something that passes `--test` to rustc.
    pub fn is_rustc_test(self) -> bool {
        match self {
            CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true } => true,
            _ => false,
        }
    }

    /// Returns `true` if this is the *execution* of a `build.rs` script.
    pub fn is_run_custom_build(self) -> bool {
        self == CompileMode::RunCustomBuild
    }

    /// List of all modes (currently used by `cargo clean -p` for computing
    /// all possible outputs).
    pub fn all_modes() -> &'static [CompileMode] {
        static ALL: [CompileMode; 9] = [
            CompileMode::Test,
            CompileMode::Build,
            CompileMode::Check { test: true },
            CompileMode::Check { test: false },
            CompileMode::Bench,
            CompileMode::Doc { deps: true },
            CompileMode::Doc { deps: false },
            CompileMode::Doctest,
            CompileMode::RunCustomBuild,
        ];
        &ALL
    }
}
<commit_msg>Auto merge of #8526 - tmiasko:remove-all-modes, r=ehuss<commit_after>use crate::core::compiler::CompileKind;
use crate::util::interning::InternedString;
use crate::util::ProcessBuilder;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
use anyhow::bail;
use serde::ser;
use std::cell::RefCell;
use std::path::PathBuf;

/// Configuration information for a rustc build.
#[derive(Debug)]
pub struct BuildConfig {
    /// The requested kind of compilation for this session
    pub requested_kinds: Vec<CompileKind>,
    /// Number of rustc jobs to run in parallel.
    pub jobs: u32,
    /// Build profile
    pub requested_profile: InternedString,
    /// The mode we are compiling in.
    pub mode: CompileMode,
    /// `true` to print stdout in JSON format (for machine reading).
    pub message_format: MessageFormat,
    /// Force Cargo to do a full rebuild and treat each target as changed.
    pub force_rebuild: bool,
    /// Output a build plan to stdout instead of actually compiling.
    pub build_plan: bool,
    /// Output the unit graph to stdout instead of actually compiling.
    pub unit_graph: bool,
    /// An optional override of the rustc process for primary units
    pub primary_unit_rustc: Option<ProcessBuilder>,
    /// A thread used by `cargo fix` to receive messages on a socket regarding
    /// the success/failure of applying fixes.
    pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
    /// The directory to copy final artifacts to. Note that even if `out_dir` is
    /// set, a copy of artifacts still could be found a `target/(debug\release)`
    /// as usual.
    // Note that, although the cmd-line flag name is `out-dir`, in code we use
    // `export_dir`, to avoid confusion with out dir at `target/debug/deps`.
    pub export_dir: Option<PathBuf>,
}

impl BuildConfig {
    /// Parses all config files to learn about build configuration. Currently
    /// configured options are:
    ///
    /// * `build.jobs`
    /// * `build.target`
    /// * `target.$target.ar`
    /// * `target.$target.linker`
    /// * `target.$target.libfoo.metadata`
    pub fn new(
        config: &Config,
        jobs: Option<u32>,
        requested_targets: &[String],
        mode: CompileMode,
    ) -> CargoResult<BuildConfig> {
        let cfg = config.build_config()?;
        let requested_kinds = CompileKind::from_requested_targets(config, requested_targets)?;
        if jobs == Some(0) {
            anyhow::bail!("jobs must be at least 1")
        }
        if jobs.is_some() && config.jobserver_from_env().is_some() {
            config.shell().warn(
                "a `-j` argument was passed to Cargo but Cargo is \
                 also configured with an external jobserver in \
                 its environment, ignoring the `-j` parameter",
            )?;
        }
        let jobs = jobs.or(cfg.jobs).unwrap_or(::num_cpus::get() as u32);

        Ok(BuildConfig {
            requested_kinds,
            jobs,
            requested_profile: InternedString::new("dev"),
            mode,
            message_format: MessageFormat::Human,
            force_rebuild: false,
            build_plan: false,
            unit_graph: false,
            primary_unit_rustc: None,
            rustfix_diagnostic_server: RefCell::new(None),
            export_dir: None,
        })
    }

    /// Whether or not the *user* wants JSON output. Whether or not rustc
    /// actually uses JSON is decided in `add_error_format`.
    pub fn emit_json(&self) -> bool {
        match self.message_format {
            MessageFormat::Json { .. } => true,
            _ => false,
        }
    }

    pub fn test(&self) -> bool {
        self.mode == CompileMode::Test || self.mode == CompileMode::Bench
    }

    pub fn single_requested_kind(&self) -> CargoResult<CompileKind> {
        match self.requested_kinds.len() {
            1 => Ok(self.requested_kinds[0]),
            _ => bail!("only one `--target` argument is supported"),
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MessageFormat {
    Human,
    Json {
        /// Whether rustc diagnostics are rendered by cargo or included into the
        /// output stream.
        render_diagnostics: bool,
        /// Whether the `rendered` field of rustc diagnostics are using the
        /// "short" rendering.
        short: bool,
        /// Whether the `rendered` field of rustc diagnostics embed ansi color
        /// codes.
        ansi: bool,
    },
    Short,
}

/// The general "mode" for what to do.
/// This is used for two purposes. The commands themselves pass this in to
/// `compile_ws` to tell it the general execution strategy. This influences
/// the default targets selected. The other use is in the `Unit` struct
/// to indicate what is being done with a specific target.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum CompileMode {
    /// A target being built for a test.
    Test,
    /// Building a target with `rustc` (lib or bin).
    Build,
    /// Building a target with `rustc` to emit `rmeta` metadata only. If
    /// `test` is true, then it is also compiled with `--test` to check it like
    /// a test.
    Check { test: bool },
    /// Used to indicate benchmarks should be built. This is not used in
    /// `Unit`, because it is essentially the same as `Test` (indicating
    /// `--test` should be passed to rustc) and by using `Test` instead it
    /// allows some de-duping of Units to occur.
    Bench,
    /// A target that will be documented with `rustdoc`.
    /// If `deps` is true, then it will also document all dependencies.
    Doc { deps: bool },
    /// A target that will be tested with `rustdoc`.
    Doctest,
    /// A marker for Units that represent the execution of a `build.rs` script.
    RunCustomBuild,
}

impl ser::Serialize for CompileMode {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        use self::CompileMode::*;
        match *self {
            Test => "test".serialize(s),
            Build => "build".serialize(s),
            Check { .. } => "check".serialize(s),
            Bench => "bench".serialize(s),
            Doc { .. } => "doc".serialize(s),
            Doctest => "doctest".serialize(s),
            RunCustomBuild => "run-custom-build".serialize(s),
        }
    }
}

impl CompileMode {
    /// Returns `true` if the unit is being checked.
    pub fn is_check(self) -> bool {
        match self {
            CompileMode::Check { .. } => true,
            _ => false,
        }
    }

    /// Returns `true` if this is generating documentation.
    pub fn is_doc(self) -> bool {
        match self {
            CompileMode::Doc { .. } => true,
            _ => false,
        }
    }

    /// Returns `true` if this a doc test.
    pub fn is_doc_test(self) -> bool {
        self == CompileMode::Doctest
    }

    /// Returns `true` if this is any type of test (test, benchmark, doc test, or
    /// check test).
    pub fn is_any_test(self) -> bool {
        match self {
            CompileMode::Test
            | CompileMode::Bench
            | CompileMode::Check { test: true }
            | CompileMode::Doctest => true,
            _ => false,
        }
    }

    /// Returns `true` if this is something that passes `--test` to rustc.
    pub fn is_rustc_test(self) -> bool {
        match self {
            CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true } => true,
            _ => false,
        }
    }

    /// Returns `true` if this is the *execution* of a `build.rs` script.
    pub fn is_run_custom_build(self) -> bool {
        self == CompileMode::RunCustomBuild
    }
}
<|endoftext|>


<commit_before>//! Undo API
use std::fmt::Debug;

use line_buffer::{ChangeListener, DeleteListener, Direction, LineBuffer};
use unicode_segmentation::UnicodeSegmentation;

enum Change {
    Begin,
    End,
    Insert {
        idx: usize,
        text: String,
    }, // QuotedInsert, SelfInsert, Yank
    Delete {
        idx: usize,
        text: String,
    }, /* BackwardDeleteChar, BackwardKillWord, DeleteChar,
        * KillLine, KillWholeLine, KillWord,
        * UnixLikeDiscard, ViDeleteTo */
    Replace {
        idx: usize,
        old: String,
        new: String,
    }, /* CapitalizeWord, Complete, DowncaseWord, Replace, TransposeChars, TransposeWords,
        * UpcaseWord, YankPop */
}

impl Change {
    fn undo(&self, line: &mut LineBuffer) {
        match *self {
            Change::Begin | Change::End => {
                unreachable!();
            }
            Change::Insert { idx, ref text } => {
                line.delete_range(idx..idx + text.len());
            }
            Change::Delete { idx, ref text } => {
                line.insert_str(idx, text);
                line.set_pos(idx + text.len());
            }
            Change::Replace {
                idx,
                ref old,
                ref new,
            } => {
                line.replace(idx..idx + new.len(), old);
            }
        }
    }

    #[cfg(test)]
    fn redo(&self, line: &mut LineBuffer) {
        match *self {
            Change::Begin | Change::End => {
                unreachable!();
            }
            Change::Insert { idx, ref text } => {
                line.insert_str(idx, text);
            }
            Change::Delete { idx, ref text } => {
                line.delete_range(idx..idx + text.len());
            }
            Change::Replace {
                idx,
                ref old,
                ref new,
            } => {
                line.replace(idx..idx + old.len(), new);
            }
        }
    }

    fn insert_seq(&self, indx: usize) -> bool {
        if let Change::Insert { idx, ref text } = *self {
            idx + text.len() == indx
        } else {
            false
        }
    }

    fn delete_seq(&self, indx: usize, len: usize) -> bool {
        if let Change::Delete { idx, .. } = *self {
            // delete or backspace
            idx == indx || idx == indx + len
        } else {
            false
        }
    }

    fn replace_seq(&self, indx: usize) -> bool {
        if let Change::Replace { idx, ref new, .. } = *self {
            idx + new.len() == indx
        } else {
            false
        }
    }
}

pub struct Changeset {
    undos: Vec<Change>, // undoable changes
    redos: Vec<Change>, // undone changes, redoable
}

impl Changeset {
    pub fn new() -> Changeset {
        Changeset {
            undos: Vec::new(),
            redos: Vec::new(),
        }
    }

    pub fn begin(&mut self) -> usize {
        debug!(target: "rustyline", "Changeset::begin");
        self.redos.clear();
        let mark = self.undos.len();
        self.undos.push(Change::Begin);
        mark
    }

    pub fn end(&mut self) {
        debug!(target: "rustyline", "Changeset::end");
        self.redos.clear();
        if let Some(&Change::Begin) = self.undos.last() {
            // emtpy Begin..End
            self.undos.pop();
        } else {
            self.undos.push(Change::End);
        }
    }

    fn insert_char(idx: usize, c: char) -> Change {
        let mut text = String::new();
        text.push(c);
        Change::Insert { idx, text }
    }

    pub fn insert(&mut self, idx: usize, c: char) {
        debug!(target: "rustyline", "Changeset::insert({}, {:?})", idx, c);
        self.redos.clear();
        if !c.is_alphanumeric() || !self.undos.last().map_or(false, |lc| lc.insert_seq(idx)) {
            self.undos.push(Self::insert_char(idx, c));
            return;
        }
        // merge consecutive char insertions when char is alphanumeric
        let mut last_change = self.undos.pop().unwrap();
        if let Change::Insert { ref mut text, .. } = last_change {
            text.push(c);
        } else {
            unreachable!();
        }
        self.undos.push(last_change);
    }

    pub fn insert_str<S: Into<String> + Debug>(&mut self, idx: usize, string: S) {
        debug!(target: "rustyline", "Changeset::insert_str({}, {:?})", idx, string);
        self.redos.clear();
        self.undos.push(Change::Insert {
            idx,
            text: string.into(),
        });
    }

    pub fn delete<S: AsRef<str> + Into<String> + Debug>(&mut self, indx: usize, string: S) {
        debug!(target: "rustyline", "Changeset::delete({}, {:?})", indx, string);
        self.redos.clear();

        if !Self::single_char(string.as_ref())
            || !self.undos
                .last()
                .map_or(false, |lc| lc.delete_seq(indx, string.as_ref().len()))
        {
            self.undos.push(Change::Delete {
                idx: indx,
                text: string.into(),
            });
            return;
        }
        // merge consecutive char deletions when char is alphanumeric
        let mut last_change = self.undos.pop().unwrap();
        if let Change::Delete {
            ref mut idx,
            ref mut text,
        } = last_change
        {
            if *idx == indx {
                text.push_str(string.as_ref());
            } else {
                text.insert_str(0, string.as_ref());
                *idx = indx;
            }
        } else {
            unreachable!();
        }
        self.undos.push(last_change);
    }

    fn single_char(s: &str) -> bool {
        let mut graphemes = s.graphemes(true);
        graphemes
            .next()
            .map_or(false, |grapheme| grapheme.is_alphanumeric())
            && graphemes.next().is_none()
    }

    pub fn replace<S: AsRef<str> + Into<String> + Debug>(&mut self, indx: usize, old_: S, new_: S) {
        debug!(target: "rustyline", "Changeset::replace({}, {:?}, {:?})", indx, old_, new_);
        self.redos.clear();

        if !self.undos.last().map_or(false, |lc| lc.replace_seq(indx)) {
            self.undos.push(Change::Replace {
                idx: indx,
                old: old_.into(),
                new: new_.into(),
            });
            return;
        }

        // merge consecutive char replacements
        let mut last_change = self.undos.pop().unwrap();
        if let Change::Replace {
            ref mut old,
            ref mut new,
            ..
        } = last_change
        {
            old.push_str(old_.as_ref());
            new.push_str(new_.as_ref());
        } else {
            unreachable!();
        }
        self.undos.push(last_change);
    }

    pub fn undo(&mut self, line: &mut LineBuffer) -> bool {
        debug!(target: "rustyline", "Changeset::undo");
        let mut waiting_for_begin = 0;
        let mut undone = false;
        loop {
            if let Some(change) = self.undos.pop() {
                match change {
                    Change::Begin => {
                        waiting_for_begin -= 1;
                    }
                    Change::End => {
                        waiting_for_begin += 1;
                    }
                    _ => {
                        change.undo(line);
                        self.redos.push(change);
                        undone = true;
                    }
                };
            } else {
                break;
            }
            if waiting_for_begin <= 0 {
                break;
            }
        }
        undone
    }

    pub fn truncate(&mut self, len: usize) {
        debug!(target: "rustyline", "Changeset::truncate({})", len);
        self.undos.truncate(len);
    }

    #[cfg(test)]
    pub fn redo(&mut self, line: &mut LineBuffer) -> bool {
        let mut waiting_for_end = 0;
        let mut redone = false;
        loop {
            if let Some(change) = self.redos.pop() {
                match change {
                    Change::Begin => {
                        waiting_for_end += 1;
                    }
                    Change::End => {
                        waiting_for_end -= 1;
                    }
                    _ => {
                        change.redo(line);
                        self.undos.push(change);
                        redone = true;
                    }
                };
            } else {
                break;
            }
            if waiting_for_end <= 0 {
                break;
            }
        }
        redone
    }
}

impl DeleteListener for Changeset {
    fn delete(&mut self, idx: usize, string: &str, _: Direction) {
        self.delete(idx, string);
    }
}
impl ChangeListener for Changeset {
    fn insert_char(&mut self, idx: usize, c: char) {
        self.insert(idx, c);
    }
    fn insert_str(&mut self, idx: usize, string: &str) {
        self.insert_str(idx, string);
    }
    fn replace(&mut self, idx: usize, old: &str, new: &str) {
        self.replace(idx, old, new);
    }
}

#[cfg(test)]
mod tests {
    use super::Changeset;
    use line_buffer::LineBuffer;

    #[test]
    fn test_insert_chars() {
        let mut cs = Changeset::new();
        cs.insert(0, 'H');
        cs.insert(1, 'i');
        assert_eq!(1, cs.undos.len());
        assert_eq!(0, cs.redos.len());
        cs.insert(0, ' ');
        assert_eq!(2, cs.undos.len());
    }

    #[test]
    fn test_insert_strings() {
        let mut cs = Changeset::new();
        cs.insert_str(0, "Hello");
        cs.insert_str(5, ", ");
        assert_eq!(2, cs.undos.len());
        assert_eq!(0, cs.redos.len());
    }

    #[test]
    fn test_undo_insert() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello");
        buf.insert_str(5, ", world!");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.insert_str(5, ", world!");

        cs.undo(&mut buf);
        assert_eq!(0, cs.undos.len());
        assert_eq!(1, cs.redos.len());
        assert_eq!(buf.as_str(), "Hello");

        cs.redo(&mut buf);
        assert_eq!(1, cs.undos.len());
        assert_eq!(0, cs.redos.len());
        assert_eq!(buf.as_str(), "Hello, world!");
    }

    #[test]
    fn test_undo_delete() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello");

        cs.delete(5, ", world!");

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.redo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_delete_chars() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hlo");

        let mut cs = Changeset::new();
        cs.delete(1, "e");
        cs.delete(1, "l");
        assert_eq!(1, cs.undos.len());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_backspace_chars() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hlo");

        let mut cs = Changeset::new();
        cs.delete(2, "l");
        cs.delete(1, "e");
        assert_eq!(1, cs.undos.len());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_undo_replace() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello, world!");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello, world!");

        buf.replace(1..5, "i");
        assert_eq!(buf.as_str(), "Hi, world!");
        cs.replace(1, "ello", "i");

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.redo(&mut buf);
        assert_eq!(buf.as_str(), "Hi, world!");
    }
}
<commit_msg>Undo: ignore empty change and keep tx boundaries<commit_after>//! Undo API
use std::fmt::Debug;

use line_buffer::{ChangeListener, DeleteListener, Direction, LineBuffer};
use unicode_segmentation::UnicodeSegmentation;

enum Change {
    Begin,
    End,
    Insert {
        idx: usize,
        text: String,
    }, // QuotedInsert, SelfInsert, Yank
    Delete {
        idx: usize,
        text: String,
    }, /* BackwardDeleteChar, BackwardKillWord, DeleteChar,
        * KillLine, KillWholeLine, KillWord,
        * UnixLikeDiscard, ViDeleteTo */
    Replace {
        idx: usize,
        old: String,
        new: String,
    }, /* CapitalizeWord, Complete, DowncaseWord, Replace, TransposeChars, TransposeWords,
        * UpcaseWord, YankPop */
}

impl Change {
    fn undo(&self, line: &mut LineBuffer) {
        match *self {
            Change::Begin | Change::End => {
                unreachable!();
            }
            Change::Insert { idx, ref text } => {
                line.delete_range(idx..idx + text.len());
            }
            Change::Delete { idx, ref text } => {
                line.insert_str(idx, text);
                line.set_pos(idx + text.len());
            }
            Change::Replace {
                idx,
                ref old,
                ref new,
            } => {
                line.replace(idx..idx + new.len(), old);
            }
        }
    }

    #[cfg(test)]
    fn redo(&self, line: &mut LineBuffer) {
        match *self {
            Change::Begin | Change::End => {
                unreachable!();
            }
            Change::Insert { idx, ref text } => {
                line.insert_str(idx, text);
            }
            Change::Delete { idx, ref text } => {
                line.delete_range(idx..idx + text.len());
            }
            Change::Replace {
                idx,
                ref old,
                ref new,
            } => {
                line.replace(idx..idx + old.len(), new);
            }
        }
    }

    fn insert_seq(&self, indx: usize) -> bool {
        if let Change::Insert { idx, ref text } = *self {
            idx + text.len() == indx
        } else {
            false
        }
    }

    fn delete_seq(&self, indx: usize, len: usize) -> bool {
        if let Change::Delete { idx, .. } = *self {
            // delete or backspace
            idx == indx || idx == indx + len
        } else {
            false
        }
    }

    fn replace_seq(&self, indx: usize) -> bool {
        if let Change::Replace { idx, ref new, .. } = *self {
            idx + new.len() == indx
        } else {
            false
        }
    }
}

pub struct Changeset {
    undos: Vec<Change>, // undoable changes
    redos: Vec<Change>, // undone changes, redoable
}

impl Changeset {
    pub fn new() -> Changeset {
        Changeset {
            undos: Vec::new(),
            redos: Vec::new(),
        }
    }

    pub fn begin(&mut self) -> usize {
        debug!(target: "rustyline", "Changeset::begin");
        self.redos.clear();
        let mark = self.undos.len();
        self.undos.push(Change::Begin);
        mark
    }

    pub fn end(&mut self) {
        debug!(target: "rustyline", "Changeset::end");
        self.redos.clear();
        if let Some(&Change::Begin) = self.undos.last() {
            // emtpy Begin..End
            self.undos.pop();
        } else {
            self.undos.push(Change::End);
        }
    }

    fn insert_char(idx: usize, c: char) -> Change {
        let mut text = String::new();
        text.push(c);
        Change::Insert { idx, text }
    }

    pub fn insert(&mut self, idx: usize, c: char) {
        debug!(target: "rustyline", "Changeset::insert({}, {:?})", idx, c);
        self.redos.clear();
        if !c.is_alphanumeric() || !self.undos.last().map_or(false, |lc| lc.insert_seq(idx)) {
            self.undos.push(Self::insert_char(idx, c));
            return;
        }
        // merge consecutive char insertions when char is alphanumeric
        let mut last_change = self.undos.pop().unwrap();
        if let Change::Insert { ref mut text, .. } = last_change {
            text.push(c);
        } else {
            unreachable!();
        }
        self.undos.push(last_change);
    }

    pub fn insert_str<S: AsRef<str> + Into<String> + Debug>(&mut self, idx: usize, string: S) {
        debug!(target: "rustyline", "Changeset::insert_str({}, {:?})", idx, string);
        self.redos.clear();
        if string.as_ref().is_empty() {
            return;
        }
        self.undos.push(Change::Insert {
            idx,
            text: string.into(),
        });
    }

    pub fn delete<S: AsRef<str> + Into<String> + Debug>(&mut self, indx: usize, string: S) {
        debug!(target: "rustyline", "Changeset::delete({}, {:?})", indx, string);
        self.redos.clear();
        if string.as_ref().is_empty() {
            return;
        }

        if !Self::single_char(string.as_ref())
            || !self.undos
                .last()
                .map_or(false, |lc| lc.delete_seq(indx, string.as_ref().len()))
        {
            self.undos.push(Change::Delete {
                idx: indx,
                text: string.into(),
            });
            return;
        }
        // merge consecutive char deletions when char is alphanumeric
        let mut last_change = self.undos.pop().unwrap();
        if let Change::Delete {
            ref mut idx,
            ref mut text,
        } = last_change
        {
            if *idx == indx {
                text.push_str(string.as_ref());
            } else {
                text.insert_str(0, string.as_ref());
                *idx = indx;
            }
        } else {
            unreachable!();
        }
        self.undos.push(last_change);
    }

    fn single_char(s: &str) -> bool {
        let mut graphemes = s.graphemes(true);
        graphemes
            .next()
            .map_or(false, |grapheme| grapheme.is_alphanumeric())
            && graphemes.next().is_none()
    }

    pub fn replace<S: AsRef<str> + Into<String> + Debug>(&mut self, indx: usize, old_: S, new_: S) {
        debug!(target: "rustyline", "Changeset::replace({}, {:?}, {:?})", indx, old_, new_);
        self.redos.clear();

        if !self.undos.last().map_or(false, |lc| lc.replace_seq(indx)) {
            self.undos.push(Change::Replace {
                idx: indx,
                old: old_.into(),
                new: new_.into(),
            });
            return;
        }

        // merge consecutive char replacements
        let mut last_change = self.undos.pop().unwrap();
        if let Change::Replace {
            ref mut old,
            ref mut new,
            ..
        } = last_change
        {
            old.push_str(old_.as_ref());
            new.push_str(new_.as_ref());
        } else {
            unreachable!();
        }
        self.undos.push(last_change);
    }

    pub fn undo(&mut self, line: &mut LineBuffer) -> bool {
        debug!(target: "rustyline", "Changeset::undo");
        let mut waiting_for_begin = 0;
        let mut undone = false;
        loop {
            if let Some(change) = self.undos.pop() {
                match change {
                    Change::Begin => {
                        waiting_for_begin -= 1;
                    }
                    Change::End => {
                        waiting_for_begin += 1;
                    }
                    _ => {
                        change.undo(line);
                        undone = true;
                    }
                };
                self.redos.push(change);
            } else {
                break;
            }
            if waiting_for_begin <= 0 {
                break;
            }
        }
        undone
    }

    pub fn truncate(&mut self, len: usize) {
        debug!(target: "rustyline", "Changeset::truncate({})", len);
        self.undos.truncate(len);
    }

    #[cfg(test)]
    pub fn redo(&mut self, line: &mut LineBuffer) -> bool {
        let mut waiting_for_end = 0;
        let mut redone = false;
        loop {
            if let Some(change) = self.redos.pop() {
                match change {
                    Change::Begin => {
                        waiting_for_end += 1;
                    }
                    Change::End => {
                        waiting_for_end -= 1;
                    }
                    _ => {
                        change.redo(line);
                        redone = true;
                    }
                };
                self.undos.push(change);
            } else {
                break;
            }
            if waiting_for_end <= 0 {
                break;
            }
        }
        redone
    }
}

impl DeleteListener for Changeset {
    fn delete(&mut self, idx: usize, string: &str, _: Direction) {
        self.delete(idx, string);
    }
}
impl ChangeListener for Changeset {
    fn insert_char(&mut self, idx: usize, c: char) {
        self.insert(idx, c);
    }
    fn insert_str(&mut self, idx: usize, string: &str) {
        self.insert_str(idx, string);
    }
    fn replace(&mut self, idx: usize, old: &str, new: &str) {
        self.replace(idx, old, new);
    }
}

#[cfg(test)]
mod tests {
    use super::Changeset;
    use line_buffer::LineBuffer;

    #[test]
    fn test_insert_chars() {
        let mut cs = Changeset::new();
        cs.insert(0, 'H');
        cs.insert(1, 'i');
        assert_eq!(1, cs.undos.len());
        assert_eq!(0, cs.redos.len());
        cs.insert(0, ' ');
        assert_eq!(2, cs.undos.len());
    }

    #[test]
    fn test_insert_strings() {
        let mut cs = Changeset::new();
        cs.insert_str(0, "Hello");
        cs.insert_str(5, ", ");
        assert_eq!(2, cs.undos.len());
        assert_eq!(0, cs.redos.len());
    }

    #[test]
    fn test_undo_insert() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello");
        buf.insert_str(5, ", world!");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.insert_str(5, ", world!");

        cs.undo(&mut buf);
        assert_eq!(0, cs.undos.len());
        assert_eq!(1, cs.redos.len());
        assert_eq!(buf.as_str(), "Hello");

        cs.redo(&mut buf);
        assert_eq!(1, cs.undos.len());
        assert_eq!(0, cs.redos.len());
        assert_eq!(buf.as_str(), "Hello, world!");
    }

    #[test]
    fn test_undo_delete() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello");

        cs.delete(5, ", world!");

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.redo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_delete_chars() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hlo");

        let mut cs = Changeset::new();
        cs.delete(1, "e");
        cs.delete(1, "l");
        assert_eq!(1, cs.undos.len());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_backspace_chars() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hlo");

        let mut cs = Changeset::new();
        cs.delete(2, "l");
        cs.delete(1, "e");
        assert_eq!(1, cs.undos.len());

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello");
    }

    #[test]
    fn test_undo_replace() {
        let mut buf = LineBuffer::init("", 0, None);
        buf.insert_str(0, "Hello, world!");
        let mut cs = Changeset::new();
        assert_eq!(buf.as_str(), "Hello, world!");

        buf.replace(1..5, "i");
        assert_eq!(buf.as_str(), "Hi, world!");
        cs.replace(1, "ello", "i");

        cs.undo(&mut buf);
        assert_eq!(buf.as_str(), "Hello, world!");

        cs.redo(&mut buf);
        assert_eq!(buf.as_str(), "Hi, world!");
    }
}
<|endoftext|>


<commit_before>#[link(name = "bloomfilter", vers = "0.1", author = "bbrittain")];
#[crate_type = "lib"];

use std;
import bitv = std::bitv;

#[doc = "Bloom Filter Type"]
type bloomfilter<T> = @{storage: bitv::bitv, capacity: uint, mut count: uint, hash_funcs: [(fn@(++T) -> [u8])]};

#[doc = "create a Bloom Filter. Requires a capacity and an array of hashing functions to use. The hashing functions return type must be [u8]"]
fn bloomfilter<T>(capacity: uint, hash_funcs: [(fn@(++T) -> [u8])]) -> bloomfilter<T> {
    @{storage: bitv::bitv(capacity,false), capacity: capacity, mut count: 0u, hash_funcs: copy hash_funcs}
}

#[doc = "add an element to the bloomfilter"]
fn add<T>(bloomfilter: bloomfilter<T>, elem: T ){
    for vec::each(bloomfilter.hash_funcs) {|func|
        let hashstr:[u8] = func(elem);
            for vec::each(hashstr) {|elm|
                let loc = (elm as uint) % (bloomfilter.capacity - 1u);
                bitv::set(bloomfilter.storage, loc, true);
            }
    }
    bloomfilter.count += 1u;
    assert bloomfilter.count <= bloomfilter.capacity;
}

#[doc = "check to see if the element might be in the bloomfilter (or certainly not)"]
fn contains<T>(bloomfilter: bloomfilter<T>, elem: T ) -> bool {
    for vec::each(bloomfilter.hash_funcs) {|func|
        let hashstr:[u8] = func(elem);
            for vec::each(hashstr) {|elm|
                let loc = (elm as uint) % (bloomfilter.capacity - 1u);
                let val = bitv::get(bloomfilter.storage, loc);
                if val == false {
                    ret false;
                }
                bitv::set(bloomfilter.storage, loc, true);
            }
    }
    ret true;
}

#[doc = "check to see if two bloomfilters are equal. Must be the same size"]
fn equal<T>(bloomfilter_one: bloomfilter<T>, bloomfilter_two: bloomfilter<T>) -> bool {
    assert bloomfilter_one.capacity == bloomfilter_two.capacity;
    if bitv::equal(bloomfilter_one.storage,bloomfilter_two.storage){
        true
    } else {
        false
    }
}

#[doc = "merge two bloom filters together. Must be the same size"]
fn union<T>(bloomfilter_one: bloomfilter<T>, bloomfilter_two: bloomfilter<T>) -> bloomfilter<T> {
    assert bloomfilter_one.capacity == bloomfilter_two.capacity;
    let bloomfilter_new = copy bloomfilter_one;
    bitv::union(bloomfilter_new.storage,bloomfilter_two.storage);
    let count_new = bloomfilter_one.count + bloomfilter_two.count;
    bloomfilter_new.count = count_new;
    bloomfilter_new
}
<commit_msg>bloomfilter has sha1 removed<commit_after>#[link(name = "bloomfilter", vers = "0.2", author = "Ben Brittain")];
#[crate_type = "lib"];
export bloomfilter;
export add;
export contains;
export equal;
export union;

use std;
import bitv = std::bitv;

#[doc = "Bloom Filter Type"]
type bloomfilter<T> = @{storage: bitv::bitv, capacity: uint, mut count: uint, hash_funcs: [(fn@(++T) -> [u8])]};

#[doc = "create a Bloom Filter. Requires a capacity and an array of hashing functions to use. The hashing functions return type must be [u8]"]
fn bloomfilter<T>(capacity: uint, hash_funcs: [(fn@(++T) -> [u8])]) -> bloomfilter<T> {
    @{storage: bitv::bitv(capacity,false), capacity: capacity, mut count: 0u, hash_funcs: copy hash_funcs}
}

#[doc = "add an element to the bloomfilter"]
fn add<T>(bloomfilter: bloomfilter<T>, elem: T ){
    for vec::each(bloomfilter.hash_funcs) {|func|
        let hashstr:[u8] = func(elem);
            for vec::each(hashstr) {|elm|
                let loc = (elm as uint) % (bloomfilter.capacity - 1u);
                bitv::set(bloomfilter.storage, loc, true);
            }
    }
    bloomfilter.count += 1u;
    assert bloomfilter.count <= bloomfilter.capacity;
}

#[doc = "check to see if the element might be in the bloomfilter (or certainly not)"]
fn contains<T>(bloomfilter: bloomfilter<T>, elem: T ) -> bool {
    for vec::each(bloomfilter.hash_funcs) {|func|
        let hashstr:[u8] = func(elem);
            for vec::each(hashstr) {|elm|
                let loc = (elm as uint) % (bloomfilter.capacity - 1u);
                let val = bitv::get(bloomfilter.storage, loc);
                if val == false {
                    ret false;
                }
                bitv::set(bloomfilter.storage, loc, true);
            }
    }
    ret true;
}

#[doc = "check to see if two bloomfilters are equal. Must be the same size"]
fn equal<T>(bloomfilter_one: bloomfilter<T>, bloomfilter_two: bloomfilter<T>) -> bool {
    assert bloomfilter_one.capacity == bloomfilter_two.capacity;
    if bitv::equal(bloomfilter_one.storage,bloomfilter_two.storage){
        true
    } else {
        false
    }
}

#[doc = "merge two bloom filters together. Must be the same size"]
fn union<T>(bloomfilter_one: bloomfilter<T>, bloomfilter_two: bloomfilter<T>) -> bloomfilter<T> {
    assert bloomfilter_one.capacity == bloomfilter_two.capacity;
    let bloomfilter_new = copy bloomfilter_one;
    bitv::union(bloomfilter_new.storage,bloomfilter_two.storage);
    let count_new = bloomfilter_one.count + bloomfilter_two.count;
    bloomfilter_new.count = count_new;
    bloomfilter_new
}

<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use ffi;
use types::{gchar,gsize};
use types::{gpointer};

use alloc::libc_heap::malloc_raw;
use libc;
use libc::c_char;
use std::c_str::{CString,ToCStr};
use std::kinds::marker;
use std::mem::transmute;
use std::ptr::copy_nonoverlapping_memory;
use std::slice;
use std::str;
use std::string;

pub struct UTF8Chars<'a> {
    data: *const gchar,
    lifetime: marker::ContravariantLifetime<'a>
}

impl<'a> UTF8Chars<'a> {
    pub unsafe fn wrap(ptr: *const gchar) -> UTF8Chars<'a> {
        UTF8Chars { data: ptr, lifetime: marker::ContravariantLifetime }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf(self.data as *const u8)
        }
    }
}

#[inline]
unsafe fn utf8_cont_byte(p: *const gchar) -> u8 {
    let byte = *p as u8;
    debug_assert!((byte & 0xC0) == 0x80);
    byte & 0x3F
}

impl<'a> Iterator<char> for UTF8Chars<'a> {
    fn next(&mut self) -> Option<char> {
        let first_byte = unsafe { *self.data as u8 };
        if first_byte == 0 {
            return None;
        }
        if first_byte < 0x80 {
            unsafe {
                self.data = self.data.offset(1);
            }
            return Some(first_byte as char);
        }
        unsafe {
            let mut p = self.data.offset(1);
            let mut wc: u32 = (first_byte & 0x1F) as u32 << 6;
            wc |= utf8_cont_byte(p) as u32;
            if first_byte >= 0xE0 {
                p = p.offset(1);
                wc = (wc << 6) & 0xFFFF;
                wc |= utf8_cont_byte(p) as u32;
                if first_byte >= 0xF0 {
                    debug_assert!(first_byte < 0xF8);
                    p = p.offset(1);
                    wc = (wc << 6) & 0x1FFFFF;
                    wc |= utf8_cont_byte(p) as u32;
                    debug_assert!(wc >= 0x010000 && wc <= 0x10FFFF);
                } else {
                    debug_assert!(wc >= 0x0800);
                    debug_assert!((wc & 0xF800) != 0xD800);
                }
            } else {
                debug_assert!(wc >= 0x80);
            }
            self.data = p.offset(1);
            Some(transmute(wc))
        }
    }
}

unsafe fn dup_to_c_str(source: *const c_char, len: uint) -> CString {
    let copy = malloc_raw(len + 1) as *mut c_char;
    copy_nonoverlapping_memory(copy, source, len + 1);
    CString::new(copy as *const c_char, true)
}

impl<'a> ToCStr for UTF8Chars<'a> {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        let src = self.data as *const c_char;
        let len = libc::strlen(src) as uint;
        dup_to_c_str(src, len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Buf {
    data: *mut gchar,
}

impl UTF8Buf {

    pub unsafe fn wrap(data: *mut gchar) -> UTF8Buf {
        UTF8Buf { data: data }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> {
        unsafe { UTF8Chars::wrap(self.data as *const gchar) }
    }

    pub fn into_collection(self) -> UTF8Str {
        unsafe {
            let len = libc::strlen(self.data as *const c_char);
            UTF8Str { buf: transmute(self), len: len as uint }
        }
    }

    #[inline]
    pub fn to_string(&self) -> String { self.chars().to_string() }

    #[inline]
    pub fn to_owned(&self) -> String { self.to_string() }

    #[inline]
    pub fn into_string(self) -> String { self.to_string() }

    #[inline]
    pub fn into_owned(self) -> String { self.to_string() }

    pub fn is_empty(&self) -> bool { unsafe { *self.data == 0 } }
}

impl Drop for UTF8Buf {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.data as gpointer) }
    }
}

impl Clone for UTF8Buf {
    fn clone(&self) -> UTF8Buf {
        unsafe {
            UTF8Buf::wrap(ffi::g_strdup(self.data as *const gchar))
        }
    }
}

impl ToCStr for UTF8Buf {

    fn to_c_str(&self) -> CString {
        self.chars().to_c_str()
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        self.chars().to_c_str_unchecked()
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Str {
    buf: UTF8Buf,
    len: uint
}

static NUL: gchar = 0;

impl UTF8Str {

    pub unsafe fn wrap(data: *mut gchar, len: uint) -> UTF8Str {
        UTF8Str { buf: UTF8Buf::wrap(data), len: len }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> { self.buf.chars() }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf_len(self.buf.data as *const u8, self.len)
        }
    }
}

impl Clone for UTF8Str {
    fn clone(&self) -> UTF8Str {
        unsafe {
            let copy = ffi::g_malloc((self.len + 1) as gsize) as *mut gchar;
            copy_nonoverlapping_memory(copy,
                    self.buf.data as *const gchar, self.len);
            *copy.offset(self.len as int) = NUL;
            UTF8Str::wrap(copy, self.len)
        }
    }
}

impl Str for UTF8Str {
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            slice::raw::buf_as_slice(
                self.buf.data as *const u8,
                self.len,
                |bytes| {
                    let s = str::raw::from_utf8(bytes);
                    transmute(s)
                })
        }
    }
}

impl StrAllocating for UTF8Str {
    fn into_string(self) -> String { self.to_string() }
}

impl Collection for UTF8Str {

    // Common sense says we should return the UTF-8 length,
    // but &str returns length in bytes, so...
    fn len(&self) -> uint { return self.len }

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

impl ToCStr for UTF8Str {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.buf.data as *const c_char, self.len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str(f)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str_unchecked(f)
    }
}

impl PartialEq for UTF8Str {
    fn eq(&self, other: &UTF8Str) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Eq for UTF8Str { }

impl<S: Str> Equiv<S> for UTF8Str {
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

pub trait WithUTF8 {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T;
}

impl<'a> WithUTF8 for UTF8Chars<'a> {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data)
    }
}

impl WithUTF8 for UTF8Buf {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data as *const gchar)
    }
}

impl WithUTF8 for UTF8Str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.buf.with_utf8_c_str(f)
    }
}

impl<'a> WithUTF8 for &'a str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}

impl WithUTF8 for String {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}
<commit_msg>Slightly more optimization-friendly code for UTF8Chars<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use ffi;
use types::{gchar,gsize};
use types::{gpointer};

use alloc::libc_heap::malloc_raw;
use libc;
use libc::c_char;
use std::c_str::{CString,ToCStr};
use std::kinds::marker;
use std::mem::transmute;
use std::ptr::copy_nonoverlapping_memory;
use std::slice;
use std::str;
use std::string;

pub struct UTF8Chars<'a> {
    data: *const gchar,
    lifetime: marker::ContravariantLifetime<'a>
}

impl<'a> UTF8Chars<'a> {
    pub unsafe fn wrap(ptr: *const gchar) -> UTF8Chars<'a> {
        UTF8Chars { data: ptr, lifetime: marker::ContravariantLifetime }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf(self.data as *const u8)
        }
    }
}

#[inline]
unsafe fn utf8_cont_bits(p: *const gchar) -> u32 {
    let byte = *p as u8;
    debug_assert!((byte & 0xC0) == 0x80);
    (byte & 0x3F) as u32
}

impl<'a> Iterator<char> for UTF8Chars<'a> {
    fn next(&mut self) -> Option<char> {
        let p = self.data;
        let first_byte = unsafe { *p as u8 };
        if first_byte == 0 {
            return None;
        }
        unsafe {
            let mut wc: u32;
            if first_byte < 0xC0 {
                debug_assert!(first_byte < 0x80);
                wc = first_byte as u32;
                self.data = p.offset(1);
            } else {
                let c1 = utf8_cont_bits(p.offset(1));
                if first_byte < 0xE0 {
                    wc = ((first_byte & 0x1F) as u32 << 6) | c1;
                    debug_assert!(wc >= 0x80);
                    self.data = p.offset(2);
                } else {
                    let c2 = utf8_cont_bits(p.offset(2));
                    if first_byte < 0xF0 {
                        wc = ((first_byte & 0x0F) as u32 << 12)
                             | (c1 << 6) | c2;
                        debug_assert!(wc >= 0x0800);
                        debug_assert!((wc & 0xF800) != 0xD800);
                        self.data = p.offset(3);
                    } else {
                        debug_assert!(first_byte <= 0xF4);
                        let c3 = utf8_cont_bits(p.offset(3));
                        wc = ((first_byte & 0x07) as u32 << 18)
                             | (c1 << 12) | (c2 << 6) | c3;
                        debug_assert!(wc >= 0x010000 && wc <= 0x10FFFF);
                        self.data = p.offset(4);
                    }
                }
            }
            Some(transmute(wc))
        }
    }
}

unsafe fn dup_to_c_str(source: *const c_char, len: uint) -> CString {
    let copy = malloc_raw(len + 1) as *mut c_char;
    copy_nonoverlapping_memory(copy, source, len + 1);
    CString::new(copy as *const c_char, true)
}

impl<'a> ToCStr for UTF8Chars<'a> {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        let src = self.data as *const c_char;
        let len = libc::strlen(src) as uint;
        dup_to_c_str(src, len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Buf {
    data: *mut gchar,
}

impl UTF8Buf {

    pub unsafe fn wrap(data: *mut gchar) -> UTF8Buf {
        UTF8Buf { data: data }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> {
        unsafe { UTF8Chars::wrap(self.data as *const gchar) }
    }

    pub fn into_collection(self) -> UTF8Str {
        unsafe {
            let len = libc::strlen(self.data as *const c_char);
            UTF8Str { buf: transmute(self), len: len as uint }
        }
    }

    #[inline]
    pub fn to_string(&self) -> String { self.chars().to_string() }

    #[inline]
    pub fn to_owned(&self) -> String { self.to_string() }

    #[inline]
    pub fn into_string(self) -> String { self.to_string() }

    #[inline]
    pub fn into_owned(self) -> String { self.to_string() }

    pub fn is_empty(&self) -> bool { unsafe { *self.data == 0 } }
}

impl Drop for UTF8Buf {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.data as gpointer) }
    }
}

impl Clone for UTF8Buf {
    fn clone(&self) -> UTF8Buf {
        unsafe {
            UTF8Buf::wrap(ffi::g_strdup(self.data as *const gchar))
        }
    }
}

impl ToCStr for UTF8Buf {

    fn to_c_str(&self) -> CString {
        self.chars().to_c_str()
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        self.chars().to_c_str_unchecked()
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        f(self.data as *const i8)
    }
}

pub struct UTF8Str {
    buf: UTF8Buf,
    len: uint
}

static NUL: gchar = 0;

impl UTF8Str {

    pub unsafe fn wrap(data: *mut gchar, len: uint) -> UTF8Str {
        UTF8Str { buf: UTF8Buf::wrap(data), len: len }
    }

    pub fn chars<'a>(&'a self) -> UTF8Chars<'a> { self.buf.chars() }

    pub fn to_string(&self) -> String {
        unsafe {
            string::raw::from_buf_len(self.buf.data as *const u8, self.len)
        }
    }
}

impl Clone for UTF8Str {
    fn clone(&self) -> UTF8Str {
        unsafe {
            let copy = ffi::g_malloc((self.len + 1) as gsize) as *mut gchar;
            copy_nonoverlapping_memory(copy,
                    self.buf.data as *const gchar, self.len);
            *copy.offset(self.len as int) = NUL;
            UTF8Str::wrap(copy, self.len)
        }
    }
}

impl Str for UTF8Str {
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            slice::raw::buf_as_slice(
                self.buf.data as *const u8,
                self.len,
                |bytes| {
                    let s = str::raw::from_utf8(bytes);
                    transmute(s)
                })
        }
    }
}

impl StrAllocating for UTF8Str {
    fn into_string(self) -> String { self.to_string() }
}

impl Collection for UTF8Str {

    // Common sense says we should return the UTF-8 length,
    // but &str returns length in bytes, so...
    fn len(&self) -> uint { return self.len }

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

impl ToCStr for UTF8Str {

    fn to_c_str(&self) -> CString {
        unsafe { self.to_c_str_unchecked() }
    }

    unsafe fn to_c_str_unchecked(&self) -> CString {
        dup_to_c_str(self.buf.data as *const c_char, self.len)
    }

    fn with_c_str<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str(f)
    }

    unsafe fn with_c_str_unchecked<T>(&self, f: |*const i8| -> T) -> T {
        self.buf.with_c_str_unchecked(f)
    }
}

impl PartialEq for UTF8Str {
    fn eq(&self, other: &UTF8Str) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl Eq for UTF8Str { }

impl<S: Str> Equiv<S> for UTF8Str {
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

pub trait WithUTF8 {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T;
}

impl<'a> WithUTF8 for UTF8Chars<'a> {
    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data)
    }
}

impl WithUTF8 for UTF8Buf {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        f(self.data as *const gchar)
    }
}

impl WithUTF8 for UTF8Str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.buf.with_utf8_c_str(f)
    }
}

impl<'a> WithUTF8 for &'a str {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}

impl WithUTF8 for String {

    fn with_utf8_c_str<T>(&self, f: |*const gchar| -> T) -> T {
        self.with_c_str(f)
    }
}
<|endoftext|>