1#![allow(clippy::needless_lifetimes)]
4
5use super::command::Command;
6use super::geometry::*;
7use super::path_builder::*;
8use super::segment::*;
9use super::style::*;
10#[allow(unused)]
11use super::F32Ext;
12
13use crate::lib::Vec;
14use core::borrow::Borrow;
15
16pub fn stroke_into<'a, I>(commands: I, style: &Stroke<'a>, sink: &mut impl PathBuilder)
17where
18 I: Iterator + Clone,
19 I::Item: Borrow<Command>,
20{
21 let mut stroker = Stroker::new(segments(commands, true), sink, style);
22 let (dashes, dash_offset, empty_gaps) = validate_dashes(style.dashes, style.offset);
23 let mut segment_buf = SmallBuf::new();
24 if !dashes.is_empty() {
25 stroker.dash(&mut segment_buf, dashes, dash_offset, empty_gaps);
26 } else {
27 stroker.stroke(&mut segment_buf);
28 }
29}
30
31pub fn stroke_with_storage<'a, I>(
32 commands: I,
33 style: &Stroke<'a>,
34 sink: &mut impl PathBuilder,
35 storage: &mut impl StrokerStorage,
36) where
37 I: Iterator + Clone,
38 I::Item: Borrow<Command>,
39{
40 let mut stroker = Stroker::new(segments(commands, true), sink, style);
41 let (dashes, dash_offset, empty_gaps) = validate_dashes(style.dashes, style.offset);
42 if !dashes.is_empty() {
43 stroker.dash(storage, dashes, dash_offset, empty_gaps);
44 } else {
45 stroker.stroke(storage);
46 }
47}
48
49pub struct Stroker<'a, I, S> {
50 source: Segments<I>,
51 sink: &'a mut S,
52 radius: f32,
53 radius_abs: f32,
54 join: Join,
55 inv_miter_limit: f32,
56 start_cap: Cap,
57 end_cap: Cap,
58}
59
60impl<'a, I, S> Stroker<'a, I, S>
61where
62 I: Iterator + Clone,
63 I::Item: Borrow<Command>,
64 S: PathBuilder,
65{
66 pub(super) fn new(source: Segments<I>, sink: &'a mut S, style: &Stroke) -> Self {
67 let radius = style.width.max(0.01) * 0.5;
68 Self {
69 source,
70 sink,
71 radius,
72 radius_abs: radius.abs(),
73 join: style.join,
74 inv_miter_limit: if style.miter_limit >= 1. {
75 1. / style.miter_limit
76 } else {
77 1.
78 },
79 start_cap: style.start_cap,
80 end_cap: style.end_cap,
81 }
82 }
83
84 fn stroke(&mut self, segment_buf: &mut impl StrokerStorage) {
85 loop {
86 let (closed, done) = segment_buf.collect(&mut self.source);
87 self.stroke_segments(segment_buf.get(), closed);
88 if done {
89 break;
90 }
91 }
92 }
93
94 fn stroke_segments(&mut self, segments: &[Segment], is_closed: bool) {
95 let len = segments.len();
96 if len == 0 {
97 return;
98 }
99 if len == 1
100 && segments[0].length() == 0.
101 && (self.start_cap != Cap::Butt || self.end_cap != Cap::Butt)
102 {
103 let segment = segments[0];
104 let from = match &segment {
105 Segment::Line(_, line) => line.a,
106 Segment::Curve(_, curve) => curve.a,
107 Segment::End(..) => Point::ZERO,
108 };
109 let n = Vector::new(0., 1.);
110 let nr = n * self.radius;
111 let start = from + nr;
112 let rstart = from - nr;
113 self.sink.move_to(start);
114 self.add_end_cap(start, rstart, n);
115 self.add_start_cap(rstart, start, n * -1.);
116 return;
117 }
118 let radius = self.radius;
119 let mut last_dir = Vector::ZERO;
120 let mut first_point = Point::ZERO;
121 let mut last_point = Point::ZERO;
122 let mut pivot = Point::ZERO;
123 let mut last_id = 0xFF;
124 if is_closed {
125 let segment = segments[len - 1].offset(radius);
126 let end_point = segment.end;
127 let out_dir = segment.end_normal;
128 pivot = segment.end_pivot;
129 last_dir = out_dir;
130 last_point = end_point;
131 first_point = end_point;
132 self.sink.move_to(last_point);
133 }
134 let mut is_first = !is_closed;
136 for segment in segments {
137 let segment = segment.offset(radius);
138 let id = segment.id;
139 let start = segment.start;
140 if is_first {
141 self.sink.move_to(start);
142 first_point = start;
143 is_first = false;
144 } else {
145 self.add_join(last_point, start, pivot, last_dir, segment.start_normal);
146 }
147 last_id = id;
148 last_dir = segment.end_normal;
149 pivot = segment.end_pivot;
150 last_point = self.emit(&segment.segment);
151 }
152 is_first = true;
154 for segment in segments.iter().rev() {
155 let segment = segment.reverse().offset(radius);
156 let id = segment.id;
157 let start = segment.start;
158 if is_first {
159 if is_closed {
160 let init = segments[0].reverse().offset(self.radius);
161 last_point = init.end;
162 last_dir = init.end_normal;
163 pivot = init.end_pivot;
164 self.sink.line_to(init.end);
165 self.add_join(last_point, start, pivot, last_dir, segment.start_normal);
166 } else {
167 self.add_end_cap(last_point, start, last_dir);
168 }
169 is_first = false;
170 } else if id != last_id {
171 self.add_join(last_point, start, pivot, last_dir, segment.start_normal);
172 } else {
173 self.add_split_join(last_point, start, pivot, last_dir, segment.start_normal);
174 };
175 last_id = id;
176 last_dir = segment.end_normal;
177 pivot = segment.end_pivot;
178 last_point = self.emit(&segment.segment);
179 }
180 if !is_closed {
181 self.add_start_cap(last_point, first_point, last_dir);
182 }
183 self.sink.close();
184 }
185
186 #[allow(clippy::field_reassign_with_default)]
187 fn dash(
188 &mut self,
189 segment_buf: &mut impl StrokerStorage,
190 dashes: &[f32],
191 offset: f32,
192 empty_gaps: bool,
193 ) {
194 let mut dasher = Dasher::default();
195 dasher.empty_gaps = empty_gaps;
196 let mut done = false;
197 while !done {
198 let (is_closed, is_done) = segment_buf.collect(&mut self.source);
199 done = is_done;
200 let segments = segment_buf.get();
201 if segments.is_empty() {
202 continue;
203 }
204 dasher.init(is_closed, dashes, offset);
205 loop {
206 match dasher.next(segments, dashes) {
207 DashOp::Done => break,
208 DashOp::Continue => {}
209 DashOp::Emit => {
210 let (start, end) = dasher.range;
211 let (t0, t1) = dasher.trange;
212 self.dash_segments(segments, start, end, t0, t1);
213 }
214 DashOp::Stroke => {
215 self.stroke_segments(segments, true);
216 break;
217 }
218 }
219 }
220 }
221 }
222
223 fn dash_segments(&mut self, segments: &[Segment], start: isize, end: isize, t0: f32, t1: f32) {
224 let radius = self.radius;
225 if t0 == t1 && start == end {
226 if self.start_cap == Cap::Butt && self.end_cap == Cap::Butt {
227 return;
228 }
229 let (t0, t1) = if t0 >= 1. {
230 (t0 - 0.001, t0)
231 } else {
232 (t0, t0 + 0.001)
233 };
234 let segment = get_signed(segments, start).slice(t0, t1).offset(radius);
235 let start = segment.start;
236 let rstart = segment.start - (segment.start_normal * (2. * radius));
237 self.sink.move_to(start);
238 self.add_end_cap(start, rstart, segment.start_normal);
239 self.add_start_cap(rstart, start, segment.start_normal * -1.);
240 self.sink.close();
241 return;
242 }
243 let mut last_dir = Vector::ZERO;
244 let mut first_point = Point::ZERO;
245 let mut last_point = Point::ZERO;
246 let mut pivot = Point::ZERO;
247 let mut is_first = true;
248 let mut last_id = 0xFF;
249 for i in start..=end {
250 let t0 = if i == start { t0 } else { 0. };
251 let t1 = if i == end { t1 } else { 1. };
252 if t0 >= 1. {
253 continue;
254 }
255 let segment = get_signed(segments, i).slice(t0, t1).offset(radius);
256 let id = segment.id;
257 let start = segment.start;
258 if is_first {
259 self.sink.move_to(start);
260 first_point = start;
261 is_first = false;
262 } else if id != last_id {
263 self.add_join(last_point, start, pivot, last_dir, segment.start_normal);
264 } else {
265 self.add_split_join(last_point, start, pivot, last_dir, segment.start_normal);
266 };
267 last_id = id;
268 pivot = segment.end_pivot;
269 last_dir = segment.end_normal;
270 last_point = self.emit(&segment.segment);
271 }
272 is_first = true;
273 last_id = 0xFF;
274 for i in (start..=end).rev() {
275 let t0 = if i == start { t0 } else { 0. };
276 let t1 = if i == end { t1 } else { 1. };
277 if t0 >= 1. {
278 continue;
279 }
280 let segment = get_signed(segments, i)
281 .slice(t0, t1)
282 .reverse()
283 .offset(radius);
284 let id = segment.id;
285 let start = segment.start;
286 if is_first {
287 self.add_end_cap(last_point, start, last_dir);
288 is_first = false;
289 } else if id != last_id {
290 self.add_join(last_point, start, pivot, last_dir, segment.start_normal);
291 } else {
292 self.add_split_join(last_point, start, pivot, last_dir, segment.start_normal);
293 };
294 last_id = id;
295 pivot = segment.end_pivot;
296 last_dir = segment.end_normal;
297 last_point = self.emit(&segment.segment);
298 }
299 self.add_start_cap(last_point, first_point, last_dir);
300 self.sink.close();
301 }
302
303 #[inline(always)]
304 fn emit(&mut self, segment: &Segment) -> Point {
305 match segment {
306 Segment::Line(_, line) => {
307 self.sink.line_to(line.b);
308 line.b
309 }
310 Segment::Curve(_, curve) => {
311 self.sink.curve_to(curve.b, curve.c, curve.d);
312 curve.d
313 }
314 _ => Point::ZERO,
315 }
316 }
317
318 fn add_join(
319 &mut self,
320 from: Point,
321 to: Point,
322 pivot: Point,
323 from_normal: Vector,
324 to_normal: Vector,
325 ) -> Point {
326 if from.nearly_eq(to) {
327 return from;
328 }
329 if !is_clockwise(from_normal, to_normal) {
330 self.sink.line_to(pivot);
331 self.sink.line_to(to);
332 return to;
333 }
334 match self.join {
335 Join::Bevel => {
336 self.sink.line_to(to);
337 to
338 }
339 Join::Round => {
340 let r = self.radius_abs;
341 let (size, sweep) = (ArcSize::Small, ArcSweep::Positive);
342 arc(self.sink, from, r, r, 0., size, sweep, to);
343 to
344 }
345 Join::Miter => {
346 let inv_limit = self.inv_miter_limit;
347 let dot = from_normal.dot(to_normal);
348 let sin_half = ((1. + dot) * 0.5).sqrt();
349 if dot < 0.0 || sin_half < inv_limit {
350 self.sink.line_to(to);
351 to
352 } else {
353 let mid = (from_normal + to_normal).normalize() * (self.radius / sin_half);
354 let p = pivot + mid;
355 self.sink.line_to(p);
356 self.sink.line_to(to);
357 to
358 }
359 }
360 }
361 }
362
363 fn add_split_join(
364 &mut self,
365 from: Point,
366 to: Point,
367 pivot: Point,
368 from_normal: Vector,
369 to_normal: Vector,
370 ) -> Point {
371 if from.nearly_eq(to) {
372 return from;
373 }
374 if !is_clockwise(from_normal, to_normal) {
375 self.sink.line_to(pivot);
376 self.sink.line_to(to);
377 return to;
378 }
379 let r = self.radius_abs;
380 let (size, sweep) = (ArcSize::Small, ArcSweep::Positive);
381 arc(self.sink, from, r, r, 0., size, sweep, to);
382 to
383 }
384
385 fn add_cap(&mut self, from: Point, to: Point, dir: Vector, cap: Cap) {
386 match cap {
387 Cap::Butt => {
388 self.sink.line_to(to);
389 }
390 Cap::Square => {
391 let dir = Vector::new(-dir.y, dir.x);
392 self.sink.line_to(from + dir * self.radius_abs);
393 self.sink.line_to(to + dir * self.radius_abs);
394 self.sink.line_to(to);
395 }
396 Cap::Round => {
397 let r = self.radius_abs;
398 let (size, sweep) = (ArcSize::Small, ArcSweep::Positive);
399 arc(self.sink, from, r, r, 0., size, sweep, to);
400 }
401 }
402 }
403
404 fn add_start_cap(&mut self, from: Point, to: Point, dir: Vector) {
405 self.add_cap(from, to, dir, self.start_cap);
406 }
407
408 fn add_end_cap(&mut self, from: Point, to: Point, dir: Vector) {
409 self.add_cap(from, to, dir, self.end_cap);
410 }
411}
412
413enum DashOp {
414 Done,
415 Continue,
416 Emit,
417 Stroke,
418}
419
420#[derive(Copy, Clone, Default)]
421struct Dasher {
422 done: bool,
423 is_closed: bool,
424 empty_gaps: bool,
425 on: bool,
426 cur: isize,
427 t0: f32,
428 t0_offset: f32,
429 index: usize,
430 is_first: bool,
431 first_on: bool,
432 first_dash: f32,
433 is_dot: bool,
434 range: (isize, isize),
435 trange: (f32, f32),
436}
437
438impl Dasher {
439 fn init(&mut self, is_closed: bool, dashes: &[f32], offset: f32) {
440 self.done = false;
441 self.is_closed = is_closed;
442 self.on = true;
443 self.cur = 0;
444 self.t0 = 0.;
445 self.t0_offset = 0.;
446 self.index = 0;
447 self.is_first = true;
448 self.first_on = true;
449 let mut first_dash = self.next_dash(dashes);
450 if offset > 0. {
451 let mut accum = first_dash;
452 while accum < offset {
453 self.on = !self.on;
454 accum += self.next_dash(dashes);
455 }
456 self.first_on = self.on;
457 first_dash = accum - offset;
458 }
459 self.first_dash = first_dash;
460 }
461
462 #[inline(always)]
463 fn next_dash(&mut self, dashes: &[f32]) -> f32 {
464 let len = dashes.len();
465 let mut dash = dashes[self.index % len];
466 if self.on && self.empty_gaps {
467 loop {
468 let next_dash = dashes[(self.index + 1) % len];
469 if next_dash != 0. {
470 break;
471 }
472 self.index += 2;
473 dash += dashes[self.index % len];
474 }
475 }
476 self.index += 1;
477 dash
478 }
479
480 #[inline(always)]
481 fn next_segments(
482 dash: f32,
483 segments: &[Segment],
484 limit: isize,
485 start: isize,
486 start_offset: f32,
487 ) -> (bool, isize, f32, f32) {
488 let mut cur = start;
489 let mut goal = dash + start_offset;
490 let mut segment = get_signed(segments, cur);
491 loop {
492 let td = segment.time(goal, 1.);
493 let dist = td.distance;
494 let t2 = td.time;
495 goal -= dist;
496 if goal <= 0. {
497 return (true, cur, dist, t2);
498 }
499 if cur + 1 >= limit {
500 return (false, cur, dist, t2);
501 }
502 cur += 1;
503 segment = get_signed(segments, cur);
504 }
505 }
506
507 #[inline(always)]
508 fn next(&mut self, segments: &[Segment], dashes: &[f32]) -> DashOp {
509 if self.done {
510 return DashOp::Done;
511 }
512 let first = self.is_first;
513 let first_and_closed = first && self.is_closed;
514 let mut dash = if first {
515 self.first_dash
516 } else {
517 self.next_dash(dashes)
518 };
519 let mut on = self.on;
520 let mut start = self.cur;
521 let limit = segments.len() as isize;
522 if self.t0 == 1. && start < limit - 1 {
523 start += 1;
524 self.t0 = 0.;
525 self.t0_offset = 0.;
526 self.cur = start;
527 }
528 let (cont, mut end, mut t1_offset, mut t1) = if dash == 0. {
529 (true, start, self.t0_offset, self.t0)
530 } else {
531 Self::next_segments(dash, segments, limit, start, self.t0_offset)
532 };
533 if !cont {
534 self.done = true;
535 }
536 if self.done && self.is_closed {
541 if on {
542 if first_and_closed {
544 return DashOp::Stroke;
546 }
547 if self.first_on {
548 self.cur = start - limit;
549 start = self.cur;
550 let (_, end2, end_offset, end_t) =
551 Self::next_segments(self.first_dash, segments, limit, 0, 0.);
552 end = end2;
553 t1_offset = end_offset;
554 t1 = end_t;
555 }
556 } else {
557 if !self.first_on {
559 return DashOp::Done;
560 }
561 dash = self.first_dash;
562 self.cur = 0;
563 self.t0 = 0.;
564 self.t0_offset = 0.;
565 self.on = true;
566 on = true;
567 start = self.cur;
568 let (_, end2, end_offset, end_t) =
569 Self::next_segments(self.first_dash, segments, limit, 0, 0.);
570 end = end2;
571 t1_offset = end_offset;
572 t1 = end_t;
573 }
574 } else if self.done && !on {
575 return DashOp::Done;
576 }
577 self.is_dot = dash == 0.;
578 let t0 = self.t0;
579
580 self.is_first = false;
581 self.cur = end;
582 self.t0 = t1;
583 self.t0_offset = t1_offset;
584 self.on = !self.on;
585 if on && !first_and_closed {
586 self.range = (start, end);
587 self.trange = (t0, t1);
588 return DashOp::Emit;
589 }
590 DashOp::Continue
591 }
592}
593
594fn validate_dashes(dashes: &[f32], offset: f32) -> (&[f32], f32, bool) {
595 let len = dashes.len();
596 if len > 0 {
597 let mut small_count = 0;
602 let mut gap_sum = 0.;
603 let mut empty_gaps = false;
604 let is_odd = len & 1 != 0;
605 for (i, dash) in dashes.iter().enumerate() {
606 let is_gap = i & 1 == 1;
607 if *dash < 1. {
608 small_count += 1;
609 if *dash < 0. {
610 return (&[], 0., false);
611 } else if *dash == 0. && (is_gap || is_odd) {
612 empty_gaps = true;
613 }
614 } else if is_gap {
615 gap_sum += *dash;
616 }
617 }
618 if dashes.len() == 1 {
619 gap_sum = 1.;
620 }
621 if small_count < dashes.len() && gap_sum > 0. {
622 let offset = if offset != 0. {
623 let mut s: f32 = dashes.iter().sum();
624 if is_odd {
625 s *= 2.;
626 }
627 if offset < 0. {
628 s - (offset.abs() % s)
629 } else {
630 offset % s
631 }
632 } else {
633 0.
634 };
635 return (dashes, offset, empty_gaps);
636 }
637 }
638 (&[], 0., false)
639}
640
641#[inline(always)]
642fn get_signed(segments: &[Segment], index: isize) -> Segment {
643 let index = if index < 0 {
644 segments.len() - (-index) as usize
645 } else {
646 index as usize
647 };
648 segments[index]
649}
650
651fn is_clockwise(a: Vector, b: Vector) -> bool {
652 a.x * b.y > a.y * b.x
653}
654
655impl Segment {
656 fn offset(&self, radius: f32) -> OffsetSegment {
657 OffsetSegment::new(self, radius)
658 }
659}
660
661#[derive(Copy, Clone)]
662pub struct OffsetSegment {
663 pub segment: Segment,
664 pub id: u8,
665 pub start: Point,
666 pub end: Point,
667 pub start_normal: Vector,
668 pub end_normal: Vector,
669 pub end_pivot: Point,
670}
671
672impl OffsetSegment {
673 fn new(segment: &Segment, radius: f32) -> Self {
674 match segment {
675 Segment::Line(id, Line { a, b }) => {
676 let n = normal(*a, *b);
677 let nr = n * radius;
678 let start = *a + nr;
679 let end = *b + nr;
680 Self {
681 segment: Segment::Line(*id, Line { a: start, b: end }),
682 id: *id,
683 start,
684 end,
685 start_normal: n,
686 end_normal: n,
687 end_pivot: *b,
688 }
689 }
690 Segment::Curve(id, c) => {
691 const EPS: f32 = 0.5;
692 let normal_ab = if c.a.nearly_eq_by(c.b, EPS) {
694 if c.a.nearly_eq_by(c.c, EPS) {
695 normal(c.a, c.d)
696 } else {
697 normal(c.a, c.c)
698 }
699 } else {
700 normal(c.a, c.b)
701 };
702 let normal_bc = if c.b.nearly_eq_by(c.c, EPS) {
703 if c.b.nearly_eq_by(c.d, EPS) {
704 normal(c.a, c.d)
705 } else {
706 normal(c.b, c.d)
707 }
708 } else {
709 normal(c.b, c.c)
710 };
711 let normal_cd = if c.c.nearly_eq_by(c.d, EPS) {
712 if c.b.nearly_eq_by(c.d, EPS) {
713 normal(c.a, c.d)
714 } else {
715 normal(c.b, c.d)
716 }
717 } else {
718 normal(c.c, c.d)
719 };
720 let mut normal_b = normal_ab + normal_bc;
721 let mut normal_c = normal_cd + normal_bc;
722 let dot = normal_ab.dot(normal_bc);
723 normal_b = normal_b.normalize() * (radius / ((1. + dot) * 0.5).sqrt());
724 let dot = normal_cd.dot(normal_bc);
725 normal_c = normal_c.normalize() * (radius / ((1. + dot) * 0.5).sqrt());
726 let start = c.a + normal_ab * radius;
727 let end = c.d + normal_cd * radius;
728 Self {
729 segment: Segment::Curve(
730 *id,
731 Curve::new(start, c.b + normal_b, c.c + normal_c, end),
732 ),
733 id: *id,
734 start,
735 end,
736 start_normal: normal_ab,
737 end_normal: normal_cd,
738 end_pivot: c.d,
739 }
740 }
741 Segment::End(..) => Self {
742 segment: *segment,
743 id: 0,
744 start: Point::ZERO,
745 end: Point::ZERO,
746 start_normal: Vector::ZERO,
747 end_normal: Vector::ZERO,
748 end_pivot: Point::ZERO,
749 },
750 }
751 }
752}
753
754pub trait StrokerStorage {
755 fn clear(&mut self);
756 fn push(&mut self, segment: &Segment);
757 fn get(&self) -> &[Segment];
758
759 fn collect(&mut self, segments: &mut impl Iterator<Item = Segment>) -> (bool, bool) {
760 self.clear();
761 let mut is_closed = false;
762 let mut done = false;
763 loop {
764 if let Some(segment) = segments.next() {
765 match segment {
766 Segment::End(closed) => {
767 is_closed = closed;
768 break;
769 }
770 _ => self.push(&segment),
771 }
772 } else {
773 done = true;
774 break;
775 }
776 }
777 (is_closed, done)
778 }
779}
780
781impl StrokerStorage for SmallBuf<Segment> {
782 fn clear(&mut self) {
783 self.clear();
784 }
785
786 #[inline(always)]
787 fn push(&mut self, segment: &Segment) {
788 self.push(*segment);
789 }
790
791 fn get(&self) -> &[Segment] {
792 self.data()
793 }
794}
795
796impl StrokerStorage for Vec<Segment> {
797 fn clear(&mut self) {
798 self.clear();
799 }
800
801 #[inline(always)]
802 fn push(&mut self, segment: &Segment) {
803 self.push(*segment);
804 }
805
806 fn get(&self) -> &[Segment] {
807 self
808 }
809}
810
811const MAX_SMALL_BUF: usize = 128;
812
813#[derive(Clone)]
814enum SmallBuf<T> {
815 Array([T; MAX_SMALL_BUF], usize),
816 Vec(Vec<T>),
817}
818
819impl<T: Copy + Default> SmallBuf<T> {
820 pub fn new() -> Self {
821 Self::Array([T::default(); MAX_SMALL_BUF], 0)
822 }
823
824 pub fn data(&self) -> &[T] {
825 match self {
826 Self::Array(ref buf, len) => &buf[..*len],
827 Self::Vec(ref buf) => buf,
828 }
829 }
830
831 pub fn push(&mut self, value: T) {
832 match self {
833 Self::Vec(ref mut buf) => buf.push(value),
834 Self::Array(ref mut buf, ref mut len) => {
835 if *len == MAX_SMALL_BUF {
836 let mut vec = Vec::from(&buf[..]);
837 vec.push(value);
838 *self = Self::Vec(vec);
839 } else {
840 buf[*len] = value;
841 *len += 1;
842 }
843 }
844 }
845 }
846
847 pub fn clear(&mut self) {
848 match self {
849 Self::Array(_, ref mut len) => *len = 0,
850 Self::Vec(ref mut buf) => buf.clear(),
851 }
852 }
853}