Skip to content

Commit

Permalink
New API: Point::is_valid
Browse files Browse the repository at this point in the history
Cf. MFEK/stroke#21 (rationale, we'd catch `NaN` bugs earlier if we
refused to write at all)
Cf. linebender/norad#198 (similar problem in a competing/featurewise
inferior library)
  • Loading branch information
ctrlcctrlv committed Dec 19, 2021
1 parent b05ed9f commit e25bfa0
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/glif/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub fn write_ufo_glif_data<PD: PointData>(glif: &Glif<PD>) -> Result<Vec<u8>, Gl
}

let mut point_node = xmltree::Element::new("point");
debug_assert!(point.is_valid(None));
point_node.attributes.insert("x".to_owned(), point.x.to_string());
point_node.attributes.insert("y".to_owned(), point.y.to_string());

Expand Down
30 changes: 30 additions & 0 deletions src/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,36 @@ pub struct Point<PD: PointData> {
pub data: Option<PD>,
}

impl<PD: PointData> Point<PD> {
/// `validate_data` parameter allows you to define an `is_valid` (or whatever) impl on your
/// `PointData` struct's. You can then pass the function while validating the point as e.g.
/// `Some(MyPointData::is_valid)`. It takes an `Option<&PD>` so that you have the choice as to
/// whether it's valid or not for your type not to be defined; `Point.data` should probably not
/// be defined as an Option<PD>, but removing that's TODO. This API will change when that does
/// and should be considered unstable/testing.
pub fn is_valid(&self, validate_data: Option<fn(Option<&PD>)->bool>) -> bool {
if let Some(validate_point_data_function) = validate_data {
if !validate_point_data_function(self.data.as_ref()) {
return false
}
}
if self.ptype == PointType::Undefined {
return false
}
if self.x.is_subnormal() || self.y.is_subnormal() {
return false
}
for handle in [self.handle(WhichHandle::A), self.handle(WhichHandle::B)] {
if let Handle::At(hx, hy) = handle {
if hx.is_subnormal() || hy.is_subnormal() {
return false
}
}
}
true
}
}

/// For use by ``Point::handle_or_colocated``
/// TODO: Replace with Option<WhichHandle>
#[cfg_attr(feature = "glifserde", derive(Serialize, Deserialize))]
Expand Down

0 comments on commit e25bfa0

Please sign in to comment.