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 {}