2020-01-25 19:35:57 -05:00
use core ::fmt ;
use std ::fmt ::{ Debug , Formatter } ;
2020-01-25 07:05:07 -05:00
use std ::ops ::{ Index , IndexMut } ;
2019-12-25 04:44:51 -05:00
2020-07-26 10:27:52 -04:00
use aho_corasick ::AhoCorasick ;
2020-07-22 04:57:47 -04:00
use crate ::err ::{ Error , ErrorType , ProcessingResult , debug_repr } ;
2020-01-25 02:04:02 -05:00
use crate ::proc ::MatchAction ::* ;
use crate ::proc ::MatchMode ::* ;
2020-01-25 07:05:07 -05:00
use crate ::proc ::range ::ProcessorRange ;
2020-07-04 06:33:02 -04:00
use memchr ::memchr ;
2020-07-22 04:57:47 -04:00
use crate ::gen ::codepoints ::Lookup ;
2020-07-26 10:27:52 -04:00
2020-07-21 03:59:56 -04:00
#[ cfg(feature = " js-esbuild " ) ]
2020-07-26 10:27:52 -04:00
use {
std ::sync ::{ Arc , Mutex } ,
crossbeam ::sync ::WaitGroup ,
esbuild_rs ::TransformResult ,
} ;
2019-12-25 04:44:51 -05:00
2020-01-25 07:05:07 -05:00
pub mod checkpoint ;
2020-07-04 06:33:02 -04:00
pub mod entity ;
2020-01-25 07:05:07 -05:00
pub mod range ;
2020-01-18 06:19:06 -05:00
2020-07-30 00:38:40 -04:00
#[ allow(dead_code) ]
2020-01-26 04:32:06 -05:00
pub enum MatchMode {
IsChar ( u8 ) ,
IsNotChar ( u8 ) ,
WhileChar ( u8 ) ,
WhileNotChar ( u8 ) ,
2020-07-11 08:52:27 -04:00
// Through is like WhileNot followed by Is, but matches zero if Is is zero.
ThroughChar ( u8 ) ,
2020-01-26 04:32:06 -05:00
IsPred ( fn ( u8 ) -> bool ) ,
IsNotPred ( fn ( u8 ) -> bool ) ,
WhilePred ( fn ( u8 ) -> bool ) ,
WhileNotPred ( fn ( u8 ) -> bool ) ,
2020-07-09 03:06:08 -04:00
IsInLookup ( & 'static Lookup ) ,
WhileInLookup ( & 'static Lookup ) ,
WhileNotInLookup ( & 'static Lookup ) ,
2020-01-26 04:32:06 -05:00
IsSeq ( & 'static [ u8 ] ) ,
2020-07-26 10:27:52 -04:00
WhileNotSeq ( & 'static AhoCorasick ) ,
2020-07-27 04:08:53 -04:00
ThroughSeq ( & 'static AhoCorasick ) ,
2020-01-25 02:04:02 -05:00
}
pub enum MatchAction {
Keep ,
Discard ,
MatchOnly ,
}
2020-07-21 03:59:56 -04:00
#[ cfg(feature = " js-esbuild " ) ]
2021-01-07 08:26:02 -05:00
pub struct EsbuildSection {
2020-07-21 09:27:56 -04:00
pub src : ProcessorRange ,
2020-07-21 03:57:39 -04:00
pub result : TransformResult ,
}
2020-01-25 19:49:43 -05:00
// Processing state of a file. Single use only; create one per processing.
2019-12-25 04:44:51 -05:00
pub struct Processor < ' d > {
2020-01-16 08:05:48 -05:00
code : & ' d mut [ u8 ] ,
2019-12-27 05:52:49 -05:00
// Index of the next character to read.
2020-01-16 08:05:48 -05:00
read_next : usize ,
2019-12-27 05:52:49 -05:00
// Index of the next unwritten space.
2020-01-16 08:05:48 -05:00
write_next : usize ,
2020-07-21 03:57:39 -04:00
#[ cfg(feature = " js-esbuild " ) ]
2021-01-07 08:26:02 -05:00
esbuild_wg : WaitGroup ,
2020-07-21 03:57:39 -04:00
#[ cfg(feature = " js-esbuild " ) ]
2021-01-07 08:26:02 -05:00
esbuild_results : Arc < Mutex < Vec < EsbuildSection > > > ,
2019-12-25 04:44:51 -05:00
}
impl < ' d > Index < ProcessorRange > for Processor < ' d > {
type Output = [ u8 ] ;
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 04:44:51 -05:00
fn index ( & self , index : ProcessorRange ) -> & Self ::Output {
2019-12-25 07:29:18 -05:00
& self . code [ index . start .. index . end ]
2019-12-25 04:44:51 -05:00
}
}
2020-01-16 08:05:48 -05:00
impl < ' d > IndexMut < ProcessorRange > for Processor < ' d > {
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-01-16 08:05:48 -05:00
fn index_mut ( & mut self , index : ProcessorRange ) -> & mut Self ::Output {
debug_assert! ( index . end < = self . write_next ) ;
& mut self . code [ index . start .. index . end ]
}
}
2020-07-30 00:38:40 -04:00
#[ allow(dead_code) ]
2019-12-25 04:44:51 -05:00
impl < ' d > Processor < ' d > {
2019-12-25 07:29:18 -05:00
// Constructor.
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 07:29:18 -05:00
pub fn new ( code : & mut [ u8 ] ) -> Processor {
2020-07-21 03:57:39 -04:00
Processor {
write_next : 0 ,
read_next : 0 ,
code ,
#[ cfg(feature = " js-esbuild " ) ]
2021-01-07 08:26:02 -05:00
esbuild_wg : WaitGroup ::new ( ) ,
2020-07-21 03:57:39 -04:00
#[ cfg(feature = " js-esbuild " ) ]
2021-01-07 08:26:02 -05:00
esbuild_results : Arc ::new ( Mutex ::new ( Vec ::new ( ) ) ) ,
2020-07-21 03:57:39 -04:00
}
2019-12-25 07:29:18 -05:00
}
2019-12-25 04:44:51 -05:00
// INTERNAL APIs.
2019-12-25 07:29:18 -05:00
// Bounds checking.
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 07:29:18 -05:00
fn _in_bounds ( & self , offset : usize ) -> bool {
2019-12-25 04:44:51 -05:00
self . read_next + offset < self . code . len ( )
}
// Reading.
/// Get the `offset` character from next.
/// When `offset` is 0, the next character is returned.
/// Panics. Does not check bounds for performance (e.g. already checked).
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 07:29:18 -05:00
fn _read_offset ( & self , offset : usize ) -> u8 {
self . code [ self . read_next + offset ]
2019-12-25 04:44:51 -05:00
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 07:29:18 -05:00
fn _maybe_read_offset ( & self , offset : usize ) -> Option < u8 > {
2020-01-25 02:04:02 -05:00
self . code . get ( self . read_next + offset ) . map ( | c | * c )
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-01-25 02:04:02 -05:00
fn _maybe_read_slice_offset ( & self , offset : usize , count : usize ) -> Option < & [ u8 ] > {
2020-01-25 19:49:43 -05:00
self . code . get ( self . read_next + offset .. self . read_next + offset + count )
2019-12-25 04:44:51 -05:00
}
/// Move next `amount` characters to output.
/// Panics. Does not check bounds for performance (e.g. already checked).
2020-01-31 07:15:35 -05:00
#[ inline(always) ]
2019-12-25 07:29:18 -05:00
fn _shift ( & mut self , amount : usize ) -> ( ) {
// Optimisation: Don't shift if already there (but still update offsets).
if self . read_next ! = self . write_next {
self . code . copy_within ( self . read_next .. self . read_next + amount , self . write_next ) ;
} ;
2019-12-25 04:44:51 -05:00
self . read_next + = amount ;
2019-12-25 07:29:18 -05:00
self . write_next + = amount ;
2019-12-25 04:44:51 -05:00
}
2020-01-25 07:05:07 -05:00
2020-01-31 07:15:35 -05:00
#[ inline(always) ]
2020-01-25 07:05:07 -05:00
fn _replace ( & mut self , start : usize , end : usize , data : & [ u8 ] ) -> usize {
2020-01-26 00:38:23 -05:00
debug_assert! ( start < = end ) ;
2020-01-25 07:05:07 -05:00
let added = data . len ( ) - ( end - start ) ;
// Do not allow writing over source.
debug_assert! ( self . write_next + added < = self . read_next ) ;
self . code . copy_within ( end .. self . write_next , end + added ) ;
self . code [ start .. start + data . len ( ) ] . copy_from_slice ( data ) ;
// Don't need to update read_next as only data before it has changed.
self . write_next + = added ;
added
}
2020-01-31 07:15:35 -05:00
#[ inline(always) ]
2020-01-25 07:05:07 -05:00
fn _insert ( & mut self , at : usize , data : & [ u8 ] ) -> usize {
self . _replace ( at , at , data )
2020-01-14 01:55:27 -05:00
}
2019-12-25 04:44:51 -05:00
2019-12-25 07:29:18 -05:00
// Matching.
2020-01-31 07:15:35 -05:00
#[ inline(always) ]
2020-01-25 02:04:02 -05:00
fn _one < C : FnOnce ( u8 ) -> bool > ( & mut self , cond : C ) -> usize {
self . _maybe_read_offset ( 0 ) . filter ( | n | cond ( * n ) ) . is_some ( ) as usize
2019-12-25 07:29:18 -05:00
}
2020-01-25 19:49:43 -05:00
2020-01-31 07:15:35 -05:00
#[ inline(always) ]
2020-01-25 02:04:02 -05:00
fn _many < C : Fn ( u8 ) -> bool > ( & mut self , cond : C ) -> usize {
2019-12-25 07:29:18 -05:00
let mut count = 0 usize ;
2020-01-25 02:04:02 -05:00
while self . _maybe_read_offset ( count ) . filter ( | c | cond ( * c ) ) . is_some ( ) {
2019-12-25 07:29:18 -05:00
count + = 1 ;
} ;
2020-01-25 02:04:02 -05:00
count
2019-12-25 07:29:18 -05:00
}
2020-01-25 02:04:02 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-07-11 08:52:27 -04:00
fn _remaining ( & self ) -> usize {
self . code . len ( ) - self . read_next
}
2020-01-31 07:15:35 -05:00
#[ inline(always) ]
2020-01-26 04:32:06 -05:00
pub fn m ( & mut self , mode : MatchMode , action : MatchAction ) -> ProcessorRange {
let count = match mode {
IsChar ( c ) = > self . _one ( | n | n = = c ) ,
IsNotChar ( c ) = > self . _one ( | n | n ! = c ) ,
WhileChar ( c ) = > self . _many ( | n | n = = c ) ,
2020-07-11 08:52:27 -04:00
WhileNotChar ( c ) = > memchr ( c , & self . code [ self . read_next .. ] ) . unwrap_or ( self . _remaining ( ) ) ,
ThroughChar ( c ) = > memchr ( c , & self . code [ self . read_next .. ] ) . map_or ( 0 , | p | p + 1 ) ,
2020-01-26 04:32:06 -05:00
2020-07-09 03:06:08 -04:00
IsInLookup ( lookup ) = > self . _one ( | n | lookup [ n ] ) ,
WhileInLookup ( lookup ) = > self . _many ( | n | lookup [ n ] ) ,
WhileNotInLookup ( lookup ) = > self . _many ( | n | ! lookup [ n ] ) ,
2020-01-26 04:32:06 -05:00
IsPred ( p ) = > self . _one ( | n | p ( n ) ) ,
IsNotPred ( p ) = > self . _one ( | n | ! p ( n ) ) ,
WhilePred ( p ) = > self . _many ( | n | p ( n ) ) ,
WhileNotPred ( p ) = > self . _many ( | n | ! p ( n ) ) ,
2020-01-25 02:04:02 -05:00
2020-01-26 04:32:06 -05:00
IsSeq ( seq ) = > self . _maybe_read_slice_offset ( 0 , seq . len ( ) ) . filter ( | src | * src = = seq ) . map_or ( 0 , | _ | seq . len ( ) ) ,
2020-07-26 10:27:52 -04:00
WhileNotSeq ( seq ) = > seq . find ( & self . code [ self . read_next .. ] ) . map_or ( self . _remaining ( ) , | m | m . start ( ) ) ,
2020-07-27 04:08:53 -04:00
// Match.end is exclusive, so do not add one.
ThroughSeq ( seq ) = > seq . find ( & self . code [ self . read_next .. ] ) . map_or ( 0 , | m | m . end ( ) ) ,
2020-01-25 02:04:02 -05:00
} ;
// If keeping, match will be available in written range (which is better as source might eventually get overwritten).
// If discarding, then only option is source range.
let start = match action {
Discard | MatchOnly = > self . read_next ,
Keep = > self . write_next ,
} ;
match action {
Discard = > self . read_next + = count ,
Keep = > self . _shift ( count ) ,
MatchOnly = > { }
} ;
ProcessorRange { start , end : start + count }
}
2019-12-25 07:29:18 -05:00
// PUBLIC APIs.
// Bounds checking
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 04:44:51 -05:00
pub fn at_end ( & self ) -> bool {
2019-12-25 07:29:18 -05:00
! self . _in_bounds ( 0 )
2019-12-25 04:44:51 -05:00
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-07-11 08:52:27 -04:00
pub fn require_not_at_end ( & self ) -> ProcessingResult < ( ) > {
if self . at_end ( ) {
Err ( ErrorType ::UnexpectedEnd )
} else {
Ok ( ( ) )
}
}
2019-12-25 07:29:18 -05:00
/// Get how many characters have been consumed from source.
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 07:29:18 -05:00
pub fn read_len ( & self ) -> usize {
self . read_next
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-01-16 08:05:48 -05:00
pub fn reserve_output ( & mut self , amount : usize ) -> ( ) {
self . write_next + = amount ;
}
2019-12-25 07:29:18 -05:00
// Looking ahead.
2019-12-25 04:44:51 -05:00
/// Get the `offset` character from next.
/// When `offset` is 0, the next character is returned.
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-01-25 07:05:07 -05:00
pub fn peek ( & self , offset : usize ) -> Option < u8 > {
2019-12-25 07:29:18 -05:00
self . _maybe_read_offset ( offset )
2019-12-25 04:44:51 -05:00
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-01-25 07:05:07 -05:00
pub fn peek_many ( & self , offset : usize , count : usize ) -> Option < & [ u8 ] > {
2020-01-25 02:04:02 -05:00
self . _maybe_read_slice_offset ( offset , count )
2020-01-04 21:28:34 -05:00
}
2019-12-25 04:44:51 -05:00
2020-07-10 06:40:33 -04:00
// Looking behind.
2020-09-02 03:07:02 -04:00
pub fn last_is ( & self , c : u8 ) -> bool {
self . write_next > 0 & & self . code [ self . write_next - 1 ] = = c
2020-07-10 06:40:33 -04:00
}
2019-12-25 07:29:18 -05:00
// Consuming source characters.
2019-12-25 04:44:51 -05:00
/// Skip and return the next character.
/// Will result in an error if exceeds bounds.
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 21:47:18 -05:00
pub fn skip ( & mut self ) -> ProcessingResult < u8 > {
2020-01-25 02:04:02 -05:00
self . _maybe_read_offset ( 0 ) . map ( | c | {
2019-12-25 07:29:18 -05:00
self . read_next + = 1 ;
2020-01-25 02:04:02 -05:00
c
} ) . ok_or ( ErrorType ::UnexpectedEnd )
2019-12-25 04:44:51 -05:00
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-29 19:33:49 -05:00
pub fn skip_amount_expect ( & mut self , amount : usize ) -> ( ) {
debug_assert! ( ! self . at_end ( ) , " skip known characters " ) ;
self . read_next + = amount ;
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-29 05:00:20 -05:00
pub fn skip_expect ( & mut self ) -> ( ) {
2019-12-29 19:33:49 -05:00
debug_assert! ( ! self . at_end ( ) , " skip known character " ) ;
2019-12-29 05:00:20 -05:00
self . read_next + = 1 ;
}
2019-12-25 04:44:51 -05:00
2019-12-25 07:29:18 -05:00
// Writing characters directly.
2019-12-25 04:44:51 -05:00
/// Write `c` to output. Will panic if exceeds bounds.
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 04:44:51 -05:00
pub fn write ( & mut self , c : u8 ) -> ( ) {
2019-12-25 07:29:18 -05:00
self . code [ self . write_next ] = c ;
self . write_next + = 1 ;
2019-12-25 04:44:51 -05:00
}
2020-01-25 07:05:07 -05:00
2020-07-29 22:32:53 -04:00
#[ inline(always) ]
pub fn make_lowercase ( & mut self , range : ProcessorRange ) -> ( ) {
self . code [ range . start .. range . end ] . make_ascii_lowercase ( ) ;
}
2020-09-02 03:07:02 -04:00
pub fn undo_write ( & mut self , len : usize ) -> ( ) {
self . write_next - = len ;
}
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-01-06 07:36:05 -05:00
pub fn write_range ( & mut self , s : ProcessorRange ) -> ProcessorRange {
let dest_start = self . write_next ;
let dest_end = dest_start + s . len ( ) ;
self . code . copy_within ( s . start .. s . end , dest_start ) ;
self . write_next = dest_end ;
ProcessorRange { start : dest_start , end : dest_end }
2019-12-28 07:06:04 -05:00
}
2020-01-25 07:05:07 -05:00
2019-12-25 04:44:51 -05:00
/// Write `s` to output. Will panic if exceeds bounds.
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 04:44:51 -05:00
pub fn write_slice ( & mut self , s : & [ u8 ] ) -> ( ) {
2019-12-25 07:29:18 -05:00
self . code [ self . write_next .. self . write_next + s . len ( ) ] . copy_from_slice ( s ) ;
self . write_next + = s . len ( ) ;
2019-12-25 04:44:51 -05:00
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-26 08:23:33 -05:00
pub fn write_utf8 ( & mut self , c : char ) -> ( ) {
2019-12-27 19:16:28 -05:00
let mut encoded = [ 0 u8 ; 4 ] ;
2020-01-26 00:38:23 -05:00
self . write_slice ( c . encode_utf8 ( & mut encoded ) . as_bytes ( ) ) ;
2019-12-25 04:44:51 -05:00
}
2019-12-25 07:29:18 -05:00
// Shifting characters.
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-25 21:47:18 -05:00
pub fn accept ( & mut self ) -> ProcessingResult < u8 > {
2020-01-25 02:04:02 -05:00
self . _maybe_read_offset ( 0 ) . map ( | c | {
2020-01-06 02:13:24 -05:00
self . code [ self . write_next ] = c ;
self . read_next + = 1 ;
self . write_next + = 1 ;
2020-01-25 02:04:02 -05:00
c
} ) . ok_or ( ErrorType ::UnexpectedEnd )
2019-12-25 04:44:51 -05:00
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2019-12-29 19:33:49 -05:00
pub fn accept_expect ( & mut self ) -> u8 {
debug_assert! ( ! self . at_end ( ) ) ;
let c = self . _read_offset ( 0 ) ;
2020-01-06 02:13:24 -05:00
self . code [ self . write_next ] = c ;
self . read_next + = 1 ;
self . write_next + = 1 ;
2019-12-29 19:33:49 -05:00
c
}
2020-01-25 07:05:07 -05:00
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-01-04 21:28:34 -05:00
pub fn accept_amount_expect ( & mut self , count : usize ) -> ( ) {
debug_assert! ( self . _in_bounds ( count - 1 ) ) ;
self . _shift ( count ) ;
}
2020-07-21 03:57:39 -04:00
2020-07-21 03:59:56 -04:00
#[ cfg(feature = " js-esbuild " ) ]
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2021-01-07 08:26:02 -05:00
pub fn new_esbuild_section ( & self ) -> ( WaitGroup , Arc < Mutex < Vec < EsbuildSection > > > ) {
( self . esbuild_wg . clone ( ) , self . esbuild_results . clone ( ) )
2020-07-21 03:57:39 -04:00
}
2020-07-21 09:27:56 -04:00
// Since we consume the Processor, we must provide a full Error with positions.
#[ cfg(not(feature = " js-esbuild " )) ]
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-07-21 09:27:56 -04:00
pub fn finish ( self ) -> Result < usize , Error > {
2020-07-30 06:17:55 -04:00
debug_assert! ( self . at_end ( ) ) ;
2020-07-21 09:27:56 -04:00
Ok ( self . write_next )
}
// Since we consume the Processor, we must provide a full Error with positions.
#[ cfg(feature = " js-esbuild " ) ]
2020-07-27 04:08:53 -04:00
#[ inline(always) ]
2020-07-21 09:27:56 -04:00
pub fn finish ( self ) -> Result < usize , Error > {
2020-07-30 06:17:55 -04:00
debug_assert! ( self . at_end ( ) ) ;
2021-01-07 08:26:02 -05:00
self . esbuild_wg . wait ( ) ;
let mut results = Arc ::try_unwrap ( self . esbuild_results )
. unwrap_or_else ( | _ | panic! ( " failed to acquire esbuild results " ) )
2020-07-21 09:27:56 -04:00
. into_inner ( )
. unwrap ( ) ;
results . sort_unstable_by_key ( | r | r . src . start ) ;
2021-01-07 08:26:02 -05:00
// As we write minified JS/CSS code for sections from left to right, we will be shifting code
// towards the left as previous source JS/CSS code sections shrink. We need to keep track of
2020-07-21 09:27:56 -04:00
// the write pointer after previous compaction.
// If there are no script sections, then we get self.write_next which will be returned.
let mut write_next = results . get ( 0 ) . map_or ( self . write_next , | r | r . src . start ) ;
2021-01-07 08:26:02 -05:00
for ( i , EsbuildSection { result , src } ) in results . iter ( ) . enumerate ( ) {
// Resulting minified JS/CSS to write.
2020-07-22 07:33:09 -04:00
// TODO Verify.
2021-04-07 08:08:44 -04:00
// TODO Handle potential `</script>` in output code, which could be in string (e.g. orig. "</" + "script>"), comment, or expression (e.g. orig. `a < /script>/.exec(b)?.length`).
let min_code = result . code . as_str ( ) . trim ( ) ;
2021-01-07 08:26:02 -05:00
let min_len = if min_code . len ( ) < src . len ( ) {
self . code [ write_next .. write_next + min_code . len ( ) ] . copy_from_slice ( min_code . as_bytes ( ) ) ;
min_code . len ( )
2020-07-22 04:57:47 -04:00
} else {
// If minified result is actually longer than source, then write source instead.
// NOTE: We still need to write source as previous iterations may have shifted code down.
self . code . copy_within ( src . start .. src . end , write_next ) ;
src . len ( )
2020-07-21 03:57:39 -04:00
} ;
2021-01-07 08:26:02 -05:00
let write_end = write_next + min_len ;
2020-07-21 09:27:56 -04:00
let next_start = results . get ( i + 1 ) . map_or ( self . write_next , | r | r . src . start ) ;
self . code . copy_within ( src . end .. next_start , write_end ) ;
write_next = write_end + ( next_start - src . end ) ;
2020-07-21 03:57:39 -04:00
} ;
2020-07-21 09:27:56 -04:00
Ok ( write_next )
2020-07-21 03:57:39 -04:00
}
2019-12-25 04:44:51 -05:00
}
2020-01-25 09:25:07 -05:00
impl Debug for Processor < '_ > {
fn fmt ( & self , f : & mut Formatter < '_ > ) -> fmt ::Result {
2020-07-22 04:57:47 -04:00
f . write_str ( & debug_repr ( self . code , self . read_next as isize , self . write_next as isize ) ) ? ;
2020-01-25 09:25:07 -05:00
Ok ( ( ) )
}
}