lyon_path/
commands.rs

1//! A generic representation for paths that allow more control over how
2//! endpoints and control points are stored.
3//!
4//! # Motivation
5//!
6//! The default `Path` data structure in this crate is works well for the
7//! most common use cases. Sometimes, however, it is useful to be able to
8//! specify exactly how endpoints and control points are stored instead of
9//! relying on implicitly following the order of the events.
10//!
11//! This module contains bricks to help with building custom path representations.
12//! The central piece is the [`PathCommands`](struct.PathCommands.html) buffer and
13//! its [`PathCommandsBuilder`](struct.PathCommandsBuilder.html), providing a compact
14//! representation for path events with IDs instead of positions.
15//!
16//! # Examples
17//!
18//! The following example shows how `PathCommands` can be used together with an
19//! external buffers for positions to implement features similar to the default
20//! Path type with a different data structure.
21//!
22//! ```
23//! use lyon_path::{EndpointId, Event, IdEvent, commands::PathCommands};
24//! let points = &[
25//!     [0.0, 0.0],
26//!     [1.0, 1.0],
27//!     [0.0, 2.0],
28//! ];
29//!
30//! let mut cmds = PathCommands::builder();
31//! cmds.begin(EndpointId(0));
32//! cmds.line_to(EndpointId(1));
33//! cmds.line_to(EndpointId(2));
34//! cmds.end(true);
35//!
36//! let cmds = cmds.build();
37//!
38//! for event in &cmds {
39//!     match event {
40//!         IdEvent::Begin { at } => { println!("move to {:?}", points[at.to_usize()]); }
41//!         IdEvent::Line { to, .. } => { println!("line to {:?}", points[to.to_usize()]); }
42//!         IdEvent::End { close: true, .. } => { println!("close"); }
43//!         _ => { panic!("unexpected event!") }
44//!     }
45//! }
46//!
47//! // Iterate over the points directly using CommandsPathSlice
48//! for event in cmds.path_slice(points, points).events() {
49//!     match event {
50//!         Event::Begin { at } => { println!("move to {:?}", at); }
51//!         Event::Line { to, .. } => { println!("line to {:?}", to); }
52//!         Event::End { close: true, .. } => { println!("close"); }
53//!         _ => { panic!("unexpected event!") }
54//!     }
55//! }
56//!
57//! ```
58
59use crate::events::{Event, IdEvent, PathEvent};
60use crate::math::Point;
61use crate::{ControlPointId, EndpointId, EventId, Position, PositionStore};
62
63use core::fmt;
64
65use crate::private::DebugValidator;
66use alloc::boxed::Box;
67use alloc::vec::Vec;
68
69// Note: Tried making the path generic over the integer type used to store
70// the commands to allow u16 and u32, but the performance difference is very
71// small and not worth the added complexity.
72
73mod verb {
74    pub const LINE: u32 = 0;
75    pub const QUADRATIC: u32 = 1;
76    pub const CUBIC: u32 = 2;
77    pub const BEGIN: u32 = 3;
78    pub const CLOSE: u32 = 4;
79    pub const END: u32 = 5;
80}
81
82/// Sadly this is very close to core::slice::Iter but reimplementing
83/// it manually to iterate over u32 makes a difference.
84/// It would seem that having next return u32 with a special value
85/// for the end of the iteration instead of Option<u32> should
86/// improve performance (simpler code and a bunch of unwraps removed),
87/// however a naive initial attempt led to worse performance.
88#[derive(Copy, Clone)]
89struct CmdIter<'l> {
90    ptr: *const u32,
91    end: *const u32,
92    _marker: core::marker::PhantomData<&'l u32>,
93}
94
95impl<'l> CmdIter<'l> {
96    fn new(slice: &'l [u32]) -> Self {
97        let ptr = slice.as_ptr();
98        let end = unsafe { ptr.add(slice.len()) };
99        CmdIter {
100            ptr,
101            end,
102            _marker: core::marker::PhantomData,
103        }
104    }
105
106    #[inline]
107    fn next(&mut self) -> Option<u32> {
108        unsafe {
109            if self.ptr == self.end {
110                return None;
111            }
112
113            let val = *self.ptr;
114            self.ptr = self.ptr.offset(1);
115
116            Some(val)
117        }
118    }
119}
120
121/// The commands of a path encoded in a single array using IDs to refer
122/// to endpoints and control points externally.
123///
124/// `PathCommands` is a good fit when the a custom endpoint and control point
125/// types are needed or when their the user needs full control over their storage.
126///
127/// # Representation
128///
129/// Path commands contains a single array of 32 bits integer values encoding path
130/// commands, endpoint IDs or control point IDs.
131///
132/// ```ascii
133///  __________________________________________________________________________
134/// |       |          |      |          |         |              |          |
135/// | Begin |EndpointID| Line |EndpointID|Quadratic|ControlPointId|EndpointID| ...
136/// |_______|__________|______|__________|_________|______________|__________|_
137///
138/// ```
139///
140/// # Example
141///
142/// ```
143/// use lyon_path::{EndpointId, PathCommands};
144///
145/// let mut cmds = PathCommands::builder();
146///
147/// cmds.begin(EndpointId(0));
148/// cmds.line_to(EndpointId(1));
149/// cmds.line_to(EndpointId(2));
150/// cmds.end(true);
151///
152/// let cmds = cmds.build();
153///
154#[derive(Clone)]
155#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
156pub struct PathCommands {
157    cmds: Box<[u32]>,
158}
159
160impl PathCommands {
161    /// Creates a [PathCommandsBuilder](struct.PathCommandsBuilder.html) to create path commands.
162    pub fn builder() -> PathCommandsBuilder {
163        PathCommandsBuilder::new()
164    }
165
166    /// Returns an iterator over the path commands.
167    pub fn iter(&self) -> Iter {
168        Iter::new(&self.cmds)
169    }
170
171    /// Returns a view on the path commands.
172    pub fn as_slice(&self) -> PathCommandsSlice {
173        PathCommandsSlice { cmds: &self.cmds }
174    }
175
176    /// Returns a view on a path made of these commands with endpoint and
177    /// control point slices.
178    pub fn path_slice<'l, Endpoint, ControlPoint>(
179        &'l self,
180        endpoints: &'l [Endpoint],
181        control_points: &'l [ControlPoint],
182    ) -> CommandsPathSlice<Endpoint, ControlPoint> {
183        CommandsPathSlice {
184            endpoints,
185            control_points,
186            cmds: self.as_slice(),
187        }
188    }
189
190    /// Returns an iterator over the path, with endpoints and control points.
191    pub fn events<'l, Endpoint, ControlPoint>(
192        &'l self,
193        endpoints: &'l [Endpoint],
194        control_points: &'l [ControlPoint],
195    ) -> Events<Endpoint, ControlPoint> {
196        Events {
197            cmds: CmdIter::new(&self.cmds),
198            first_endpoint: 0,
199            prev_endpoint: 0,
200            endpoints,
201            control_points,
202        }
203    }
204
205    /// Returns the event for a given event ID.
206    pub fn event(&self, id: EventId) -> IdEvent {
207        self.as_slice().event(id)
208    }
209
210    /// Returns the next event id within the path.
211    pub fn next_event_id_in_path(&self, id: EventId) -> Option<EventId> {
212        self.as_slice().next_event_id_in_path(id)
213    }
214
215    /// Returns the next event id within the sub-path.
216    ///
217    /// Loops back to the first event after the end of the sub-path.
218    pub fn next_event_id_in_sub_path(&self, id: EventId) -> EventId {
219        self.as_slice().next_event_id_in_sub_path(id)
220    }
221}
222
223impl fmt::Debug for PathCommands {
224    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225        self.as_slice().fmt(f)
226    }
227}
228
229impl<'l> IntoIterator for &'l PathCommands {
230    type Item = IdEvent;
231    type IntoIter = Iter<'l>;
232
233    fn into_iter(self) -> Iter<'l> {
234        self.iter()
235    }
236}
237
238impl<'l> From<&'l PathCommands> for PathCommandsSlice<'l> {
239    fn from(commands: &'l PathCommands) -> Self {
240        commands.as_slice()
241    }
242}
243
244/// A view over [`PathCommands`](struct.PathCommands.html).
245#[derive(Copy, Clone)]
246pub struct PathCommandsSlice<'l> {
247    cmds: &'l [u32],
248}
249
250impl<'l> PathCommandsSlice<'l> {
251    /// Returns an iterator over the path commands.
252    pub fn iter(&self) -> Iter {
253        Iter::new(self.cmds)
254    }
255
256    /// Returns the event for a given event ID.
257    pub fn event(&self, id: EventId) -> IdEvent {
258        let idx = id.to_usize();
259        match self.cmds[idx] {
260            verb::LINE => IdEvent::Line {
261                from: EndpointId(self.cmds[idx - 1]),
262                to: EndpointId(self.cmds[idx + 1]),
263            },
264            verb::QUADRATIC => IdEvent::Quadratic {
265                from: EndpointId(self.cmds[idx - 1]),
266                ctrl: ControlPointId(self.cmds[idx + 1]),
267                to: EndpointId(self.cmds[idx + 2]),
268            },
269            verb::CUBIC => IdEvent::Cubic {
270                from: EndpointId(self.cmds[idx - 1]),
271                ctrl1: ControlPointId(self.cmds[idx + 1]),
272                ctrl2: ControlPointId(self.cmds[idx + 2]),
273                to: EndpointId(self.cmds[idx + 3]),
274            },
275            verb::BEGIN => IdEvent::Begin {
276                at: EndpointId(self.cmds[idx + 1]),
277            },
278            verb::END => {
279                let first_event = self.cmds[idx + 1] as usize;
280                IdEvent::End {
281                    last: EndpointId(self.cmds[idx - 1]),
282                    first: EndpointId(self.cmds[first_event + 1]),
283                    close: false,
284                }
285            }
286            _ => {
287                // CLOSE
288                let first_event = self.cmds[idx + 1] as usize;
289                IdEvent::End {
290                    last: EndpointId(self.cmds[idx - 1]),
291                    first: EndpointId(self.cmds[first_event + 1]),
292                    close: true,
293                }
294            }
295        }
296    }
297
298    /// Returns the next event id within the path.
299    pub fn next_event_id_in_sub_path(&self, id: EventId) -> EventId {
300        let idx = id.to_usize();
301        match self.cmds[idx] {
302            verb::LINE | verb::BEGIN => EventId(id.0 + 2),
303            verb::QUADRATIC => EventId(id.0 + 3),
304            verb::CUBIC => EventId(id.0 + 4),
305            //verb::END | verb::CLOSE
306            _ => EventId(self.cmds[idx + 1]),
307        }
308    }
309
310    /// Returns the next event id within the path.
311    pub fn next_event_id_in_path(&self, id: EventId) -> Option<EventId> {
312        let idx = id.to_usize();
313        let next = match self.cmds[idx] {
314            verb::QUADRATIC => EventId(id.0 + 3),
315            verb::CUBIC => EventId(id.0 + 4),
316            // verb::LINE | verb::BEGIN | verb::END | verb::CLOSE
317            _ => EventId(id.0 + 2),
318        };
319
320        if next.0 < self.cmds.len() as u32 {
321            return Some(next);
322        }
323
324        None
325    }
326}
327
328impl<'l> fmt::Debug for PathCommandsSlice<'l> {
329    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
330        write!(f, "\"")?;
331        for evt in self.iter() {
332            match evt {
333                IdEvent::Line { to, .. } => write!(f, "L {to:?}"),
334                IdEvent::Quadratic { ctrl, to, .. } => write!(f, "Q {ctrl:?} {to:?} "),
335                IdEvent::Cubic {
336                    ctrl1, ctrl2, to, ..
337                } => write!(f, "C {ctrl1:?} {ctrl2:?} {to:?} "),
338                IdEvent::Begin { at, .. } => write!(f, "M {at:?} "),
339                IdEvent::End { close: true, .. } => write!(f, "Z "),
340                IdEvent::End { close: false, .. } => Ok(()),
341            }?;
342        }
343        write!(f, "\"")
344    }
345}
346
347/// A view on a [`PathCommands`](struct.PathCommands.html) buffer and
348/// two slices for endpoints and control points, providing similar
349/// functionalities as `PathSlice`.
350#[derive(Copy, Clone)]
351pub struct CommandsPathSlice<'l, Endpoint, ControlPoint> {
352    endpoints: &'l [Endpoint],
353    control_points: &'l [ControlPoint],
354    cmds: PathCommandsSlice<'l>,
355}
356
357impl<'l, Endpoint, ControlPoint> CommandsPathSlice<'l, Endpoint, ControlPoint> {
358    /// Returns an iterator over the events of the path using IDs.
359    pub fn iter(&self) -> Iter {
360        self.cmds.iter()
361    }
362
363    /// Returns an iterator over the events of the path using endpoint
364    /// and control point references.
365    pub fn events(&self) -> Events<Endpoint, ControlPoint> {
366        Events {
367            cmds: CmdIter::new(self.cmds.cmds),
368            first_endpoint: 0,
369            prev_endpoint: 0,
370            endpoints: self.endpoints,
371            control_points: self.control_points,
372        }
373    }
374}
375
376impl<'l, Endpoint, ControlPoint> core::ops::Index<EndpointId>
377    for CommandsPathSlice<'l, Endpoint, ControlPoint>
378{
379    type Output = Endpoint;
380    fn index(&self, id: EndpointId) -> &Endpoint {
381        &self.endpoints[id.to_usize()]
382    }
383}
384
385impl<'l, Endpoint, ControlPoint> core::ops::Index<ControlPointId>
386    for CommandsPathSlice<'l, Endpoint, ControlPoint>
387{
388    type Output = ControlPoint;
389    fn index(&self, id: ControlPointId) -> &ControlPoint {
390        &self.control_points[id.to_usize()]
391    }
392}
393
394impl<'l, Endpoint, ControlPoint> fmt::Debug for CommandsPathSlice<'l, Endpoint, ControlPoint>
395where
396    Endpoint: fmt::Debug,
397    ControlPoint: fmt::Debug,
398{
399    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400        write!(f, "{{ ")?;
401        for evt in self.events() {
402            match evt {
403                Event::Line { to, .. } => write!(f, "L {to:?}"),
404                Event::Quadratic { ctrl, to, .. } => write!(f, "Q {ctrl:?} {to:?} "),
405                Event::Cubic {
406                    ctrl1, ctrl2, to, ..
407                } => write!(f, "C {ctrl1:?} {ctrl2:?} {to:?} "),
408                Event::Begin { at, .. } => write!(f, "M {at:?} "),
409                Event::End { close: true, .. } => write!(f, "Z "),
410                Event::End { close: false, .. } => Ok(()),
411            }?;
412        }
413        write!(f, "}}")
414    }
415}
416
417/// Builds path commands.
418///
419/// See [`PathCommands`](struct.PathCommands.html).
420#[derive(Debug, Default, Clone)]
421pub struct PathCommandsBuilder {
422    cmds: Vec<u32>,
423    first_event_index: u32,
424    validator: DebugValidator,
425}
426
427impl PathCommandsBuilder {
428    /// Creates a builder without allocating memory.
429    pub fn new() -> Self {
430        Self::default()
431    }
432
433    /// Creates a pre-allocated builder.
434    pub fn with_capacity(cap: usize) -> Self {
435        Self {
436            cmds: Vec::with_capacity(cap),
437            ..Self::default()
438        }
439    }
440
441    pub fn begin(&mut self, to: EndpointId) -> EventId {
442        self.validator.begin();
443
444        self.first_event_index = self.cmds.len() as u32;
445        let id = EventId(self.cmds.len() as u32);
446        self.cmds.push(verb::BEGIN);
447        self.cmds.push(to.0);
448
449        id
450    }
451
452    pub fn end(&mut self, close: bool) -> Option<EventId> {
453        self.validator.end();
454
455        let id = EventId(self.cmds.len() as u32);
456        let cmd = if close { verb::CLOSE } else { verb::END };
457        self.cmds.push(cmd);
458        self.cmds.push(self.first_event_index);
459
460        Some(id)
461    }
462
463    pub fn line_to(&mut self, to: EndpointId) -> EventId {
464        self.validator.edge();
465
466        let id = EventId(self.cmds.len() as u32);
467        self.cmds.push(verb::LINE);
468        self.cmds.push(to.0);
469
470        id
471    }
472
473    pub fn quadratic_bezier_to(&mut self, ctrl: ControlPointId, to: EndpointId) -> EventId {
474        self.validator.edge();
475
476        let id = EventId(self.cmds.len() as u32);
477        self.cmds.push(verb::QUADRATIC);
478        self.cmds.push(ctrl.0);
479        self.cmds.push(to.0);
480
481        id
482    }
483
484    pub fn cubic_bezier_to(
485        &mut self,
486        ctrl1: ControlPointId,
487        ctrl2: ControlPointId,
488        to: EndpointId,
489    ) -> EventId {
490        self.validator.edge();
491
492        let id = EventId(self.cmds.len() as u32);
493        self.cmds.push(verb::CUBIC);
494        self.cmds.push(ctrl1.0);
495        self.cmds.push(ctrl2.0);
496        self.cmds.push(to.0);
497
498        id
499    }
500
501    /// Consumes the builder and returns path commands.
502    pub fn build(self) -> PathCommands {
503        self.validator.build();
504
505        PathCommands {
506            cmds: self.cmds.into_boxed_slice(),
507        }
508    }
509}
510
511/// An iterator of `Event<&Endpoint, &ControlPoint>`.
512#[derive(Clone)]
513pub struct Events<'l, Endpoint, ControlPoint> {
514    cmds: CmdIter<'l>,
515    prev_endpoint: usize,
516    first_endpoint: usize,
517    endpoints: &'l [Endpoint],
518    control_points: &'l [ControlPoint],
519}
520
521impl<'l, Endpoint, ControlPoint> Iterator for Events<'l, Endpoint, ControlPoint> {
522    type Item = Event<&'l Endpoint, &'l ControlPoint>;
523
524    #[inline]
525    fn next(&mut self) -> Option<Event<&'l Endpoint, &'l ControlPoint>> {
526        match self.cmds.next() {
527            Some(verb::BEGIN) => {
528                let to = self.cmds.next().unwrap() as usize;
529                self.prev_endpoint = to;
530                self.first_endpoint = to;
531                Some(Event::Begin {
532                    at: &self.endpoints[to],
533                })
534            }
535            Some(verb::LINE) => {
536                let to = self.cmds.next().unwrap() as usize;
537                let from = self.prev_endpoint;
538                self.prev_endpoint = to;
539                Some(Event::Line {
540                    from: &self.endpoints[from],
541                    to: &self.endpoints[to],
542                })
543            }
544            Some(verb::QUADRATIC) => {
545                let ctrl = self.cmds.next().unwrap() as usize;
546                let to = self.cmds.next().unwrap() as usize;
547                let from = self.prev_endpoint;
548                self.prev_endpoint = to;
549                Some(Event::Quadratic {
550                    from: &self.endpoints[from],
551                    ctrl: &self.control_points[ctrl],
552                    to: &self.endpoints[to],
553                })
554            }
555            Some(verb::CUBIC) => {
556                let ctrl1 = self.cmds.next().unwrap() as usize;
557                let ctrl2 = self.cmds.next().unwrap() as usize;
558                let to = self.cmds.next().unwrap() as usize;
559                let from = self.prev_endpoint;
560                self.prev_endpoint = to;
561                Some(Event::Cubic {
562                    from: &self.endpoints[from],
563                    ctrl1: &self.control_points[ctrl1],
564                    ctrl2: &self.control_points[ctrl2],
565                    to: &self.endpoints[to],
566                })
567            }
568            Some(verb::END) => {
569                let _first_index = self.cmds.next();
570                let last = self.prev_endpoint;
571                let first = self.first_endpoint;
572                self.prev_endpoint = first;
573                Some(Event::End {
574                    last: &self.endpoints[last],
575                    first: &self.endpoints[first],
576                    close: false,
577                })
578            }
579            Some(_) => {
580                // CLOSE
581                let _first_index = self.cmds.next();
582                let last = self.prev_endpoint;
583                let first = self.first_endpoint;
584                self.prev_endpoint = first;
585                Some(Event::End {
586                    last: &self.endpoints[last],
587                    first: &self.endpoints[first],
588                    close: true,
589                })
590            }
591            None => None,
592        }
593    }
594}
595
596impl<'l, Ep, Cp> Events<'l, Ep, Cp>
597where
598    Ep: Position,
599    Cp: Position,
600{
601    pub fn points(self) -> PointEvents<'l, Ep, Cp> {
602        PointEvents {
603            cmds: self.cmds,
604            prev_endpoint: self.prev_endpoint,
605            first_endpoint: self.first_endpoint,
606            endpoints: self.endpoints,
607            control_points: self.control_points,
608        }
609    }
610}
611/// An iterator of `Event<&Endpoint, &ControlPoint>`.
612#[derive(Clone)]
613pub struct Iter<'l> {
614    cmds: CmdIter<'l>,
615    idx: u32,
616    prev_endpoint: EndpointId,
617    first_endpoint: EndpointId,
618}
619
620impl<'l> Iter<'l> {
621    fn new(cmds: &'l [u32]) -> Self {
622        Iter {
623            cmds: CmdIter::new(cmds),
624            idx: 0,
625            prev_endpoint: EndpointId(0),
626            first_endpoint: EndpointId(0),
627        }
628    }
629}
630
631impl<'l> Iterator for Iter<'l> {
632    type Item = IdEvent;
633
634    #[inline]
635    fn next(&mut self) -> Option<IdEvent> {
636        match self.cmds.next() {
637            Some(verb::BEGIN) => {
638                let to = EndpointId(self.cmds.next().unwrap());
639                self.prev_endpoint = to;
640                self.first_endpoint = to;
641                self.idx += 2;
642                Some(IdEvent::Begin { at: to })
643            }
644            Some(verb::LINE) => {
645                let to = EndpointId(self.cmds.next().unwrap());
646                let from = self.prev_endpoint;
647                self.prev_endpoint = to;
648                self.idx += 2;
649                Some(IdEvent::Line { from, to })
650            }
651            Some(verb::QUADRATIC) => {
652                let ctrl = ControlPointId(self.cmds.next().unwrap());
653                let to = EndpointId(self.cmds.next().unwrap());
654                let from = self.prev_endpoint;
655                self.prev_endpoint = to;
656                self.idx += 3;
657                Some(IdEvent::Quadratic { from, ctrl, to })
658            }
659            Some(verb::CUBIC) => {
660                let ctrl1 = ControlPointId(self.cmds.next().unwrap());
661                let ctrl2 = ControlPointId(self.cmds.next().unwrap());
662                let to = EndpointId(self.cmds.next().unwrap());
663                let from = self.prev_endpoint;
664                self.prev_endpoint = to;
665                self.idx += 4;
666                Some(IdEvent::Cubic {
667                    from,
668                    ctrl1,
669                    ctrl2,
670                    to,
671                })
672            }
673            Some(verb::END) => {
674                let _first_index = self.cmds.next();
675                let last = self.prev_endpoint;
676                let first = self.first_endpoint;
677                self.prev_endpoint = first;
678                self.idx += 2;
679                Some(IdEvent::End {
680                    last,
681                    first,
682                    close: false,
683                })
684            }
685            Some(_) => {
686                let _first_index = self.cmds.next();
687                let last = self.prev_endpoint;
688                let first = self.first_endpoint;
689                self.prev_endpoint = first;
690                self.idx += 2;
691                Some(IdEvent::End {
692                    last,
693                    first,
694                    close: true,
695                })
696            }
697            None => None,
698        }
699    }
700}
701
702/// An iterator of `PathEvent`.
703#[derive(Clone)]
704pub struct PointEvents<'l, Endpoint, ControlPoint> {
705    cmds: CmdIter<'l>,
706    prev_endpoint: usize,
707    first_endpoint: usize,
708    endpoints: &'l [Endpoint],
709    control_points: &'l [ControlPoint],
710}
711
712impl<'l, Endpoint, ControlPoint> Iterator for PointEvents<'l, Endpoint, ControlPoint>
713where
714    Endpoint: Position,
715    ControlPoint: Position,
716{
717    type Item = PathEvent;
718
719    #[inline]
720    fn next(&mut self) -> Option<PathEvent> {
721        match self.cmds.next() {
722            Some(verb::BEGIN) => {
723                let to = self.cmds.next().unwrap() as usize;
724                self.prev_endpoint = to;
725                self.first_endpoint = to;
726                Some(Event::Begin {
727                    at: self.endpoints[to].position(),
728                })
729            }
730            Some(verb::LINE) => {
731                let to = self.cmds.next().unwrap() as usize;
732                let from = self.prev_endpoint;
733                self.prev_endpoint = to;
734                Some(Event::Line {
735                    from: self.endpoints[from].position(),
736                    to: self.endpoints[to].position(),
737                })
738            }
739            Some(verb::QUADRATIC) => {
740                let ctrl = self.cmds.next().unwrap() as usize;
741                let to = self.cmds.next().unwrap() as usize;
742                let from = self.prev_endpoint;
743                self.prev_endpoint = to;
744                Some(Event::Quadratic {
745                    from: self.endpoints[from].position(),
746                    ctrl: self.control_points[ctrl].position(),
747                    to: self.endpoints[to].position(),
748                })
749            }
750            Some(verb::CUBIC) => {
751                let ctrl1 = self.cmds.next().unwrap() as usize;
752                let ctrl2 = self.cmds.next().unwrap() as usize;
753                let to = self.cmds.next().unwrap() as usize;
754                let from = self.prev_endpoint;
755                self.prev_endpoint = to;
756                Some(Event::Cubic {
757                    from: self.endpoints[from].position(),
758                    ctrl1: self.control_points[ctrl1].position(),
759                    ctrl2: self.control_points[ctrl2].position(),
760                    to: self.endpoints[to].position(),
761                })
762            }
763            Some(verb::END) => {
764                let _first_index = self.cmds.next();
765                let last = self.prev_endpoint;
766                let first = self.first_endpoint;
767                self.prev_endpoint = first;
768                Some(Event::End {
769                    last: self.endpoints[last].position(),
770                    first: self.endpoints[first].position(),
771                    close: false,
772                })
773            }
774            Some(_) => {
775                let _first_index = self.cmds.next();
776                let last = self.prev_endpoint;
777                let first = self.first_endpoint;
778                self.prev_endpoint = first;
779                Some(Event::End {
780                    last: self.endpoints[last].position(),
781                    first: self.endpoints[first].position(),
782                    close: true,
783                })
784            }
785            None => None,
786        }
787    }
788}
789
790impl<'l, Endpoint, ControlPoint> PositionStore for CommandsPathSlice<'l, Endpoint, ControlPoint>
791where
792    Endpoint: Position,
793    ControlPoint: Position,
794{
795    fn get_endpoint(&self, id: EndpointId) -> Point {
796        self[id].position()
797    }
798
799    fn get_control_point(&self, id: ControlPointId) -> Point {
800        self[id].position()
801    }
802}
803
804#[cfg(debug_assertions)]
805#[test]
806#[should_panic]
807fn missing_begin_1() {
808    let mut builder = PathCommands::builder();
809    builder.line_to(EndpointId(1));
810    builder.end(true);
811
812    builder.build();
813}
814
815#[cfg(debug_assertions)]
816#[test]
817#[should_panic]
818fn missing_begin_2() {
819    let mut builder = PathCommands::builder();
820    builder.begin(EndpointId(0));
821    builder.line_to(EndpointId(1));
822    builder.end(true);
823
824    builder.line_to(EndpointId(1));
825    builder.end(true);
826
827    builder.build();
828}
829
830#[cfg(debug_assertions)]
831#[test]
832#[should_panic]
833fn missing_end() {
834    let mut builder = PathCommands::builder();
835    builder.begin(EndpointId(0));
836    builder.line_to(EndpointId(1));
837
838    builder.build();
839}
840
841#[test]
842fn simple_path() {
843    let mut builder = PathCommands::builder();
844    builder.begin(EndpointId(0));
845    builder.line_to(EndpointId(1));
846    builder.quadratic_bezier_to(ControlPointId(2), EndpointId(3));
847    builder.cubic_bezier_to(ControlPointId(4), ControlPointId(5), EndpointId(6));
848    builder.end(false);
849
850    builder.begin(EndpointId(10));
851    builder.line_to(EndpointId(11));
852    builder.quadratic_bezier_to(ControlPointId(12), EndpointId(13));
853    builder.cubic_bezier_to(ControlPointId(14), ControlPointId(15), EndpointId(16));
854    builder.end(true);
855
856    builder.begin(EndpointId(20));
857    builder.line_to(EndpointId(21));
858    builder.quadratic_bezier_to(ControlPointId(22), EndpointId(23));
859    builder.cubic_bezier_to(ControlPointId(24), ControlPointId(25), EndpointId(26));
860    builder.end(false);
861
862    let path = builder.build();
863    let mut iter = path.iter();
864    assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(0) }));
865    assert_eq!(
866        iter.next(),
867        Some(IdEvent::Line {
868            from: EndpointId(0),
869            to: EndpointId(1)
870        })
871    );
872    assert_eq!(
873        iter.next(),
874        Some(IdEvent::Quadratic {
875            from: EndpointId(1),
876            ctrl: ControlPointId(2),
877            to: EndpointId(3)
878        })
879    );
880    assert_eq!(
881        iter.next(),
882        Some(IdEvent::Cubic {
883            from: EndpointId(3),
884            ctrl1: ControlPointId(4),
885            ctrl2: ControlPointId(5),
886            to: EndpointId(6)
887        })
888    );
889    assert_eq!(
890        iter.next(),
891        Some(IdEvent::End {
892            last: EndpointId(6),
893            first: EndpointId(0),
894            close: false
895        })
896    );
897
898    assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(10) }));
899    assert_eq!(
900        iter.next(),
901        Some(IdEvent::Line {
902            from: EndpointId(10),
903            to: EndpointId(11)
904        })
905    );
906    assert_eq!(
907        iter.next(),
908        Some(IdEvent::Quadratic {
909            from: EndpointId(11),
910            ctrl: ControlPointId(12),
911            to: EndpointId(13)
912        })
913    );
914    assert_eq!(
915        iter.next(),
916        Some(IdEvent::Cubic {
917            from: EndpointId(13),
918            ctrl1: ControlPointId(14),
919            ctrl2: ControlPointId(15),
920            to: EndpointId(16)
921        })
922    );
923    assert_eq!(
924        iter.next(),
925        Some(IdEvent::End {
926            last: EndpointId(16),
927            first: EndpointId(10),
928            close: true
929        })
930    );
931
932    assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(20) }));
933    assert_eq!(
934        iter.next(),
935        Some(IdEvent::Line {
936            from: EndpointId(20),
937            to: EndpointId(21)
938        })
939    );
940    assert_eq!(
941        iter.next(),
942        Some(IdEvent::Quadratic {
943            from: EndpointId(21),
944            ctrl: ControlPointId(22),
945            to: EndpointId(23)
946        })
947    );
948    assert_eq!(
949        iter.next(),
950        Some(IdEvent::Cubic {
951            from: EndpointId(23),
952            ctrl1: ControlPointId(24),
953            ctrl2: ControlPointId(25),
954            to: EndpointId(26)
955        })
956    );
957    assert_eq!(
958        iter.next(),
959        Some(IdEvent::End {
960            last: EndpointId(26),
961            first: EndpointId(20),
962            close: false
963        })
964    );
965
966    assert_eq!(iter.next(), None);
967}
968
969#[test]
970fn next_event() {
971    let mut builder = PathCommands::builder();
972    builder.begin(EndpointId(0));
973    builder.line_to(EndpointId(1));
974    builder.quadratic_bezier_to(ControlPointId(2), EndpointId(3));
975    builder.cubic_bezier_to(ControlPointId(4), ControlPointId(5), EndpointId(6));
976    builder.end(false);
977
978    builder.begin(EndpointId(10));
979    builder.line_to(EndpointId(11));
980    builder.quadratic_bezier_to(ControlPointId(12), EndpointId(13));
981    builder.cubic_bezier_to(ControlPointId(14), ControlPointId(15), EndpointId(16));
982    builder.end(true);
983
984    builder.begin(EndpointId(20));
985    builder.line_to(EndpointId(21));
986    builder.quadratic_bezier_to(ControlPointId(22), EndpointId(23));
987    builder.cubic_bezier_to(ControlPointId(24), ControlPointId(25), EndpointId(26));
988    builder.end(false);
989
990    let path = builder.build();
991
992    let mut id = EventId(0);
993    let first = id;
994    assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(0) });
995    id = path.next_event_id_in_path(id).unwrap();
996    assert_eq!(
997        path.event(id),
998        IdEvent::Line {
999            from: EndpointId(0),
1000            to: EndpointId(1)
1001        }
1002    );
1003    id = path.next_event_id_in_path(id).unwrap();
1004    assert_eq!(
1005        path.event(id),
1006        IdEvent::Quadratic {
1007            from: EndpointId(1),
1008            ctrl: ControlPointId(2),
1009            to: EndpointId(3)
1010        }
1011    );
1012    id = path.next_event_id_in_path(id).unwrap();
1013    assert_eq!(
1014        path.event(id),
1015        IdEvent::Cubic {
1016            from: EndpointId(3),
1017            ctrl1: ControlPointId(4),
1018            ctrl2: ControlPointId(5),
1019            to: EndpointId(6)
1020        }
1021    );
1022    id = path.next_event_id_in_path(id).unwrap();
1023    assert_eq!(
1024        path.event(id),
1025        IdEvent::End {
1026            last: EndpointId(6),
1027            first: EndpointId(0),
1028            close: false
1029        }
1030    );
1031
1032    assert_eq!(path.next_event_id_in_sub_path(id), first);
1033
1034    id = path.next_event_id_in_path(id).unwrap();
1035    let first = id;
1036    assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(10) });
1037    id = path.next_event_id_in_path(id).unwrap();
1038    assert_eq!(
1039        path.event(id),
1040        IdEvent::Line {
1041            from: EndpointId(10),
1042            to: EndpointId(11)
1043        }
1044    );
1045    id = path.next_event_id_in_path(id).unwrap();
1046    assert_eq!(
1047        path.event(id),
1048        IdEvent::Quadratic {
1049            from: EndpointId(11),
1050            ctrl: ControlPointId(12),
1051            to: EndpointId(13)
1052        }
1053    );
1054    id = path.next_event_id_in_path(id).unwrap();
1055    assert_eq!(
1056        path.event(id),
1057        IdEvent::Cubic {
1058            from: EndpointId(13),
1059            ctrl1: ControlPointId(14),
1060            ctrl2: ControlPointId(15),
1061            to: EndpointId(16)
1062        }
1063    );
1064    id = path.next_event_id_in_path(id).unwrap();
1065    assert_eq!(
1066        path.event(id),
1067        IdEvent::End {
1068            last: EndpointId(16),
1069            first: EndpointId(10),
1070            close: true
1071        }
1072    );
1073
1074    assert_eq!(path.next_event_id_in_sub_path(id), first);
1075
1076    id = path.next_event_id_in_path(id).unwrap();
1077    let first = id;
1078    assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(20) });
1079    id = path.next_event_id_in_path(id).unwrap();
1080    assert_eq!(
1081        path.event(id),
1082        IdEvent::Line {
1083            from: EndpointId(20),
1084            to: EndpointId(21)
1085        }
1086    );
1087    id = path.next_event_id_in_path(id).unwrap();
1088    assert_eq!(
1089        path.event(id),
1090        IdEvent::Quadratic {
1091            from: EndpointId(21),
1092            ctrl: ControlPointId(22),
1093            to: EndpointId(23)
1094        }
1095    );
1096    id = path.next_event_id_in_path(id).unwrap();
1097    assert_eq!(
1098        path.event(id),
1099        IdEvent::Cubic {
1100            from: EndpointId(23),
1101            ctrl1: ControlPointId(24),
1102            ctrl2: ControlPointId(25),
1103            to: EndpointId(26)
1104        }
1105    );
1106    id = path.next_event_id_in_path(id).unwrap();
1107    assert_eq!(
1108        path.event(id),
1109        IdEvent::End {
1110            last: EndpointId(26),
1111            first: EndpointId(20),
1112            close: false
1113        }
1114    );
1115
1116    assert_eq!(path.next_event_id_in_path(id), None);
1117    assert_eq!(path.next_event_id_in_sub_path(id), first);
1118}