lyon_path/
path_buffer.rs

1//! A container to store multiple paths contiguously.
2
3use crate::builder::*;
4use crate::math::*;
5use crate::path;
6use crate::{Attributes, EndpointId, PathSlice, NO_ATTRIBUTES};
7
8use core::fmt;
9use core::iter::{FromIterator, FusedIterator, IntoIterator};
10use core::ops::Range;
11
12use alloc::vec::Vec;
13
14#[derive(Clone, Debug)]
15struct PathDescriptor {
16    points: (u32, u32),
17    verbs: (u32, u32),
18    num_attributes: u32,
19}
20
21/// An object that stores multiple paths contiguously.
22#[derive(Clone, Default)]
23pub struct PathBuffer {
24    points: Vec<Point>,
25    verbs: Vec<path::Verb>,
26    paths: Vec<PathDescriptor>,
27}
28
29impl PathBuffer {
30    #[inline]
31    pub fn new() -> Self {
32        PathBuffer {
33            points: Vec::new(),
34            verbs: Vec::new(),
35            paths: Vec::new(),
36        }
37    }
38
39    #[inline]
40    pub fn with_capacity(endpoints: usize, ctrl_points: usize, paths: usize) -> Self {
41        let mut buffer = PathBuffer::new();
42        buffer.reserve(endpoints, ctrl_points, paths);
43
44        buffer
45    }
46
47    #[inline]
48    pub fn as_slice(&self) -> PathBufferSlice {
49        PathBufferSlice {
50            points: &self.points,
51            verbs: &self.verbs,
52            paths: &self.paths,
53        }
54    }
55
56    #[inline]
57    pub fn get(&self, index: usize) -> PathSlice {
58        let desc = &self.paths[index];
59        PathSlice {
60            points: &self.points[desc.points.0 as usize..desc.points.1 as usize],
61            verbs: &self.verbs[desc.verbs.0 as usize..desc.verbs.1 as usize],
62            num_attributes: desc.num_attributes as usize,
63        }
64    }
65
66    #[inline]
67    pub fn indices(&self) -> Range<usize> {
68        0..self.paths.len()
69    }
70
71    #[inline]
72    pub fn iter(&self) -> Iter<'_> {
73        Iter::new(&self.points, &self.verbs, &self.paths)
74    }
75
76    #[inline]
77    /// Returns the number of paths in the path buffer.
78    pub fn len(&self) -> usize {
79        self.paths.len()
80    }
81
82    /// Returns whether the path buffer is empty.
83    #[inline]
84    pub fn is_empty(&self) -> bool {
85        self.paths.is_empty()
86    }
87
88    #[inline]
89    pub fn builder(&mut self) -> Builder {
90        Builder::new(self)
91    }
92
93    #[inline]
94    pub fn clear(&mut self) {
95        self.points.clear();
96        self.verbs.clear();
97        self.paths.clear();
98    }
99
100    #[inline]
101    pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize, paths: usize) {
102        self.points.reserve(endpoints + ctrl_points);
103        self.verbs.reserve(endpoints);
104        self.paths.reserve(paths);
105    }
106}
107
108impl fmt::Debug for PathBuffer {
109    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
110        self.as_slice().fmt(formatter)
111    }
112}
113
114impl<'l> FromIterator<PathSlice<'l>> for PathBuffer {
115    fn from_iter<T: IntoIterator<Item = PathSlice<'l>>>(iter: T) -> PathBuffer {
116        iter.into_iter()
117            .fold(PathBuffer::new(), |mut buffer, path| {
118                let builder = buffer.builder();
119                path.iter()
120                    .fold(builder, |mut builder, event| {
121                        builder.path_event(event, NO_ATTRIBUTES);
122                        builder
123                    })
124                    .build();
125                buffer
126            })
127    }
128}
129
130/// A view on a `PathBuffer`.
131#[derive(Clone)]
132pub struct PathBufferSlice<'l> {
133    points: &'l [Point],
134    verbs: &'l [path::Verb],
135    paths: &'l [PathDescriptor],
136}
137
138impl<'l> PathBufferSlice<'l> {
139    #[inline]
140    pub fn get(&self, index: usize) -> PathSlice {
141        let desc = &self.paths[index];
142        PathSlice {
143            points: &self.points[desc.points.0 as usize..desc.points.1 as usize],
144            verbs: &self.verbs[desc.verbs.0 as usize..desc.verbs.1 as usize],
145            num_attributes: desc.num_attributes as usize,
146        }
147    }
148
149    #[inline]
150    pub fn indices(&self) -> Range<usize> {
151        0..self.paths.len()
152    }
153
154    #[inline]
155    pub fn iter(&self) -> Iter<'_> {
156        Iter::new(self.points, self.verbs, self.paths)
157    }
158
159    /// Returns the number of paths in the path buffer.
160    #[inline]
161    pub fn len(&self) -> usize {
162        self.paths.len()
163    }
164
165    /// Returns whether the path buffer is empty.
166    #[inline]
167    pub fn is_empty(&self) -> bool {
168        self.paths.is_empty()
169    }
170}
171
172impl<'l> fmt::Debug for PathBufferSlice<'l> {
173    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
174        write!(
175            formatter,
176            "PathBuffer {{ paths: {:?}, points: {:?}, verbs: {:?}, ",
177            self.paths.len(),
178            self.points.len(),
179            self.verbs.len(),
180        )?;
181        for idx in self.indices() {
182            write!(formatter, "#{idx:?}: ")?;
183            self.get(idx).fmt(formatter)?;
184            write!(formatter, ", ")?;
185        }
186        write!(formatter, " }}")
187    }
188}
189
190/// A Builder that appends a path to an existing PathBuffer.
191///
192/// Implements the `PathBuilder` trait.
193pub struct Builder<'l> {
194    buffer: &'l mut PathBuffer,
195    builder: path::Builder,
196    points_start: u32,
197    verbs_start: u32,
198}
199
200impl<'l> Builder<'l> {
201    #[inline]
202    fn new(buffer: &'l mut PathBuffer) -> Self {
203        let mut builder = path::Path::builder();
204        core::mem::swap(&mut buffer.points, &mut builder.inner_mut().points);
205        core::mem::swap(&mut buffer.verbs, &mut builder.inner_mut().verbs);
206        let points_start = builder.inner().points.len() as u32;
207        let verbs_start = builder.inner().verbs.len() as u32;
208        Builder {
209            buffer,
210            builder,
211            points_start,
212            verbs_start,
213        }
214    }
215
216    #[inline]
217    pub fn with_attributes(self, num_attributes: usize) -> BuilderWithAttributes<'l> {
218        assert_eq!(self.builder.inner().verbs.len(), self.verbs_start as usize);
219
220        BuilderWithAttributes {
221            buffer: self.buffer,
222            builder: path::BuilderWithAttributes {
223                builder: self.builder.into_inner(),
224                num_attributes,
225                first_attributes: alloc::vec![0.0; num_attributes],
226            },
227            points_start: self.points_start,
228            verbs_start: self.verbs_start,
229        }
230    }
231
232    #[inline]
233    pub fn build(mut self) -> usize {
234        let points_end = self.builder.inner().points.len() as u32;
235        let verbs_end = self.builder.inner().verbs.len() as u32;
236        core::mem::swap(
237            &mut self.builder.inner_mut().points,
238            &mut self.buffer.points,
239        );
240        core::mem::swap(&mut self.builder.inner_mut().verbs, &mut self.buffer.verbs);
241
242        let index = self.buffer.paths.len();
243        self.buffer.paths.push(PathDescriptor {
244            points: (self.points_start, points_end),
245            verbs: (self.verbs_start, verbs_end),
246            num_attributes: 0,
247        });
248
249        index
250    }
251
252    #[inline]
253    fn adjust_id(&self, mut id: EndpointId) -> EndpointId {
254        id.0 -= self.points_start;
255
256        id
257    }
258
259    #[inline]
260    pub fn begin(&mut self, at: Point) -> EndpointId {
261        let id = self.builder.begin(at);
262        self.adjust_id(id)
263    }
264
265    #[inline]
266    pub fn end(&mut self, close: bool) {
267        self.builder.end(close)
268    }
269
270    #[inline]
271    pub fn line_to(&mut self, to: Point) -> EndpointId {
272        let id = self.builder.line_to(to);
273        self.adjust_id(id)
274    }
275
276    #[inline]
277    pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId {
278        let id = self.builder.quadratic_bezier_to(ctrl, to);
279        self.adjust_id(id)
280    }
281
282    #[inline]
283    pub fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId {
284        let id = self.builder.cubic_bezier_to(ctrl1, ctrl2, to);
285        self.adjust_id(id)
286    }
287
288    #[inline]
289    pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
290        self.builder.reserve(endpoints, ctrl_points);
291    }
292}
293
294impl<'l> PathBuilder for Builder<'l> {
295    #[inline]
296    fn num_attributes(&self) -> usize {
297        0
298    }
299
300    #[inline]
301    fn begin(&mut self, at: Point, _attributes: Attributes) -> EndpointId {
302        self.begin(at)
303    }
304
305    #[inline]
306    fn end(&mut self, close: bool) {
307        self.end(close);
308    }
309
310    #[inline]
311    fn line_to(&mut self, to: Point, _attributes: Attributes) -> EndpointId {
312        self.line_to(to)
313    }
314
315    #[inline]
316    fn quadratic_bezier_to(
317        &mut self,
318        ctrl: Point,
319        to: Point,
320        _attributes: Attributes,
321    ) -> EndpointId {
322        self.quadratic_bezier_to(ctrl, to)
323    }
324
325    #[inline]
326    fn cubic_bezier_to(
327        &mut self,
328        ctrl1: Point,
329        ctrl2: Point,
330        to: Point,
331        _attributes: Attributes,
332    ) -> EndpointId {
333        self.cubic_bezier_to(ctrl1, ctrl2, to)
334    }
335
336    #[inline]
337    fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
338        self.reserve(endpoints, ctrl_points);
339    }
340}
341
342impl<'l> Build for Builder<'l> {
343    type PathType = usize;
344    fn build(self) -> usize {
345        self.build()
346    }
347}
348
349/// A Builder that appends a path to an existing PathBuffer, with custom attributes.
350pub struct BuilderWithAttributes<'l> {
351    buffer: &'l mut PathBuffer,
352    builder: path::BuilderWithAttributes,
353    points_start: u32,
354    verbs_start: u32,
355}
356
357impl<'l> BuilderWithAttributes<'l> {
358    #[inline]
359    pub fn new(buffer: &'l mut PathBuffer, num_attributes: usize) -> Self {
360        let mut builder = path::Path::builder().into_inner();
361        core::mem::swap(&mut buffer.points, &mut builder.points);
362        core::mem::swap(&mut buffer.verbs, &mut builder.verbs);
363        let points_start = builder.points.len() as u32;
364        let verbs_start = builder.verbs.len() as u32;
365        BuilderWithAttributes {
366            buffer,
367            builder: path::BuilderWithAttributes {
368                builder,
369                num_attributes,
370                first_attributes: alloc::vec![0.0; num_attributes],
371            },
372            points_start,
373            verbs_start,
374        }
375    }
376
377    #[inline]
378    pub fn build(mut self) -> usize {
379        let points_end = self.builder.builder.points.len() as u32;
380        let verbs_end = self.builder.builder.verbs.len() as u32;
381        core::mem::swap(&mut self.builder.builder.points, &mut self.buffer.points);
382        core::mem::swap(&mut self.builder.builder.verbs, &mut self.buffer.verbs);
383
384        let index = self.buffer.paths.len();
385        self.buffer.paths.push(PathDescriptor {
386            points: (self.points_start, points_end),
387            verbs: (self.verbs_start, verbs_end),
388            num_attributes: 0,
389        });
390
391        index
392    }
393
394    #[inline]
395    fn adjust_id(&self, mut id: EndpointId) -> EndpointId {
396        id.0 -= self.points_start;
397
398        id
399    }
400
401    #[inline]
402    pub fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId {
403        let id = self.builder.begin(at, attributes);
404        self.adjust_id(id)
405    }
406
407    #[inline]
408    pub fn end(&mut self, close: bool) {
409        self.builder.end(close)
410    }
411
412    #[inline]
413    pub fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId {
414        let id = self.builder.line_to(to, attributes);
415        self.adjust_id(id)
416    }
417
418    #[inline]
419    pub fn quadratic_bezier_to(
420        &mut self,
421        ctrl: Point,
422        to: Point,
423        attributes: Attributes,
424    ) -> EndpointId {
425        let id = self.builder.quadratic_bezier_to(ctrl, to, attributes);
426        self.adjust_id(id)
427    }
428
429    #[inline]
430    pub fn cubic_bezier_to(
431        &mut self,
432        ctrl1: Point,
433        ctrl2: Point,
434        to: Point,
435        attributes: Attributes,
436    ) -> EndpointId {
437        let id = self.builder.cubic_bezier_to(ctrl1, ctrl2, to, attributes);
438        self.adjust_id(id)
439    }
440
441    #[inline]
442    pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
443        self.builder.reserve(endpoints, ctrl_points);
444    }
445}
446
447impl<'l> PathBuilder for BuilderWithAttributes<'l> {
448    #[inline]
449    fn num_attributes(&self) -> usize {
450        self.builder.num_attributes()
451    }
452
453    #[inline]
454    fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId {
455        self.begin(at, attributes)
456    }
457
458    #[inline]
459    fn end(&mut self, close: bool) {
460        self.end(close);
461    }
462
463    #[inline]
464    fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId {
465        self.line_to(to, attributes)
466    }
467
468    #[inline]
469    fn quadratic_bezier_to(
470        &mut self,
471        ctrl: Point,
472        to: Point,
473        attributes: Attributes,
474    ) -> EndpointId {
475        self.quadratic_bezier_to(ctrl, to, attributes)
476    }
477
478    #[inline]
479    fn cubic_bezier_to(
480        &mut self,
481        ctrl1: Point,
482        ctrl2: Point,
483        to: Point,
484        attributes: Attributes,
485    ) -> EndpointId {
486        self.cubic_bezier_to(ctrl1, ctrl2, to, attributes)
487    }
488
489    #[inline]
490    fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
491        self.reserve(endpoints, ctrl_points);
492    }
493}
494
495impl<'l> Build for BuilderWithAttributes<'l> {
496    type PathType = usize;
497    fn build(self) -> usize {
498        self.build()
499    }
500}
501
502/// Iterator over the paths in a [`PathBufferSlice`].
503#[derive(Clone)]
504pub struct Iter<'l> {
505    points: &'l [Point],
506    verbs: &'l [path::Verb],
507    paths: ::core::slice::Iter<'l, PathDescriptor>,
508}
509
510impl<'l> Iter<'l> {
511    fn new(points: &'l [Point], verbs: &'l [path::Verb], paths: &'l [PathDescriptor]) -> Iter<'l> {
512        Iter {
513            points,
514            verbs,
515            paths: paths.iter(),
516        }
517    }
518}
519
520impl<'l> Iterator for Iter<'l> {
521    type Item = PathSlice<'l>;
522
523    fn next(&mut self) -> Option<PathSlice<'l>> {
524        let path = self.paths.next()?;
525        Some(PathSlice {
526            points: &self.points[path.points.0 as usize..path.points.1 as usize],
527            verbs: &self.verbs[path.verbs.0 as usize..path.verbs.1 as usize],
528            num_attributes: path.num_attributes as usize,
529        })
530    }
531
532    fn size_hint(&self) -> (usize, Option<usize>) {
533        self.paths.size_hint()
534    }
535}
536
537// slice::Iter is Fused and ExactSize
538impl<'l> FusedIterator for Iter<'l> {}
539impl<'l> ExactSizeIterator for Iter<'l> {}
540
541impl<'l> DoubleEndedIterator for Iter<'l> {
542    fn next_back(&mut self) -> Option<PathSlice<'l>> {
543        let path = self.paths.next_back()?;
544        Some(PathSlice {
545            points: &self.points[path.points.0 as usize..path.points.1 as usize],
546            verbs: &self.verbs[path.verbs.0 as usize..path.verbs.1 as usize],
547            num_attributes: path.num_attributes as usize,
548        })
549    }
550}
551
552#[test]
553fn simple() {
554    use crate::PathEvent;
555
556    let mut buffer = PathBuffer::new();
557
558    let mut builder = buffer.builder();
559    builder.begin(point(0.0, 0.0));
560    builder.line_to(point(10.0, 0.0));
561    builder.line_to(point(10.0, 10.0));
562    let a = builder.line_to(point(0.0, 10.0));
563    builder.end(true);
564
565    let p1 = builder.build();
566
567    let mut builder = buffer.builder();
568    builder.begin(point(0.0, 0.0));
569    builder.line_to(point(20.0, 0.0));
570    builder.line_to(point(20.0, 20.0));
571    let b = builder.line_to(point(0.0, 20.0));
572    builder.end(false);
573
574    let p2 = builder.build();
575
576    let mut iter = buffer.get(p1).iter();
577    assert_eq!(
578        iter.next(),
579        Some(PathEvent::Begin {
580            at: point(0.0, 0.0)
581        })
582    );
583    assert_eq!(
584        iter.next(),
585        Some(PathEvent::Line {
586            from: point(0.0, 0.0),
587            to: point(10.0, 0.0)
588        })
589    );
590    assert_eq!(
591        iter.next(),
592        Some(PathEvent::Line {
593            from: point(10.0, 0.0),
594            to: point(10.0, 10.0)
595        })
596    );
597    assert_eq!(
598        iter.next(),
599        Some(PathEvent::Line {
600            from: point(10.0, 10.0),
601            to: point(0.0, 10.0)
602        })
603    );
604    assert_eq!(
605        iter.next(),
606        Some(PathEvent::End {
607            last: point(0.0, 10.0),
608            first: point(0.0, 0.0),
609            close: true
610        })
611    );
612    assert_eq!(iter.next(), None);
613
614    let mut iter = buffer.get(p2).iter();
615    assert_eq!(
616        iter.next(),
617        Some(PathEvent::Begin {
618            at: point(0.0, 0.0)
619        })
620    );
621    assert_eq!(
622        iter.next(),
623        Some(PathEvent::Line {
624            from: point(0.0, 0.0),
625            to: point(20.0, 0.0)
626        })
627    );
628    assert_eq!(
629        iter.next(),
630        Some(PathEvent::Line {
631            from: point(20.0, 0.0),
632            to: point(20.0, 20.0)
633        })
634    );
635    assert_eq!(
636        iter.next(),
637        Some(PathEvent::Line {
638            from: point(20.0, 20.0),
639            to: point(0.0, 20.0)
640        })
641    );
642    assert_eq!(
643        iter.next(),
644        Some(PathEvent::End {
645            last: point(0.0, 20.0),
646            first: point(0.0, 0.0),
647            close: false
648        })
649    );
650    assert_eq!(iter.next(), None);
651
652    assert_eq!(buffer.get(p1)[a], point(0.0, 10.0));
653    assert_eq!(buffer.get(p2)[b], point(0.0, 20.0));
654}