Skip to content

Commit b67c9f4

Browse files
committed
Use IndexSet instead of Vec for codepoints
This ensures that codepoints are unique, but also respects the original order in which they appear in the file.
1 parent 417e4ac commit b67c9f4

6 files changed

Lines changed: 40 additions & 6 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ quick-xml = { version = "0.26.0", features = ["serialize"] }
2727
rayon = { version = "1.3.0", optional = true }
2828
kurbo = { version = "0.9.0", optional = true }
2929
thiserror = "1.0"
30+
indexmap = {version = "1.9.2", features = ["serde"] }
3031

3132
[dependencies.druid]
3233
default-features = false

src/glyph/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::error::ConvertContourError;
1313

1414
#[cfg(feature = "druid")]
1515
use druid::{Data, Lens};
16+
use indexmap::IndexSet;
1617

1718
use crate::error::{ErrorKind, GlifLoadError, GlifWriteError, StoreError};
1819
use crate::name::Name;
@@ -38,7 +39,7 @@ pub struct Glyph {
3839
/// A collection of glyph Unicode code points.
3940
///
4041
/// The first entry defines the primary Unicode value for this glyph.
41-
pub codepoints: Vec<char>,
42+
pub codepoints: IndexSet<char>,
4243
/// Arbitrary glyph note.
4344
pub note: Option<String>,
4445
/// A collection of glyph guidelines.
@@ -115,7 +116,7 @@ impl Glyph {
115116
name,
116117
height: 0.0,
117118
width: 0.0,
118-
codepoints: Vec::new(),
119+
codepoints: Default::default(),
119120
note: None,
120121
guidelines: Vec::new(),
121122
anchors: Vec::new(),

src/glyph/parse.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ impl<'names> GlifParser<'names> {
409409
.map_err(|_| value.to_string())
410410
.and_then(|n| char::try_from(n).map_err(|_| value.to_string()))
411411
.map_err(|_| ErrorKind::BadHexValue)?;
412-
self.glyph.codepoints.push(chr);
412+
self.glyph.codepoints.insert(chr);
413413
}
414414
_other => return Err(ErrorKind::UnexpectedAttribute.into()),
415415
}

src/glyph/tests.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use indexmap::indexset;
2+
13
use super::parse::parse_glyph;
24
use super::*;
35
use crate::write::QuoteChar;
@@ -868,3 +870,30 @@ fn has_component_with_base() {
868870
assert!(glyph.has_component_with_base("dieresis"));
869871
assert!(!glyph.has_component_with_base("Z"));
870872
}
873+
874+
#[test]
875+
fn deduplicate_unicodes2() {
876+
let data = r#"
877+
<?xml version="1.0" encoding="UTF-8"?>
878+
<glyph name="period" format="2">
879+
<unicode hex="0065"/>
880+
<unicode hex="0066"/>
881+
<unicode hex="0065"/>
882+
<unicode hex="0067"/>
883+
</glyph>
884+
"#;
885+
let mut glyph = parse_glyph(data.as_bytes()).unwrap();
886+
assert_eq!(glyph.codepoints, indexset!['e', 'f', 'g'].into());
887+
888+
glyph.codepoints = indexset!['e', 'f', 'e', 'g'].into();
889+
let data2 = glyph.encode_xml().unwrap();
890+
let data2 = std::str::from_utf8(&data2).unwrap();
891+
let data2_expected = r#"<?xml version="1.0" encoding="UTF-8"?>
892+
<glyph name="period" format="2">
893+
<unicode hex="0065"/>
894+
<unicode hex="0066"/>
895+
<unicode hex="0067"/>
896+
</glyph>
897+
"#;
898+
assert_eq!(data2, data2_expected);
899+
}

src/layer.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,8 @@ impl Default for Layer {
594594

595595
#[cfg(test)]
596596
mod tests {
597+
use indexmap::indexset;
598+
597599
use crate::DataRequest;
598600

599601
use super::*;
@@ -613,7 +615,7 @@ mod tests {
613615
let glyph = layer.get_glyph("A").expect("failed to load glyph 'A'");
614616
assert_eq!(glyph.height, 0.);
615617
assert_eq!(glyph.width, 1190.);
616-
assert_eq!(glyph.codepoints, vec!['A']);
618+
assert_eq!(glyph.codepoints, indexset!['A']);
617619
}
618620

619621
#[test]

tests/save.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Testing saving files.
22
3+
use indexmap::indexset;
34
use norad::{Font, FormatVersion, Glyph, Identifier, Plist};
45
use plist::Value;
56

@@ -24,7 +25,7 @@ fn save_default() {
2425
fn save_new_file() {
2526
let mut my_ufo = Font::new();
2627
let mut my_glyph = Glyph::new("A");
27-
my_glyph.codepoints = vec!['A'];
28+
my_glyph.codepoints = indexset!['A'];
2829
my_glyph.note = Some("I did a glyph!".into());
2930
let mut plist = Plist::new();
3031
plist.insert("my-cool-key".into(), plist::Value::Integer(420_u32.into()));
@@ -42,7 +43,7 @@ fn save_new_file() {
4243
let loaded = Font::load(dir).unwrap();
4344
assert!(loaded.default_layer().get_glyph("A").is_some());
4445
let glyph = loaded.default_layer().get_glyph("A").unwrap();
45-
assert_eq!(glyph.codepoints, vec!['A']);
46+
assert_eq!(glyph.codepoints, indexset!['A']);
4647
let lib_val = glyph.lib.get("my-cool-key").and_then(|val| val.as_unsigned_integer());
4748
assert_eq!(lib_val, Some(420));
4849
}

0 commit comments

Comments
 (0)