1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
use std::mem;
use crate::Shape;
/// A 2-dimensional shape
#[derive(Clone, Debug)]
#[repr(C)]
pub enum Shape2d {
/// A circle
Circle(Circle),
/// A difference between two shapes
Difference(Box<Difference2d>),
/// A sketch
Sketch(Sketch),
}
/// A circle
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Circle {
/// The radius of the circle
pub radius: f64,
}
impl From<Circle> for Shape {
fn from(shape: Circle) -> Self {
Self::Shape2d(Shape2d::Circle(shape))
}
}
impl From<Circle> for Shape2d {
fn from(shape: Circle) -> Self {
Self::Circle(shape)
}
}
/// A difference between two shapes
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Difference2d {
/// The original shape
pub a: Shape2d,
/// The shape being subtracted
pub b: Shape2d,
}
impl From<Difference2d> for Shape {
fn from(shape: Difference2d) -> Self {
Self::Shape2d(Shape2d::Difference(Box::new(shape)))
}
}
impl From<Difference2d> for Shape2d {
fn from(shape: Difference2d) -> Self {
Self::Difference(Box::new(shape))
}
}
/// A sketch
///
/// Sketches are currently limited to a single cycle of straight lines,
/// represented by a number of points. For example, if the points a, b, and c
/// are provided, the edges ab, bc, and ca are assumed.
///
/// Nothing about these edges is checked right now, but algorithms might assume
/// that the edges are non-overlapping. If you create a `Sketch` with
/// overlapping edges, you're on your own.
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Sketch {
// The fields are the raw parts of a `Vec`. `Sketch` needs to be FFI-safe,
// meaning it can't store a `Vec` directly. It needs to take this detour.
ptr: *mut [f64; 2],
length: usize,
capacity: usize,
}
impl Sketch {
/// Create a sketch from a bunch of points
pub fn from_points(mut points: Vec<[f64; 2]>) -> Self {
// This can be cleaned up, once `Vec::into_raw_parts` is stable.
let ptr = points.as_mut_ptr();
let length = points.len();
let capacity = points.capacity();
// We're taking ownership of the memory here, so we can't allow `points`
// to deallocate it.
mem::forget(points);
Self {
ptr,
length,
capacity,
}
}
/// Return the points of the sketch
pub fn to_points(&self) -> Vec<[f64; 2]> {
// This is sound. All invariants are automatically kept, as the raw
// parts come from an original `Vec` that is identical to the new one we
// create here, and aren't being modified anywhere.
let points = unsafe {
Vec::from_raw_parts(self.ptr, self.length, self.capacity)
};
// Ownership of the pointer in `self.raw_parts` transferred to `points`.
// We work around that, by returning a clone of `points` (hence not
// giving ownership to the caller).
let ret = points.clone();
// Now we just need to forget that `points` ever existed, and we keep
// ownership of the pointer.
mem::forget(points);
ret
}
}
impl From<Sketch> for Shape {
fn from(shape: Sketch) -> Self {
Self::Shape2d(Shape2d::Sketch(shape))
}
}
impl From<Sketch> for Shape2d {
fn from(shape: Sketch) -> Self {
Self::Sketch(shape)
}
}
// `Sketch` can be `Send`, because it encapsulates the raw pointer it contains,
// making sure memory ownership rules are observed.
unsafe impl Send for Sketch {}