Skip to content

Commit

Permalink
Add no_std support for lyon_tessellation (#887)
Browse files Browse the repository at this point in the history
  • Loading branch information
konall authored Dec 17, 2023
1 parent f9b010f commit 001d713
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 111 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions crates/tessellation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ name = "lyon_tessellation"
path = "src/lib.rs"

[features]
default = ["std"]
std = ["lyon_path/std", "num-traits/std"]
serialization = ["serde", "lyon_path/serialization"]
debugger = []
profiling = []

[dependencies]
lyon_path = { version = "1.0.3", path = "../path" }
lyon_path = { version = "1.0.3", path = "../path", default-features = false }
float_next_after = "1.0.0"
serde = { version = "1.0", optional = true, features = ["serde_derive"] }
thiserror = "1.0"
num-traits = { version = "0.2.15", default-features = false, features = ["libm"] }

[dev-dependencies]
lyon_extra = { version = "1.0.0", path = "../extra" }
5 changes: 4 additions & 1 deletion crates/tessellation/src/basic_shapes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use crate::{
FillGeometryBuilder, FillOptions, FillVertex, TessellationError, TessellationResult, VertexId,
};

use std::f32::consts::PI;
use core::f32::consts::PI;

#[cfg(not(feature = "std"))]
use num_traits::Float;

pub fn fill_rectangle(rect: &Box2D, output: &mut dyn FillGeometryBuilder) -> TessellationResult {
output.begin_geometry();
Expand Down
133 changes: 133 additions & 0 deletions crates/tessellation/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/// The fill tessellator's result type.
pub type TessellationResult = Result<(), TessellationError>;

/// An error that can happen while generating geometry.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum GeometryBuilderError {
InvalidVertex,
TooManyVertices,
}

#[cfg(feature = "std")]
impl core::fmt::Display for GeometryBuilderError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
GeometryBuilderError::InvalidVertex => {
std::write!(f, "Invalid vertex")
},
GeometryBuilderError::TooManyVertices => {
std::write!(f, "Too many vertices")
}
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for GeometryBuilderError {}

/// Describes an unexpected error happening during tessellation.
///
/// If you run into one of these, please consider
/// [filing an issue](https://github.com/nical/lyon/issues/new).
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum InternalError {
IncorrectActiveEdgeOrder(i16),
InsufficientNumberOfSpans,
InsufficientNumberOfEdges,
MergeVertexOutside,
InvalidNumberOfEdgesBelowVertex,
ErrorCode(i16),
}

#[cfg(feature = "std")]
impl core::fmt::Display for InternalError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
InternalError::IncorrectActiveEdgeOrder(i) => {
std::write!(f, "Incorrect active edge order ({i})")
},
InternalError::InsufficientNumberOfSpans => {
std::write!(f, "Insufficient number of spans")
},
InternalError::InsufficientNumberOfEdges => {
std::write!(f, "Insufficient number of edges")
},
InternalError::MergeVertexOutside => {
std::write!(f, "Merge vertex is outside of the shape")
},
InternalError::InvalidNumberOfEdgesBelowVertex => {
std::write!(f, "Unexpected number of edges below a vertex")
},
InternalError::ErrorCode(i) => {
std::write!(f, "Error code: #{i}")
},
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for InternalError {}

/// The fill tessellator's error enumeration.
#[derive(Clone, Debug, PartialEq)]
pub enum TessellationError {
// TODO Parameter typo
UnsupportedParamater(UnsupportedParamater),
GeometryBuilder(GeometryBuilderError),
Internal(InternalError),
}

#[cfg(feature = "std")]
impl core::fmt::Display for TessellationError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
TessellationError::UnsupportedParamater(e) => {
std::write!(f, "Unsupported parameter: {e}")
},
TessellationError::GeometryBuilder(e) => {
std::write!(f, "Geometry builder error: {e}")
},
TessellationError::Internal(e) => {
std::write!(f, "Internal error: {e}")
},
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for TessellationError {}

impl core::convert::From<GeometryBuilderError> for TessellationError {
fn from(value: GeometryBuilderError) -> Self {
Self::GeometryBuilder(value)
}
}

impl core::convert::From<InternalError> for TessellationError {
fn from(value: InternalError) -> Self {
Self::Internal(value)
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum UnsupportedParamater {
PositionIsNaN,
ToleranceIsNaN,
}

#[cfg(feature = "std")]
impl core::fmt::Display for UnsupportedParamater {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
UnsupportedParamater::PositionIsNaN => {
std::write!(f, "Position is not a number")
},
UnsupportedParamater::ToleranceIsNaN => {
std::write!(f, "Tolerance threshold is not a number")
},
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for UnsupportedParamater {}
21 changes: 11 additions & 10 deletions crates/tessellation/src/event_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use crate::path::private::DebugValidator;
use crate::path::{EndpointId, IdEvent, PathEvent, PositionStore};
use crate::Orientation;

use std::cmp::Ordering;
use std::mem::swap;
use std::ops::Range;
use core::cmp::Ordering;
use core::mem::swap;
use core::ops::Range;
use alloc::vec::Vec;

#[inline]
fn reorient(p: Point) -> Point {
Expand All @@ -27,7 +28,7 @@ pub(crate) struct Event {
#[derive(Clone, Debug)]
pub(crate) struct EdgeData {
pub to: Point,
pub range: std::ops::Range<f32>,
pub range: core::ops::Range<f32>,
pub winding: i16,
pub is_edge: bool,
pub from_id: EndpointId,
Expand Down Expand Up @@ -412,26 +413,26 @@ impl EventQueue {
current_sibling
}

#[cfg(debug_assertions)]
#[cfg(all(debug_assertions, feature = "std"))]
fn log(&self) {
let mut iter_count = self.events.len() * self.events.len();

println!("--");
std::println!("--");
let mut current = self.first;
while (current as usize) < self.events.len() {
assert!(iter_count > 0);
iter_count -= 1;

print!("[");
std::print!("[");
let mut current_sibling = current;
while (current_sibling as usize) < self.events.len() {
print!("{:?},", self.events[current_sibling as usize].position);
std::print!("{:?},", self.events[current_sibling as usize].position);
current_sibling = self.events[current_sibling as usize].next_sibling;
}
print!("] ");
std::print!("] ");
current = self.events[current as usize].next_event;
}
println!("\n--");
std::println!("\n--");
}

fn assert_sorted(&self) {
Expand Down
45 changes: 24 additions & 21 deletions crates/tessellation/src/fill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ use crate::{
UnsupportedParamater, VertexSource,
};
use float_next_after::NextAfter;
use std::cmp::Ordering;
use std::f32::consts::FRAC_1_SQRT_2;
use std::mem;
use std::ops::Range;
use core::cmp::Ordering;
use core::f32::consts::FRAC_1_SQRT_2;
use core::mem;
use core::ops::Range;
use alloc::boxed::Box;
use alloc::vec::Vec;

#[cfg(debug_assertions)]
use std::env;
#[cfg(not(feature = "std"))]
use num_traits::Float;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum Side {
Expand Down Expand Up @@ -63,21 +65,21 @@ fn slope(v: Vector) -> f32 {
v.x / (v.y.max(f32::MIN))
}

#[cfg(debug_assertions)]
#[cfg(all(debug_assertions, feature = "std"))]
macro_rules! tess_log {
($obj:ident, $fmt:expr) => (
if $obj.log {
println!($fmt);
std::println!($fmt);
}
);
($obj:ident, $fmt:expr, $($arg:tt)*) => (
if $obj.log {
println!($fmt, $($arg)*);
std::println!($fmt, $($arg)*);
}
);
}

#[cfg(not(debug_assertions))]
#[cfg(not(all(debug_assertions, feature = "std")))]
macro_rules! tess_log {
($obj:ident, $fmt:expr) => {};
($obj:ident, $fmt:expr, $($arg:tt)*) => {};
Expand Down Expand Up @@ -545,9 +547,9 @@ impl Default for FillTessellator {
impl FillTessellator {
/// Constructor.
pub fn new() -> Self {
#[cfg(debug_assertions)]
let log = env::var("LYON_FORCE_LOGGING").is_ok();
#[cfg(not(debug_assertions))]
#[cfg(all(debug_assertions, feature = "std"))]
let log = std::env::var("LYON_FORCE_LOGGING").is_ok();
#[cfg(not(all(debug_assertions, feature = "std")))]
let log = false;

FillTessellator {
Expand Down Expand Up @@ -579,7 +581,7 @@ impl FillTessellator {
options: &FillOptions,
output: &mut dyn FillGeometryBuilder,
) -> TessellationResult {
let event_queue = std::mem::replace(&mut self.events, EventQueue::new());
let event_queue = core::mem::replace(&mut self.events, EventQueue::new());
let mut queue_builder = event_queue.into_builder(options.tolerance);

queue_builder.set_path(
Expand All @@ -604,7 +606,7 @@ impl FillTessellator {
options: &FillOptions,
output: &mut dyn FillGeometryBuilder,
) -> TessellationResult {
let event_queue = std::mem::replace(&mut self.events, EventQueue::new());
let event_queue = core::mem::replace(&mut self.events, EventQueue::new());
let mut queue_builder = event_queue.into_builder(options.tolerance);

queue_builder.set_path_with_ids(
Expand Down Expand Up @@ -808,10 +810,10 @@ impl FillTessellator {
/// Enable/disable some verbose logging during the tessellation, for
/// debugging purposes.
pub fn set_logging(&mut self, is_enabled: bool) {
#[cfg(debug_assertions)]
let forced = env::var("LYON_FORCE_LOGGING").is_ok();
#[cfg(all(debug_assertions, feature = "std"))]
let forced = std::env::var("LYON_FORCE_LOGGING").is_ok();

#[cfg(not(debug_assertions))]
#[cfg(not(all(debug_assertions, feature = "std")))]
let forced = false;

self.log = is_enabled || forced;
Expand Down Expand Up @@ -2341,7 +2343,7 @@ impl<'l> FillBuilder<'l> {
options: &'l FillOptions,
output: &'l mut dyn FillGeometryBuilder,
) -> Self {
let events = std::mem::replace(&mut tessellator.events, EventQueue::new())
let events = core::mem::replace(&mut tessellator.events, EventQueue::new())
.into_builder(options.tolerance);

FillBuilder {
Expand Down Expand Up @@ -2509,7 +2511,7 @@ impl<'l> FillBuilder<'l> {

pub fn build(self) -> TessellationResult {
let mut event_queue = self.events.build();
std::mem::swap(&mut self.tessellator.events, &mut event_queue);
core::mem::swap(&mut self.tessellator.events, &mut event_queue);

let attrib_store = if self.attrib_store.num_attributes > 0 {
Some(&self.attrib_store as &dyn AttributeStore)
Expand Down Expand Up @@ -2833,8 +2835,9 @@ fn fill_vertex_source_02() {
fn assert_attr(a: Attributes, b: Attributes) {
for i in 0..a.len() {
let are_equal = (a[i] - b[i]).abs() < 0.001;
#[cfg(feature = "std")]
if !are_equal {
println!("{a:?} != {b:?}");
std::println!("{a:?} != {b:?}");
}
assert!(are_equal);
}
Expand Down
Loading

0 comments on commit 001d713

Please sign in to comment.