ff0af1ee unknown 1 month ago
1
2
3
4
5
6
0bdc3f91 Andy McCall 1 month ago ↶
7
use crate :: fasthash:: { FastMap as HashMap, FastSet as HashSet} ;
ff0af1ee unknown 1 month ago
8
use crate :: hash:: ChangeHash;
01a47cd7 Andy McCall 1 month ago ↶
9
use crate :: lines:: { LineRef, Lines} ;
ff0af1ee unknown 1 month ago
10
use crate :: objects:: AtomRange;
0bdc3f91 Andy McCall 1 month ago ↶
11
use std:: collections:: { BTreeMap, BTreeSet} ;
ff0af1ee unknown 1 month ago
12
13
14
pub type AtomKey = ( ChangeHash, u32 ) ;
15
16
# [ derive ( Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug ) ]
17
pub enum Vertex {
18
Start,
19
Atom( AtomKey) ,
20
End,
21
}
22
23
24
pub trait DepOracle {
25
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool ;
26
}
27
28
29
pub struct NoDeps ;
30
impl DepOracle for NoDeps {
31
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
32
a = = b
33
}
34
}
35
36
# [ derive ( Default, Clone, Debug ) ]
37
struct AtomInfo {
01a47cd7 Andy McCall 1 month ago ↶
38
39
40
content : Option< LineRef> ,
ff0af1ee unknown 1 month ago
41
deleted_by : BTreeSet< ChangeHash> ,
42
}
43
44
# [ derive ( Clone, Debug ) ]
45
pub struct FileGraph {
46
atoms : HashMap< AtomKey, AtomInfo> ,
0bdc3f91 Andy McCall 1 month ago ↶
47
48
succ : HashMap< Vertex, Edges> ,
dbf06d34 Andy McCall 1 month ago ↶
49
50
order : OrderSlot,
0bdc3f91 Andy McCall 1 month ago ↶
51
}
dbf06d34 Andy McCall 1 month ago ↶
52
53
54
55
56
57
58
# [ derive ( Debug ) ]
59
pub struct Order {
60
atoms : Vec< AtomKey> ,
61
62
63
64
unchecked : Vec< AtomKey> ,
65
confirmed : std:: sync:: atomic:: AtomicBool,
66
}
67
68
69
70
# [ derive ( Debug, Default ) ]
71
struct OrderSlot ( std:: sync:: Mutex< Option< std:: sync:: Arc< Order> > > ) ;
72
73
impl OrderSlot {
74
fn get ( & self ) -> Option< std:: sync:: Arc< Order> > {
75
self .0. lock ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) .clone ( )
76
}
77
fn set ( & self , o : Option< std:: sync:: Arc< Order> > ) {
78
* self .0. lock ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) = o;
79
}
80
fn take ( & mut self ) -> Option< std:: sync:: Arc< Order> > {
81
self .0. get_mut ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) .take ( )
82
}
83
}
84
85
impl Clone for OrderSlot {
86
fn clone ( & self ) -> Self {
87
OrderSlot( std:: sync:: Mutex:: new( self .get ( ) ) )
88
}
89
}
90
91
impl Order {
92
fn known ( atoms : Vec< AtomKey> ) -> Order {
93
Order {
94
atoms,
95
unchecked: Vec :: new( ) ,
96
confirmed: std:: sync:: atomic:: AtomicBool:: new( true ) ,
97
}
98
}
0bdc3f91 Andy McCall 1 month ago ↶
99
dbf06d34 Andy McCall 1 month ago ↶
100
101
102
103
104
105
pub fn splice (
106
& self ,
107
h : ChangeHash,
108
inserts : & [( Vertex , Vertex , u32 , u32 ) ],
109
deleted : & [AtomKey],
110
) -> Option< std:: sync:: Arc< Order> > {
111
let mut want: HashSet< AtomKey> = deleted.iter ( ) .copied ( ) .collect ( ) ;
112
for ( a, b, _ , _ ) in inserts {
113
for v in [ a, b] {
114
if let Vertex:: Atom( k) = v {
115
want.insert ( * k) ;
116
}
117
}
118
}
119
let mut pos: HashMap< AtomKey, usize > = HashMap:: default( ) ;
120
for ( i, k) in self .atoms.iter ( ) .enumerate ( ) {
121
if want.contains ( k) {
122
pos.insert ( * k, i) ;
123
}
124
}
125
let len = self .atoms.len ( ) ;
126
let mut gone = vec! [ false ; len] ;
127
let mut unchecked = if self .confirmed.load ( std:: sync:: atomic:: Ordering:: Relaxed) {
128
Vec :: new( )
129
} else {
130
self .unchecked.clone ( )
131
} ;
132
for k in deleted {
133
if k.0 = = h {
134
return None ;
135
}
136
if let Some ( & i) = pos.get ( k) {
137
if ! gone[ i] {
138
gone[ i] = true ;
139
unchecked.push ( * k) ;
140
}
141
}
142
}
143
144
145
let mut slots: Vec< ( usize , usize , u32 , u32 ) > = Vec :: with_capacity( inserts.len ( ) ) ;
146
for & ( a, b, first, count) in inserts {
147
let from = match a {
148
Vertex:: Start => 0 ,
149
Vertex:: Atom( k) => pos.get ( & k) ? + 1 ,
150
Vertex:: End => return None ,
151
} ;
152
let to = match b {
153
Vertex:: End => len,
154
Vertex:: Atom( k) => * pos.get ( & k) ? ,
155
Vertex:: Start => return None ,
156
} ;
157
if from > to | | gone[ from.. to] .iter ( ) .any ( | g | ! g) {
158
return None ;
159
}
160
slots.push ( ( from, to, first, count) ) ;
161
}
162
163
164
slots.sort_unstable ( ) ;
165
for w in slots.windows ( 2 ) {
166
let ( end, next) = ( w[ 0 ] .1 , w[ 1 ] .0 ) ;
167
if end > = next | | ! gone[ end.. next] .iter ( ) .any ( | g | ! g) {
168
return None ;
169
}
170
}
171
let added: usize = slots.iter ( ) .map ( | s | s.3 as usize ) .sum ( ) ;
172
let mut atoms = Vec :: with_capacity( len + added) ;
173
let mut slots = slots.into_iter ( ) .peekable ( ) ;
174
let mut runs_at = | i : usize , atoms : & mut Vec< AtomKey> | {
175
while let Some ( & ( from, _ , first, count) ) = slots.peek ( ) {
176
if from ! = i {
177
break ;
178
}
179
atoms.extend ( ( first.. first + count) .map ( | j | ( h, j) ) ) ;
180
slots.next ( ) ;
181
}
182
} ;
183
for ( i, ( k, g) ) in self .atoms.iter ( ) .zip ( & gone) .enumerate ( ) {
184
runs_at ( i, & mut atoms) ;
185
if ! g {
186
atoms.push ( * k) ;
187
}
188
}
189
runs_at ( len, & mut atoms) ;
190
let confirmed = unchecked.is_empty ( ) ;
191
Some ( std:: sync:: Arc:: new( Order {
192
atoms,
193
unchecked,
194
confirmed: std:: sync:: atomic:: AtomicBool:: new( confirmed) ,
195
} ) )
196
}
197
}
198
0bdc3f91 Andy McCall 1 month ago ↶
199
200
201
# [ derive ( Clone, Debug, Default, PartialEq, Eq ) ]
202
enum Edges {
203
# [ default ]
204
None ,
205
One( Vertex) ,
206
Many( Vec< Vertex> ) ,
ff0af1ee unknown 1 month ago
207
}
208
0bdc3f91 Andy McCall 1 month ago ↶
209
impl Edges {
210
fn insert ( & mut self , v : Vertex) {
211
match self {
212
Edges:: None => * self = Edges:: One( v) ,
213
Edges:: One( a) if * a = = v => { }
214
Edges:: One( a) => {
215
let a = * a;
216
* self = Edges:: Many( if a < v { vec! [ a, v] } else { vec! [ v, a] } ) ;
217
}
218
Edges:: Many( list) => {
219
if let Err ( i) = list.binary_search ( & v) {
220
list.insert ( i, v) ;
221
}
222
}
223
}
224
}
225
226
fn as_slice ( & self ) -> & [ Vertex] {
227
match self {
228
Edges:: None => & [ ] ,
229
Edges:: One( v) => std:: slice:: from_ref( v) ,
230
Edges:: Many( list) => list,
231
}
232
}
233
234
fn iter ( & self ) -> std:: slice:: Iter< '_ , Vertex> {
235
self .as_slice ( ) .iter ( )
236
}
237
}
238
ff0af1ee unknown 1 month ago
239
impl Default for FileGraph {
240
fn default ( ) -> Self {
241
Self :: new( )
242
}
243
}
244
245
246
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
247
pub enum Segment {
248
Lines( Vec< AtomKey> ) ,
249
250
Conflict( Vec< Vec< AtomKey> > ) ,
251
252
75167672 Andy McCall 1 month ago
253
Zombie {
254
deleted: Vec< AtomKey> ,
255
inserted: Vec< AtomKey> ,
256
} ,
ff0af1ee unknown 1 month ago
257
}
258
259
# [ derive ( Clone, Debug, PartialEq, Eq, Default ) ]
260
pub struct Materialized {
261
pub segments : Vec< Segment> ,
262
}
263
264
impl Materialized {
265
pub fn is_conflicted ( & self ) -> bool {
75167672 Andy McCall 1 month ago
266
self .segments
267
.iter ( )
268
.any ( | s | ! matches! ( s, Segment:: Lines( _ ) ) )
ff0af1ee unknown 1 month ago
269
}
270
pub fn conflict_count ( & self ) -> usize {
75167672 Andy McCall 1 month ago
271
self .segments
272
.iter ( )
273
.filter ( | s | ! matches! ( s, Segment:: Lines( _ ) ) )
274
.count ( )
ff0af1ee unknown 1 month ago
275
}
276
277
pub fn live_atoms ( & self ) -> Vec< AtomKey> {
278
let mut out = Vec :: new( ) ;
279
for s in & self .segments {
280
match s {
281
Segment:: Lines( a) => out.extend ( a) ,
282
Segment:: Conflict( sides) => sides.iter ( ) .for_each ( | x | out.extend ( x) ) ,
283
Segment:: Zombie { inserted, .. } => out.extend ( inserted) ,
284
}
285
}
286
out
287
}
288
}
289
290
impl FileGraph {
291
pub fn new ( ) -> Self {
75167672 Andy McCall 1 month ago
292
let mut g = FileGraph {
0bdc3f91 Andy McCall 1 month ago ↶
293
atoms: HashMap:: default( ) ,
294
succ: HashMap:: default( ) ,
dbf06d34 Andy McCall 1 month ago ↶
295
order: OrderSlot:: default( ) ,
75167672 Andy McCall 1 month ago
296
} ;
ff0af1ee unknown 1 month ago
297
g.edge ( Vertex:: Start, Vertex:: End) ;
298
g
299
}
300
301
fn edge ( & mut self , a : Vertex, b : Vertex) {
302
self .succ.entry ( a) .or_default ( ) .insert ( b) ;
303
self .succ.entry ( b) .or_default ( ) ;
304
}
305
306
75167672 Andy McCall 1 month ago
307
pub fn insert (
308
& mut self ,
309
change : ChangeHash,
310
first_index : u32 ,
311
after : Vertex,
312
before : Vertex,
01a47cd7 Andy McCall 1 month ago ↶
313
lines : & Lines,
0bdc3f91 Andy McCall 1 month ago ↶
314
) {
01a47cd7 Andy McCall 1 month ago ↶
315
self .insert_owned ( change, first_index, after, before, lines.clone ( ) ) ;
0bdc3f91 Andy McCall 1 month ago ↶
316
}
317
318
319
320
321
pub fn insert_owned (
322
& mut self ,
323
change : ChangeHash,
324
first_index : u32 ,
325
after : Vertex,
326
before : Vertex,
01a47cd7 Andy McCall 1 month ago ↶
327
lines : Lines,
75167672 Andy McCall 1 month ago
328
) {
dbf06d34 Andy McCall 1 month ago ↶
329
self .order.take ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
330
self .atoms.reserve ( lines.len ( ) ) ;
331
self .succ.reserve ( lines.len ( ) + 1 ) ;
ff0af1ee unknown 1 month ago
332
let mut prev = after;
01a47cd7 Andy McCall 1 month ago ↶
333
for i in 0 .. lines.len ( ) {
ff0af1ee unknown 1 month ago
334
let key = ( change, first_index + i as u32 ) ;
01a47cd7 Andy McCall 1 month ago ↶
335
self .atoms.entry ( key) .or_default ( ) .content =
336
Some ( LineRef:: new( lines.clone ( ) , i as u32 ) ) ;
ff0af1ee unknown 1 month ago
337
let v = Vertex:: Atom( key) ;
0bdc3f91 Andy McCall 1 month ago ↶
338
self .succ.entry ( prev) .or_default ( ) .insert ( v) ;
ff0af1ee unknown 1 month ago
339
prev = v;
340
}
0bdc3f91 Andy McCall 1 month ago ↶
341
self .succ.entry ( prev) .or_default ( ) .insert ( before) ;
342
self .succ.entry ( before) .or_default ( ) ;
ff0af1ee unknown 1 month ago
343
}
344
345
346
pub fn delete ( & mut self , by : ChangeHash, range : & AtomRange) {
dbf06d34 Andy McCall 1 month ago ↶
347
self .order.take ( ) ;
ff0af1ee unknown 1 month ago
348
for i in range.from.. range.to {
75167672 Andy McCall 1 month ago
349
self .atoms
350
.entry ( ( range.change, i) )
351
.or_default ( )
352
.deleted_by
353
.insert ( by) ;
ff0af1ee unknown 1 month ago
354
}
355
}
356
357
pub fn is_live ( & self , k : & AtomKey) -> bool {
75167672 Andy McCall 1 month ago
358
self .atoms
359
.get ( k)
360
.is_some_and ( | a | a.content.is_some ( ) & & a.deleted_by.is_empty ( ) )
ff0af1ee unknown 1 month ago
361
}
362
363
pub fn content ( & self , k : & AtomKey) -> Option< & [ u8 ] > {
01a47cd7 Andy McCall 1 month ago ↶
364
self .atoms
365
.get ( k)
366
.and_then ( | a | a.content.as_ref ( ) .map ( LineRef:: bytes) )
ff0af1ee unknown 1 month ago
367
}
368
369
pub fn deleters ( & self , k : & AtomKey) -> impl Iterator< Item = & ChangeHash> {
75167672 Andy McCall 1 month ago
370
self .atoms
371
.get ( k)
372
.into_iter ( )
373
.flat_map ( | a | a.deleted_by.iter ( ) )
ff0af1ee unknown 1 month ago
374
}
375
376
377
pub fn atom_count ( & self ) -> usize {
378
self .atoms.len ( )
379
}
380
62794ecc Andy McCall 1 month ago ↶
381
382
383
83d61e80 Andy McCall 1 month ago ↶
384
385
386
387
388
pub fn between ( & self , first : & AtomKey, last : & AtomKey) -> Vec< AtomKey> {
389
let ( from, to) = ( Vertex:: Atom( * first) , Vertex:: Atom( * last) ) ;
390
let mut ahead: HashSet< Vertex> = HashSet:: default( ) ;
391
let mut stack = vec! [ from] ;
392
while let Some ( v) = stack.pop ( ) {
393
if ahead.insert ( v) {
394
stack.extend (
395
self .succ
396
.get ( & v)
397
.map ( | e | e.as_slice ( ) )
398
.unwrap_or ( & [ ] )
399
.iter ( )
400
.copied ( ) ,
401
) ;
402
}
403
}
404
if ! ahead.contains ( & to) {
405
return vec! [ ] ;
406
}
407
let mut pred: HashMap< Vertex, Vec< Vertex> > = HashMap:: default( ) ;
408
for ( u, es) in & self .succ {
409
if ahead.contains ( u) {
410
for w in es.iter ( ) {
411
pred.entry ( * w) .or_default ( ) .push ( * u) ;
412
}
413
}
414
}
415
let mut behind: HashSet< Vertex> = HashSet:: default( ) ;
416
let mut stack = vec! [ to] ;
417
while let Some ( v) = stack.pop ( ) {
418
if behind.insert ( v) {
419
stack.extend ( pred.get ( & v) .into_iter ( ) .flatten ( ) .copied ( ) ) ;
420
}
421
}
422
let mut out: Vec< AtomKey> = ahead
423
.intersection ( & behind)
424
.filter_map ( | v | match v {
425
Vertex:: Atom( k) if self .atoms.contains_key ( k) => Some ( * k) ,
426
_ => None ,
427
} )
428
.collect ( ) ;
429
out.sort ( ) ;
430
out
431
}
432
433
434
pub fn touching ( & self , atoms : & [AtomKey]) -> BTreeSet< ChangeHash> {
435
let mut out = BTreeSet:: new( ) ;
436
for k in atoms {
437
out.insert ( k.0 ) ;
438
if let Some ( info) = self .atoms.get ( k) {
439
out.extend ( info.deleted_by.iter ( ) .copied ( ) ) ;
440
}
441
}
442
out
443
}
444
62794ecc Andy McCall 1 month ago ↶
445
pub fn live_successor_changes ( & self , k : & AtomKey) -> Vec< ChangeHash> {
446
self .succ
447
.get ( & Vertex:: Atom( * k) )
448
.map ( | ss | {
449
ss.iter ( )
450
.filter_map ( | s | match s {
451
Vertex:: Atom( y) if self .is_live ( y) => Some ( y.0 ) ,
452
_ => None ,
453
} )
454
.collect ( )
455
} )
456
.unwrap_or_default ( )
457
}
458
ff0af1ee unknown 1 month ago
459
fn is_ghost ( & self , k : & AtomKey, info : & AtomInfo, deps : & dyn DepOracle) -> bool {
23b217d7 Andy McCall 1 month ago ↶
460
461
462
463
ff0af1ee unknown 1 month ago
464
self .succ.get ( & Vertex:: Atom( * k) ) .is_some_and ( | ss | {
465
ss.iter ( ) .any ( | s | match s {
75167672 Andy McCall 1 month ago
466
Vertex:: Atom( y) if self .is_live ( y) => ! info
467
.deleted_by
468
.iter ( )
469
.any ( | d | deps.depends_on ( d, & y.0 ) | | deps.depends_on ( & y.0 , d) ) ,
ff0af1ee unknown 1 month ago
470
_ => false ,
471
} )
472
} )
473
}
474
475
75167672 Andy McCall 1 month ago
476
fn reduced_succ (
477
& self ,
478
v : Vertex,
479
kept : & HashSet< Vertex> ,
480
memo : & mut HashMap< Vertex, BTreeSet< Vertex> > ,
481
) -> BTreeSet< Vertex> {
598009a7 Andy McCall 1 month ago ↶
482
let direct = self .succ.get ( & v) .map ( Edges:: as_slice) .unwrap_or_default ( ) ;
483
484
485
if direct.iter ( ) .all ( | s | kept.contains ( s) ) {
486
return direct.iter ( ) .copied ( ) .collect ( ) ;
487
}
ff0af1ee unknown 1 month ago
488
let mut out = BTreeSet:: new( ) ;
598009a7 Andy McCall 1 month ago ↶
489
let mut stack: Vec< Vertex> = direct.to_vec ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
490
let mut seen = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
491
while let Some ( s) = stack.pop ( ) {
492
if kept.contains ( & s) {
493
out.insert ( s) ;
494
} else if seen.insert ( s) {
495
if let Some ( m) = memo.get ( & s) {
496
out.extend ( m.iter ( ) .copied ( ) ) ;
497
} else if let Some ( next) = self .succ.get ( & s) {
498
stack.extend ( next.iter ( ) .copied ( ) ) ;
499
}
500
}
501
}
502
out
598009a7 Andy McCall 1 month ago ↶
503
}
504
505
506
507
508
509
510
fn as_chain ( & self ) -> Option< Vec< AtomKey> > {
511
if self
512
.atoms
513
.values ( )
514
.any ( | a | a.content.is_none ( ) | | ! a.deleted_by.is_empty ( ) )
515
{
516
return None ;
517
}
518
let mut order = Vec :: with_capacity( self .atoms.len ( ) ) ;
519
let mut v = Vertex:: Start;
520
loop {
521
let succ = self .succ.get ( & v) ? .as_slice ( ) ;
522
let mut atoms = succ.iter ( ) .filter ( | s | * * s ! = Vertex:: End) ;
523
match ( atoms.next ( ) , atoms.next ( ) ) {
524
( None , _ ) if succ.contains ( & Vertex:: End) => break ,
525
( Some ( Vertex:: Atom( k) ) , None ) if order.len ( ) < self .atoms.len ( ) => {
526
order.push ( * k) ;
527
v = Vertex:: Atom( * k) ;
528
}
529
_ => return None ,
530
}
531
}
532
( order.len ( ) = = self .atoms.len ( ) ) .then_some ( order)
ff0af1ee unknown 1 month ago
533
}
534
535
536
pub fn materialize ( & self , deps : & dyn DepOracle) -> Materialized {
dbf06d34 Andy McCall 1 month ago ↶
537
let lines = | order : Vec< AtomKey> | Materialized {
538
segments: if order.is_empty ( ) {
539
vec! [ ]
540
} else {
541
vec! [ Segment:: Lines( order) ]
542
} ,
543
} ;
544
use std:: sync:: atomic:: Ordering:: Relaxed;
545
if let Some ( o) = self .order.get ( ) {
546
let holds = o.confirmed.load ( Relaxed)
547
| | o.unchecked.iter ( ) .all ( | k | {
548
self .atoms
549
.get ( k)
550
.is_none_or ( | info | ! self .is_ghost ( k, info, deps) )
551
} ) ;
552
if holds {
553
o.confirmed.store ( true , Relaxed) ;
554
return lines ( o.atoms.clone ( ) ) ;
555
}
556
self .order.set ( None ) ;
557
}
558
559
560
if let Some ( order) = self .as_chain ( ) {
561
return lines ( order) ;
598009a7 Andy McCall 1 month ago ↶
562
}
dbf06d34 Andy McCall 1 month ago ↶
563
if let Some ( order) = self .as_order ( deps) {
564
self .order
565
.set ( Some ( std:: sync:: Arc:: new( Order:: known( order.clone ( ) ) ) ) ) ;
566
return lines ( order) ;
567
}
598009a7 Andy McCall 1 month ago ↶
568
self .materialize_general ( deps)
dbf06d34 Andy McCall 1 month ago ↶
569
}
570
571
572
573
pub fn take_order ( & mut self ) -> Option< std:: sync:: Arc< Order> > {
574
self .order.take ( )
575
}
576
577
578
pub fn keep_order ( & mut self , order : Option< std:: sync:: Arc< Order> > ) {
579
* self .order.0. get_mut ( ) .unwrap_or_else ( | e | e.into_inner ( ) ) = order;
598009a7 Andy McCall 1 month ago ↶
580
}
581
e83354cd Andy McCall 1 month ago ↶
582
583
584
585
586
587
588
fn as_order ( & self , deps : & dyn DepOracle) -> Option< Vec< AtomKey> > {
589
590
let mut index: HashMap< Vertex, u32 > =
591
HashMap:: with_capacity_and_hasher( self .atoms.len ( ) + 2 , Default :: default( ) ) ;
592
let mut verts: Vec< Vertex> = Vec :: with_capacity( self .atoms.len ( ) + 2 ) ;
593
verts.extend ( [ Vertex:: Start, Vertex:: End] ) ;
594
index.insert ( Vertex:: Start, 0 ) ;
595
index.insert ( Vertex:: End, 1 ) ;
596
for ( k, info) in & self .atoms {
597
if info.content.is_none ( ) {
598
continue ;
599
}
600
if info.deleted_by.is_empty ( ) {
601
index.insert ( Vertex:: Atom( * k) , verts.len ( ) as u32 ) ;
602
verts.push ( Vertex:: Atom( * k) ) ;
603
} else if self .is_ghost ( k, info, deps) {
604
return None ;
605
}
606
}
607
608
609
let mut reach: HashMap< Vertex, Vec< u32 > > = HashMap:: default( ) ;
610
let contracted = | v : Vertex, reach : & mut HashMap< Vertex, Vec< u32 > > | {
611
let mut stack: Vec< ( Vertex, bool ) > = vec! [ ( v, false ) ] ;
612
while let Some ( ( x, done) ) = stack.pop ( ) {
613
if reach.contains_key ( & x) {
614
continue ;
615
}
616
let next = self .succ.get ( & x) .map ( Edges:: as_slice) .unwrap_or_default ( ) ;
617
if ! done {
618
stack.push ( ( x, true ) ) ;
619
for s in next {
620
if ! index.contains_key ( s) & & ! reach.contains_key ( s) {
621
stack.push ( ( * s, false ) ) ;
622
}
623
}
624
continue ;
625
}
626
let mut out: Vec< u32 > = Vec :: new( ) ;
627
for s in next {
628
match index.get ( s) {
629
Some ( i) => out.push ( * i) ,
630
None => out.extend ( reach.get ( s) .into_iter ( ) .flatten ( ) ) ,
631
}
632
}
633
out.sort_unstable ( ) ;
634
out.dedup ( ) ;
635
reach.insert ( x, out) ;
636
}
637
} ;
638
639
let mut succ: Vec< u32 > = Vec :: with_capacity( verts.len ( ) * 2 ) ;
640
let mut starts: Vec< usize > = Vec :: with_capacity( verts.len ( ) + 1 ) ;
641
let mut indeg: Vec< u32 > = vec! [ 0 ; verts.len ( ) ] ;
642
for v in & verts {
643
let from = succ.len ( ) ;
644
starts.push ( from) ;
645
for s in self .succ.get ( v) .map ( Edges:: as_slice) .unwrap_or_default ( ) {
646
match index.get ( s) {
647
Some ( i) => succ.push ( * i) ,
648
None => {
649
contracted ( * s, & mut reach) ;
650
succ.extend ( reach.get ( s) .into_iter ( ) .flatten ( ) ) ;
651
}
652
}
653
}
654
if succ.len ( ) - from > 1 {
655
succ[ from.. ] .sort_unstable ( ) ;
656
let mut kept = from;
657
for i in from.. succ.len ( ) {
658
if i = = from | | succ[ i] ! = succ[ kept - 1 ] {
659
succ[ kept] = succ[ i] ;
660
kept + = 1 ;
661
}
662
}
663
succ.truncate ( kept) ;
664
}
665
for & w in & succ[ from.. ] {
666
indeg[ w as usize ] + = 1 ;
667
}
668
}
669
starts.push ( succ.len ( ) ) ;
670
671
let mut ready: Vec< u32 > = ( 0 .. verts.len ( ) as u32 )
672
.filter ( | & i | indeg[ i as usize ] = = 0 )
673
.collect ( ) ;
674
let mut order: Vec< AtomKey> = Vec :: with_capacity( verts.len ( ) ) ;
675
let mut seen = 0 ;
676
while let Some ( v) = ready.pop ( ) {
677
if ! ready.is_empty ( ) {
678
return None ;
679
}
680
seen + = 1 ;
681
if let Vertex:: Atom( k) = verts[ v as usize ] {
682
order.push ( k) ;
683
}
684
for & w in & succ[ starts[ v as usize ] .. starts[ v as usize + 1 ] ] {
685
indeg[ w as usize ] - = 1 ;
686
if indeg[ w as usize ] = = 0 {
687
ready.push ( w) ;
688
}
689
}
690
if ready.len ( ) > 1 {
691
return None ;
692
}
693
}
694
( seen = = verts.len ( ) ) .then_some ( order)
695
}
696
598009a7 Andy McCall 1 month ago ↶
697
698
699
fn materialize_general ( & self , deps : & dyn DepOracle) -> Materialized {
ff0af1ee unknown 1 month ago
700
0bdc3f91 Andy McCall 1 month ago ↶
701
let mut kept: HashSet< Vertex> = HashSet:: default( ) ;
702
let mut ghosts: HashSet< AtomKey> = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
703
kept.insert ( Vertex:: Start) ;
704
kept.insert ( Vertex:: End) ;
705
for ( k, info) in & self .atoms {
706
if info.content.is_none ( ) {
707
continue ;
708
}
709
if info.deleted_by.is_empty ( ) {
710
kept.insert ( Vertex:: Atom( * k) ) ;
711
} else if self .is_ghost ( k, info, deps) {
712
kept.insert ( Vertex:: Atom( * k) ) ;
713
ghosts.insert ( * k) ;
714
}
715
}
716
717
0bdc3f91 Andy McCall 1 month ago ↶
718
let mut memo = HashMap:: default( ) ;
719
let mut rsucc: HashMap< Vertex, BTreeSet< Vertex> > = HashMap:: default( ) ;
720
let mut indeg: HashMap< Vertex, usize > = HashMap:: default( ) ;
ff0af1ee unknown 1 month ago
721
for & u in & kept {
722
indeg.entry ( u) .or_insert ( 0 ) ;
723
let rs = self .reduced_succ ( u, & kept, & mut memo) ;
724
for & w in & rs {
725
* indeg.entry ( w) .or_insert ( 0 ) + = 1 ;
726
}
727
rsucc.insert ( u, rs) ;
728
}
729
730
75167672 Andy McCall 1 month ago
731
let mut ready: BTreeSet< Vertex> = indeg
732
.iter ( )
733
.filter ( | ( _, &d ) | d = = 0 )
734
.map ( | ( v , _) | * v)
735
.collect ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
736
let mut side: HashMap< Vertex, u32 > = HashMap:: default( ) ;
737
let mut joins: HashSet< Vertex> = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
738
let mut next_side = 0 u32 ;
739
let mut plain: Vec< Vertex> = Vec :: new( ) ;
740
let mut conflict: Option< BTreeMap< u32 , Vec< Vertex> > > = None ;
741
let mut segments: Vec< Segment> = Vec :: new( ) ;
742
743
let flush_plain = | plain : & mut Vec< Vertex> , segments : & mut Vec< Segment> | {
75167672 Andy McCall 1 month ago
744
let atoms: Vec< AtomKey> = plain
745
.iter ( )
746
.filter_map ( | v | {
747
if let Vertex:: Atom( k) = v {
748
Some ( * k)
749
} else {
750
None
751
}
752
} )
753
.collect ( ) ;
ff0af1ee unknown 1 month ago
754
plain.clear ( ) ;
755
if ! atoms.is_empty ( ) {
756
segments.extend ( split_zombies ( atoms, & ghosts) ) ;
757
}
758
} ;
759
let finish_conflict = | c : BTreeMap< u32 , Vec< Vertex> > , segments : & mut Vec< Segment> | {
760
let sides: Vec< Vec< AtomKey> > = c
761
.into_values ( )
762
.map ( | vs | {
763
vs.into_iter ( )
764
.filter_map ( | v | match v {
765
Vertex:: Atom( k) if ! ghosts.contains ( & k) => Some ( k) ,
766
_ => None ,
767
} )
768
.collect:: < Vec< _ > > ( )
769
} )
770
.filter ( | s | ! s.is_empty ( ) )
771
.collect ( ) ;
772
match sides.len ( ) {
773
0 => { }
774
1 => segments.push ( Segment:: Lines( sides.into_iter ( ) .next ( ) .unwrap ( ) ) ) ,
775
_ => segments.push ( Segment:: Conflict( sides) ) ,
776
}
777
} ;
778
779
while ! ready.is_empty ( ) {
780
if ready.len ( ) > = 2 {
781
if conflict.is_none ( ) {
782
flush_plain ( & mut plain, & mut segments) ;
783
conflict = Some ( BTreeMap:: new( ) ) ;
784
}
785
for r in & ready {
786
if ! side.contains_key ( r) {
787
side.insert ( * r, next_side) ;
788
next_side + = 1 ;
789
}
790
}
791
}
792
let v = ready.pop_first ( ) .unwrap ( ) ;
793
let my_side = side.get ( & v) .copied ( ) ;
794
match ( & mut conflict, my_side) {
795
( Some ( c) , Some ( s) ) => c.entry ( s) .or_default ( ) .push ( v) ,
796
( Some ( _ ) , None ) => {
797
let c = conflict.take ( ) .unwrap ( ) ;
798
finish_conflict ( c, & mut segments) ;
799
plain.push ( v) ;
800
}
801
( None , _ ) => plain.push ( v) ,
802
}
803
for & w in & rsucc[ & v] {
804
let d = indeg.get_mut ( & w) .unwrap ( ) ;
805
* d - = 1 ;
806
if conflict.is_some ( ) & & ! joins.contains ( & w) {
807
match ( my_side, side.get ( & w) .copied ( ) ) {
808
( Some ( s) , None ) => {
809
side.insert ( w, s) ;
810
}
811
( Some ( s) , Some ( t) ) if s ! = t => {
812
side.remove ( & w) ;
813
joins.insert ( w) ;
814
}
815
( None , Some ( _ ) ) => {
816
side.remove ( & w) ;
817
joins.insert ( w) ;
818
}
819
_ => { }
820
}
821
}
822
if * d = = 0 {
823
ready.insert ( w) ;
824
}
825
}
826
}
827
if let Some ( c) = conflict.take ( ) {
828
finish_conflict ( c, & mut segments) ;
829
}
830
flush_plain ( & mut plain, & mut segments) ;
831
Materialized { segments }
832
}
833
834
835
836
pub fn render ( & self , m : & Materialized, label : & dyn Fn( &ChangeHash ) -> String) -> Vec< u8 > {
837
let total = m.conflict_count ( ) ;
838
let mut n = 0 ;
839
let mut out: Vec< u8 > = Vec :: new( ) ;
840
let push_atoms = | out : & mut Vec< u8 > , atoms : & [AtomKey]| {
841
for a in atoms {
842
if let Some ( c) = self .content ( a) {
843
out.extend_from_slice ( c) ;
844
}
845
}
846
} ;
847
let newline_if_needed = | out : & mut Vec< u8 > | {
848
if ! out.is_empty ( ) & & * out.last ( ) .unwrap ( ) ! = b ' \n ' {
849
out.push ( b ' \n ' ) ;
850
}
851
} ;
852
for seg in & m.segments {
853
match seg {
854
Segment:: Lines( a) => push_atoms ( & mut out, a) ,
855
Segment:: Conflict( sides) => {
856
n + = 1 ;
857
let k = sides.len ( ) ;
858
for ( i, s) in sides.iter ( ) .enumerate ( ) {
859
newline_if_needed ( & mut out) ;
860
let who = s.first ( ) .map ( | a | label ( & a.0 ) ) .unwrap_or_default ( ) ;
861
let marker = if i = = 0 { " <<<<<<<" } else { " =======" } ;
862
out.extend_from_slice (
863
format! ( " {marker} oxy conflict {n} of {total} , side {} of {k} : change {who} \n " , i + 1 ) .as_bytes ( ) ,
864
) ;
865
push_atoms ( & mut out, s) ;
866
}
867
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
868
out.extend_from_slice (
869
format! ( " >>>>>>> oxy conflict {n} of {total} end\n " ) .as_bytes ( ) ,
870
) ;
ff0af1ee unknown 1 month ago
871
}
872
Segment:: Zombie { deleted, inserted } => {
873
n + = 1 ;
874
newline_if_needed ( & mut out) ;
875
let deleter = deleted
876
.first ( )
877
.and_then ( | a | self .deleters ( a) .next ( ) .copied ( ) )
878
.map ( | d | label ( & d) )
879
.unwrap_or_default ( ) ;
880
let inserter = inserted.first ( ) .map ( | a | label ( & a.0 ) ) .unwrap_or_default ( ) ;
881
out.extend_from_slice (
882
format! ( " <<<<<<< oxy conflict {n} of {total} , side 1 of 2: deleted by change {deleter} \n -------\n " ) .as_bytes ( ) ,
883
) ;
884
push_atoms ( & mut out, deleted) ;
885
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
886
out.extend_from_slice (
887
format! (
888
" ======= oxy conflict {n} of {total} , side 2 of 2: change {inserter} \n "
889
)
890
.as_bytes ( ) ,
891
) ;
ff0af1ee unknown 1 month ago
892
push_atoms ( & mut out, inserted) ;
893
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
894
out.extend_from_slice (
895
format! ( " >>>>>>> oxy conflict {n} of {total} end\n " ) .as_bytes ( ) ,
896
) ;
ff0af1ee unknown 1 month ago
897
}
898
}
899
}
900
out
901
}
902
}
903
252e8cb2 Andy McCall 1 month ago ↶
904
fn vertex_value ( v : & Vertex) -> crate:: cbor:: Value {
905
use crate :: cbor:: Value;
906
match v {
907
Vertex:: Start => Value:: Uint( 0 ) ,
908
Vertex:: End => Value:: Uint( 1 ) ,
75167672 Andy McCall 1 month ago
909
Vertex:: Atom( ( c, i) ) => {
910
Value:: Array( vec! [ Value:: Bytes( c.0. to_vec ( ) ) , Value:: Uint( * i as u64 ) ] )
911
}
252e8cb2 Andy McCall 1 month ago ↶
912
}
913
}
914
915
fn vertex_from ( v : & crate:: cbor:: Value) -> Result< Vertex, crate:: objects:: ObjectError> {
916
use crate :: cbor:: Value;
917
use crate :: objects:: ObjectError;
918
match v {
919
Value:: Uint( 0 ) => Ok ( Vertex:: Start) ,
920
Value:: Uint( 1 ) => Ok ( Vertex:: End) ,
75167672 Andy McCall 1 month ago
921
Value:: Array( a) if a.len ( ) = = 2 => Ok ( Vertex:: Atom( (
922
crate :: objects:: oref( & a[ 0 ] , " vertex" ) ? ,
923
crate :: objects:: u32_( & a[ 1 ] , " vertex" ) ? ,
924
) ) ) ,
925
_ => Err ( ObjectError:: Schema(
926
" vertex: expected 0, 1, or [hash, index]" .into ( ) ,
927
) ) ,
252e8cb2 Andy McCall 1 month ago ↶
928
}
929
}
930
931
impl FileGraph {
932
933
pub fn to_value ( & self ) -> crate:: cbor:: Value {
934
use crate :: cbor:: Value;
935
let mut atoms: Vec< ( & AtomKey, & AtomInfo) > = self .atoms.iter ( ) .collect ( ) ;
936
atoms.sort_by_key ( | ( k , _) | * * k) ;
75167672 Andy McCall 1 month ago
937
let mut edges: Vec< ( Vertex, Vertex) > = self
938
.succ
939
.iter ( )
940
.flat_map ( | ( a , bs ) | bs.iter ( ) .map ( move | b| ( * a, * b) ) )
941
.collect ( ) ;
252e8cb2 Andy McCall 1 month ago ↶
942
edges.sort ( ) ;
943
Value:: map( [
944
(
945
0 ,
946
Value:: Array(
947
atoms
948
.into_iter ( )
949
.map ( | ( (c , i ) , info) | {
950
Value:: Array( vec! [
951
Value:: Bytes( c.0. to_vec ( ) ) ,
952
Value:: Uint( * i as u64 ) ,
75167672 Andy McCall 1 month ago
953
info.content
954
.as_ref ( )
01a47cd7 Andy McCall 1 month ago ↶
955
.map ( | b | Value:: Bytes( b.bytes ( ) .to_vec ( ) ) )
75167672 Andy McCall 1 month ago
956
.unwrap_or ( Value:: Null) ,
957
Value:: Array(
958
info.deleted_by
959
.iter ( )
960
.map ( | d | Value:: Bytes( d.0. to_vec ( ) ) )
961
.collect ( ) ,
962
) ,
252e8cb2 Andy McCall 1 month ago ↶
963
] )
964
} )
965
.collect ( ) ,
966
) ,
967
),
75167672 Andy McCall 1 month ago
968
(
969
1 ,
970
Value:: Array(
971
edges
972
.iter ( )
973
.map ( | ( a , b ) | Value:: Array( vec! [ vertex_value ( a) , vertex_value ( b) ] ) )
974
.collect ( ) ,
975
) ,
976
) ,
252e8cb2 Andy McCall 1 month ago ↶
977
] )
978
}
979
980
pub fn from_value ( v : & crate:: cbor:: Value) -> Result< FileGraph, crate:: objects:: ObjectError> {
981
use crate :: objects:: { array, bytes, field, map, oref, u32_, ObjectError} ;
982
let m = map ( v, " file graph" ) ? ;
75167672 Andy McCall 1 month ago
983
let mut g = FileGraph {
0bdc3f91 Andy McCall 1 month ago ↶
984
atoms: HashMap:: default( ) ,
985
succ: HashMap:: default( ) ,
dbf06d34 Andy McCall 1 month ago ↶
986
order: OrderSlot:: default( ) ,
75167672 Andy McCall 1 month ago
987
} ;
01a47cd7 Andy McCall 1 month ago ↶
988
let atoms = array ( field ( m, 0 , " atoms" ) ? , " atoms" ) ? ;
989
990
let mut texts: Vec< & [ u8 ] > = Vec :: new( ) ;
991
for a in atoms {
992
let e = array ( a, " atom" ) ? ;
993
if e.len ( ) = = 4 & & ! e[ 2 ] .is_null ( ) {
994
texts.push ( bytes ( & e[ 2 ] , " atom content" ) ? ) ;
995
}
996
}
997
let all: Lines = texts.into_iter ( ) .collect ( ) ;
998
let mut next = 0 u32 ;
999
for a in atoms {
252e8cb2 Andy McCall 1 month ago ↶
1000
let e = array ( a, " atom" ) ? ;
1001
if e.len ( ) ! = 4 {
1002
return Err ( ObjectError:: Schema( " atom: expected 4 fields" .into ( ) ) ) ;
1003
}
1004
let key = ( oref ( & e[ 0 ] , " atom change" ) ? , u32_ ( & e[ 1 ] , " atom index" ) ? ) ;
75167672 Andy McCall 1 month ago
1005
let content = if e[ 2 ] .is_null ( ) {
1006
None
1007
} else {
01a47cd7 Andy McCall 1 month ago ↶
1008
next + = 1 ;
1009
Some ( LineRef:: new( all.clone ( ) , next - 1 ) )
75167672 Andy McCall 1 month ago
1010
} ;
1011
let deleted_by = array ( & e[ 3 ] , " deleters" ) ?
1012
.iter ( )
1013
.map ( | d | oref ( d, " deleter" ) )
1014
.collect:: < Result< BTreeSet< _ > , _ > > ( ) ? ;
1015
g.atoms.insert (
1016
key,
1017
AtomInfo {
1018
content,
1019
deleted_by,
1020
} ,
1021
) ;
252e8cb2 Andy McCall 1 month ago ↶
1022
}
1023
for e in array ( field ( m, 1 , " edges" ) ? , " edges" ) ? {
1024
let pair = array ( e, " edge" ) ? ;
1025
if pair.len ( ) ! = 2 {
1026
return Err ( ObjectError:: Schema( " edge: expected [from, to]" .into ( ) ) ) ;
1027
}
1028
g.edge ( vertex_from ( & pair[ 0 ] ) ? , vertex_from ( & pair[ 1 ] ) ? ) ;
1029
}
1030
Ok ( g)
1031
}
1032
}
1033
ff0af1ee unknown 1 month ago
1034
1035
fn split_zombies ( atoms : Vec< AtomKey> , ghosts : & HashSet< AtomKey> ) -> Vec< Segment> {
1036
let mut out = Vec :: new( ) ;
1037
let mut lines: Vec< AtomKey> = Vec :: new( ) ;
1038
let mut i = 0 ;
1039
while i < atoms.len ( ) {
1040
if ! ghosts.contains ( & atoms[ i] ) {
1041
lines.push ( atoms[ i] ) ;
1042
i + = 1 ;
1043
continue ;
1044
}
1045
if ! lines.is_empty ( ) {
1046
out.push ( Segment:: Lines( std:: mem:: take( & mut lines) ) ) ;
1047
}
1048
let mut deleted = Vec :: new( ) ;
1049
while i < atoms.len ( ) & & ghosts.contains ( & atoms[ i] ) {
1050
deleted.push ( atoms[ i] ) ;
1051
i + = 1 ;
1052
}
1053
let mut inserted = Vec :: new( ) ;
1054
if i < atoms.len ( ) {
1055
let ch = atoms[ i] .0 ;
1056
while i < atoms.len ( ) & & atoms[ i] .0 = = ch & & ! ghosts.contains ( & atoms[ i] ) {
1057
inserted.push ( atoms[ i] ) ;
1058
i + = 1 ;
1059
}
1060
}
1061
out.push ( Segment:: Zombie { deleted, inserted } ) ;
1062
}
1063
if ! lines.is_empty ( ) {
1064
out.push ( Segment:: Lines( lines) ) ;
1065
}
1066
out
1067
}
1068
1069
# [ cfg ( test ) ]
1070
mod tests {
1071
use super :: * ;
1072
use crate :: hash:: ObjectRef;
1073
1074
fn h ( n : u8 ) -> ChangeHash {
1075
ObjectRef( [ n; 32 ] )
1076
}
01a47cd7 Andy McCall 1 month ago ↶
1077
fn lines ( v : & [& str ]) -> Lines {
1078
v.iter ( ) .map ( | s | s.as_bytes ( ) ) .collect ( )
ff0af1ee unknown 1 month ago
1079
}
1080
fn text ( g : & FileGraph, m : & Materialized) -> String {
1081
String :: from_utf8( g.render ( m, & | c| c.short ( 4 ) ) ) .unwrap ( )
1082
}
1083
1084
struct Deps ( HashMap< ChangeHash, Vec< ChangeHash> > ) ;
1085
impl DepOracle for Deps {
1086
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
1087
if a = = b {
1088
return true ;
1089
}
1090
let mut stack = vec! [ * a] ;
0bdc3f91 Andy McCall 1 month ago ↶
1091
let mut seen = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
1092
while let Some ( x) = stack.pop ( ) {
1093
if let Some ( ds) = self .0. get ( & x) {
1094
for d in ds {
1095
if d = = b {
1096
return true ;
1097
}
1098
if seen.insert ( * d) {
1099
stack.push ( * d) ;
1100
}
1101
}
1102
}
1103
}
1104
false
e83354cd Andy McCall 1 month ago ↶
1105
}
1106
}
1107
1108
1109
struct Linear ;
1110
impl DepOracle for Linear {
1111
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
1112
a.0 [ .. 2 ] > = b.0 [ .. 2 ]
1113
}
1114
}
1115
1116
1117
1118
fn edited_file ( n : usize , revs : usize , per : usize ) -> FileGraph {
1119
let hn = | i : usize | {
1120
let mut b = [ 0 u8 ; 32 ] ;
1121
b[ .. 2 ] .copy_from_slice ( & ( i as u16 ) .to_be_bytes ( ) ) ;
1122
ObjectRef( b)
1123
} ;
1124
let mut g = FileGraph:: new( ) ;
1125
let first: Vec< String> = ( 0 .. n) .map ( | i | format! ( " line {i} \n " ) ) .collect ( ) ;
1126
let first: Vec< & str > = first.iter ( ) .map ( String :: as_str) .collect ( ) ;
1127
g.insert ( hn ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & first) ) ;
1128
for r in 2 .. revs + 2 {
1129
let order = g.materialize ( & Linear) .live_atoms ( ) ;
1130
let step = order.len ( ) / per;
1131
for j in 0 .. per {
1132
let at = j * step + ( r % step.max ( 1 ) ) ;
1133
let k = order[ at] ;
1134
g.delete (
1135
hn ( r) ,
1136
& AtomRange {
1137
change: k.0 ,
1138
from: k.1 ,
1139
to: k.1 + 1 ,
1140
} ,
1141
) ;
1142
let after = if at = = 0 {
1143
Vertex:: Start
1144
} else {
1145
Vertex:: Atom( order[ at - 1 ] )
1146
} ;
1147
let before = order
1148
.get ( at + 1 )
1149
.map ( | k | Vertex:: Atom( * k) )
1150
.unwrap_or ( Vertex:: End) ;
1151
g.insert ( hn ( r) , j as u32 , after, before, & lines ( & [ " new\n " ] ) ) ;
1152
}
ff0af1ee unknown 1 month ago
1153
}
e83354cd Andy McCall 1 month ago ↶
1154
g
1155
}
1156
1157
1158
# [ test ]
1159
fn the_order_shortcut_agrees_with_the_general_order ( ) {
1160
let g = edited_file ( 500 , 10 , 20 ) ;
1161
assert! ( g.as_chain ( ) .is_none ( ) ) ;
1162
let fast = g.as_order ( & Linear) .expect ( " a single order" ) ;
1163
assert_eq! (
1164
Materialized {
1165
segments: vec! [ Segment:: Lines( fast) ]
1166
} ,
1167
g.materialize_general ( & Linear)
1168
) ;
1169
1170
1171
let mut g = FileGraph:: new( ) ;
1172
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
1173
let a = Vertex:: Atom( ( h ( 1 ) , 0 ) ) ;
1174
g.insert ( h ( 2 ) , 0 , a, Vertex:: End, & lines ( & [ " b\n " ] ) ) ;
1175
g.insert ( h ( 3 ) , 0 , a, Vertex:: End, & lines ( & [ " c\n " ] ) ) ;
1176
assert! ( g.as_order ( & NoDeps) .is_none ( ) ) ;
1177
assert! ( g.materialize ( & NoDeps) .is_conflicted ( ) ) ;
dbf06d34 Andy McCall 1 month ago ↶
1178
}
1179
1180
1181
1182
fn apply_spliced (
1183
g : & mut FileGraph,
1184
h : ChangeHash,
1185
inserts : & [( Vertex , Vertex , usize ) ],
1186
deleted : & [AtomKey],
1187
) {
1188
let order = g.take_order ( ) ;
1189
let mut runs = Vec :: new( ) ;
1190
let mut next = 0 u32 ;
1191
for ( i, & ( a, b, n) ) in inserts.iter ( ) .enumerate ( ) {
1192
let text: Vec< String> = ( 0 .. n) .map ( | j | format! ( " {i} .{j} \n " ) ) .collect ( ) ;
1193
let text: Vec< & str > = text.iter ( ) .map ( String :: as_str) .collect ( ) ;
1194
g.insert ( h, next, a, b, & lines ( & text) ) ;
1195
runs.push ( ( a, b, next, n as u32 ) ) ;
1196
next + = n as u32 ;
1197
}
1198
for k in deleted {
1199
g.delete (
1200
h,
1201
& AtomRange {
1202
change: k.0 ,
1203
from: k.1 ,
1204
to: k.1 + 1 ,
1205
} ,
1206
) ;
1207
}
1208
if let Some ( o) = order {
1209
g.keep_order ( o.splice ( h, & runs, deleted) ) ;
1210
}
1211
}
1212
1213
1214
1215
fn random_edits (
1216
l : & [AtomKey],
1217
rnd : & mut impl FnMut( usize ) -> usize ,
1218
) -> ( Vec< ( Vertex, Vertex, usize ) > , Vec< AtomKey> ) {
1219
let ( mut inserts, mut deleted) = ( Vec :: new( ) , Vec :: new( ) ) ;
1220
let mut i = rnd ( 3 ) ;
1221
while i < = l.len ( ) {
1222
let del = rnd ( 3 ) .min ( l.len ( ) - i) ;
1223
let add = rnd ( 3 ) ;
1224
let after = if i = = 0 {
1225
Vertex:: Start
1226
} else {
1227
Vertex:: Atom( l[ i - 1 ] )
1228
} ;
1229
let before = l.get ( i) .map ( | k | Vertex:: Atom( * k) ) .unwrap_or ( Vertex:: End) ;
1230
deleted.extend ( & l[ i.. i + del] ) ;
1231
if add > 0 {
1232
inserts.push ( ( after, before, add) ) ;
1233
}
1234
i + = del + 1 + rnd ( 6 ) ;
1235
}
1236
( inserts, deleted)
1237
}
1238
1239
1240
1241
1242
# [ test ]
1243
fn the_kept_order_follows_edits ( ) {
1244
let hn = | i : usize | {
1245
let mut b = [ 0 u8 ; 32 ] ;
1246
b[ .. 2 ] .copy_from_slice ( & ( i as u16 ) .to_be_bytes ( ) ) ;
1247
ObjectRef( b)
1248
} ;
1249
let mut seed = 7 u64 ;
1250
let mut rnd = move | n: usize | {
1251
seed = seed
1252
.wrapping_mul ( 6364136223846793005 )
1253
.wrapping_add ( 1442695040888963407 ) ;
1254
( ( seed > > 33 ) as usize ) % n.max ( 1 )
1255
} ;
1256
let mut deps = Deps( HashMap:: default( ) ) ;
1257
let mut g = FileGraph:: new( ) ;
1258
let first: Vec< String> = ( 0 .. 40 ) .map ( | i | format! ( " {i} \n " ) ) .collect ( ) ;
1259
let first: Vec< & str > = first.iter ( ) .map ( String :: as_str) .collect ( ) ;
1260
g.insert ( hn ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & first) ) ;
1261
let mut known: Vec< ChangeHash> = vec! [ hn ( 1 ) ] ;
1262
let mut c = 2 ;
1263
let ( mut spliced, mut conflicted) = ( 0 , 0 ) ;
1264
for step in 0 .. 400 {
1265
let l = g.materialize ( & deps) .live_atoms ( ) ;
1266
1267
1268
let pair = step % 7 = = 3 ;
1269
let base = known.clone ( ) ;
1270
for _ in 0 .. if pair { 2 } else { 1 } {
1271
let h = hn ( c) ;
1272
c + = 1 ;
1273
let ( inserts, deleted) = random_edits ( & l, & mut rnd) ;
1274
deps.0. insert ( h, base.clone ( ) ) ;
1275
apply_spliced ( & mut g, h, & inserts, & deleted) ;
1276
known.push ( h) ;
1277
if g.order.get ( ) .is_some ( ) {
1278
spliced + = 1 ;
1279
}
1280
let m = g.materialize ( & deps) ;
1281
assert_eq! ( m, g.materialize_general ( & deps) , " step {step}" ) ;
1282
if m.is_conflicted ( ) {
1283
conflicted + = 1 ;
1284
}
1285
}
1286
1287
1288
if g.materialize ( & deps) .is_conflicted ( ) {
1289
let h = hn ( c) ;
1290
c + = 1 ;
1291
let all = g.materialize ( & deps) .live_atoms ( ) ;
1292
deps.0. insert ( h, known.clone ( ) ) ;
1293
apply_spliced ( & mut g, h, & [ ( Vertex:: Start, Vertex:: End, 5 ) ] , & all) ;
1294
known.push ( h) ;
1295
assert_eq! ( g.materialize ( & deps) , g.materialize_general ( & deps) ) ;
1296
}
1297
}
1298
assert! (
1299
spliced > 100 & & conflicted > 0 ,
1300
" {spliced} spliced, {conflicted} conflicted"
1301
) ;
e83354cd Andy McCall 1 month ago ↶
1302
}
1303
1304
1305
# [ test ]
1306
# [ ignore ]
1307
fn bench_materialize_edited_file ( ) {
1308
let g = edited_file ( 20_000 , 50 , 100 ) ;
1309
let t = std:: time:: Instant:: now( ) ;
1310
let mut n = 0 ;
1311
for _ in 0 .. 20 {
1312
n + = g.materialize ( & Linear) .live_atoms ( ) .len ( ) ;
1313
}
1314
eprintln! (
1315
" materialize: {:.2} ms each ({n} atoms)" ,
1316
t.elapsed ( ) .as_secs_f64 ( ) * 1000. 0 / 20. 0
1317
) ;
598009a7 Andy McCall 1 month ago ↶
1318
}
1319
1320
1321
1322
# [ test ]
1323
fn the_chain_shortcut_agrees_with_the_general_order ( ) {
1324
let mut g = FileGraph:: new( ) ;
1325
g.insert (
1326
h ( 1 ) ,
1327
0 ,
1328
Vertex:: Start,
1329
Vertex:: End,
1330
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1331
) ;
1332
assert! ( g.as_chain ( ) .is_some ( ) ) ;
1333
assert_eq! ( g.materialize ( & NoDeps) , g.materialize_general ( & NoDeps) ) ;
1334
1335
g.insert (
1336
h ( 2 ) ,
1337
0 ,
1338
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1339
Vertex:: End,
1340
& lines ( & [ " d\n " ] ) ,
1341
) ;
1342
assert! ( g.as_chain ( ) .is_some ( ) ) ;
1343
assert_eq! ( g.materialize ( & NoDeps) , g.materialize_general ( & NoDeps) ) ;
1344
1345
g.insert (
1346
h ( 4 ) ,
1347
0 ,
1348
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1349
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1350
& lines ( & [ " x\n " ] ) ,
1351
) ;
1352
assert! ( g.as_chain ( ) .is_none ( ) ) ;
1353
assert_eq! ( text ( & g, & g.materialize ( & NoDeps) ) , " a\n x\n b\n c\n d\n " ) ;
1354
1355
let mut c = FileGraph:: new( ) ;
1356
c.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
1357
c.insert ( h ( 2 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " b\n " ] ) ) ;
1358
assert! ( c.as_chain ( ) .is_none ( ) ) ;
1359
assert! ( c.materialize ( & NoDeps) .is_conflicted ( ) ) ;
1360
1361
let mut d = FileGraph:: new( ) ;
1362
d.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
1363
d.delete (
1364
h ( 3 ) ,
1365
& AtomRange {
1366
change: h ( 1 ) ,
1367
from: 0 ,
1368
to: 1 ,
1369
} ,
1370
) ;
1371
assert! ( d.as_chain ( ) .is_none ( ) ) ;
1372
assert_eq! ( d.materialize ( & NoDeps) , d.materialize_general ( & NoDeps) ) ;
1373
1374
let e = FileGraph:: new( ) ;
1375
assert_eq! ( e.materialize ( & NoDeps) , e.materialize_general ( & NoDeps) ) ;
ff0af1ee unknown 1 month ago
1376
}
1377
1378
# [ test ]
1379
fn sequential_inserts_and_deletes ( ) {
1380
let mut g = FileGraph:: new( ) ;
75167672 Andy McCall 1 month ago
1381
g.insert (
1382
h ( 1 ) ,
1383
0 ,
1384
Vertex:: Start,
1385
Vertex:: End,
1386
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1387
) ;
ff0af1ee unknown 1 month ago
1388
let m = g.materialize ( & NoDeps) ;
1389
assert! ( ! m.is_conflicted ( ) ) ;
1390
assert_eq! ( text ( & g, & m) , " a\n b\n c\n " ) ;
1391
1392
75167672 Andy McCall 1 month ago
1393
g.insert (
1394
h ( 2 ) ,
1395
0 ,
1396
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1397
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1398
& lines ( & [ " x\n " ] ) ,
1399
) ;
1400
g.delete (
1401
h ( 2 ) ,
1402
& AtomRange {
1403
change: h ( 1 ) ,
1404
from: 0 ,
1405
to: 1 ,
1406
} ,
1407
) ;
ff0af1ee unknown 1 month ago
1408
let deps = Deps( [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) ] .into_iter ( ) .collect ( ) ) ;
1409
let m = g.materialize ( & deps) ;
1410
assert! ( ! m.is_conflicted ( ) ) ;
1411
assert_eq! ( text ( & g, & m) , " b\n x\n c\n " ) ;
1412
assert_eq! ( m.live_atoms ( ) , vec! [ ( h ( 1 ) , 1 ) , ( h ( 2 ) , 0 ) , ( h ( 1 ) , 2 ) ] ) ;
1413
}
1414
1415
# [ test ]
1416
fn concurrent_inserts_at_same_anchor_conflict ( ) {
1417
let mut g = FileGraph:: new( ) ;
1418
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1419
g.insert (
1420
h ( 2 ) ,
1421
0 ,
1422
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1423
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1424
& lines ( & [ " from-2\n " ] ) ,
1425
) ;
1426
g.insert (
1427
h ( 3 ) ,
1428
0 ,
1429
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1430
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1431
& lines ( & [ " from-3\n " , " more-3\n " ] ) ,
1432
) ;
1433
let deps = Deps(
1434
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1435
.into_iter ( )
1436
.collect ( ) ,
1437
) ;
ff0af1ee unknown 1 month ago
1438
let m = g.materialize ( & deps) ;
1439
assert! ( m.is_conflicted ( ) ) ;
1440
assert_eq! ( m.conflict_count ( ) , 1 ) ;
1441
assert_eq! (
1442
m.segments,
1443
vec! [
1444
Segment:: Lines( vec! [ ( h ( 1 ) , 0 ) ] ) ,
1445
Segment:: Conflict( vec! [ vec! [ ( h ( 2 ) , 0 ) ] , vec! [ ( h ( 3 ) , 0 ) , ( h ( 3 ) , 1 ) ] ] ) ,
1446
Segment:: Lines( vec! [ ( h ( 1 ) , 1 ) ] ) ,
1447
]
1448
) ;
1449
let t = text ( & g, & m) ;
1450
assert! ( t.starts_with ( " a\n <<<<<<< oxy conflict 1 of 1, side 1 of 2: change 0202\n from-2\n ======= oxy conflict 1 of 1, side 2 of 2: change 0303\n from-3\n more-3\n >>>>>>> oxy conflict 1 of 1 end\n b\n " ) , " {t}" ) ;
1451
}
1452
1453
# [ test ]
1454
fn concurrent_inserts_at_different_anchors_do_not_conflict ( ) {
1455
let mut g = FileGraph:: new( ) ;
75167672 Andy McCall 1 month ago
1456
g.insert (
1457
h ( 1 ) ,
1458
0 ,
1459
Vertex:: Start,
1460
Vertex:: End,
1461
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
1462
) ;
1463
g.insert (
1464
h ( 2 ) ,
1465
0 ,
1466
Vertex:: Start,
1467
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1468
& lines ( & [ " top\n " ] ) ,
1469
) ;
1470
g.insert (
1471
h ( 3 ) ,
1472
0 ,
1473
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
1474
Vertex:: End,
1475
& lines ( & [ " bottom\n " ] ) ,
1476
) ;
1477
let deps = Deps(
1478
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1479
.into_iter ( )
1480
.collect ( ) ,
1481
) ;
ff0af1ee unknown 1 month ago
1482
let m = g.materialize ( & deps) ;
1483
assert! ( ! m.is_conflicted ( ) ) ;
1484
assert_eq! ( text ( & g, & m) , " top\n a\n b\n c\n bottom\n " ) ;
1485
}
1486
1487
# [ test ]
1488
fn concurrent_deletes_of_the_same_line_agree ( ) {
1489
let mut g = FileGraph:: new( ) ;
1490
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1491
g.delete (
1492
h ( 2 ) ,
1493
& AtomRange {
1494
change: h ( 1 ) ,
1495
from: 0 ,
1496
to: 1 ,
1497
} ,
1498
) ;
1499
g.delete (
1500
h ( 3 ) ,
1501
& AtomRange {
1502
change: h ( 1 ) ,
1503
from: 0 ,
1504
to: 1 ,
1505
} ,
1506
) ;
1507
let deps = Deps(
1508
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1509
.into_iter ( )
1510
.collect ( ) ,
1511
) ;
ff0af1ee unknown 1 month ago
1512
let m = g.materialize ( & deps) ;
1513
assert! ( ! m.is_conflicted ( ) ) ;
1514
assert_eq! ( text ( & g, & m) , " b\n " ) ;
1515
}
1516
1517
# [ test ]
1518
fn delete_insert_conflict_is_a_zombie ( ) {
1519
let mut g = FileGraph:: new( ) ;
1520
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
1521
75167672 Andy McCall 1 month ago
1522
g.delete (
1523
h ( 2 ) ,
1524
& AtomRange {
1525
change: h ( 1 ) ,
1526
from: 0 ,
1527
to: 1 ,
1528
} ,
1529
) ;
1530
g.insert (
1531
h ( 3 ) ,
1532
0 ,
1533
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1534
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1535
& lines ( & [ " after-a\n " ] ) ,
1536
) ;
1537
let deps = Deps(
1538
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1539
.into_iter ( )
1540
.collect ( ) ,
1541
) ;
ff0af1ee unknown 1 month ago
1542
let m = g.materialize ( & deps) ;
1543
assert! ( m.is_conflicted ( ) ) ;
1544
assert_eq! (
1545
m.segments,
1546
vec! [
75167672 Andy McCall 1 month ago
1547
Segment:: Zombie {
1548
deleted: vec! [ ( h ( 1 ) , 0 ) ] ,
1549
inserted: vec! [ ( h ( 3 ) , 0 ) ]
1550
} ,
ff0af1ee unknown 1 month ago
1551
Segment:: Lines( vec! [ ( h ( 1 ) , 1 ) ] ) ,
1552
]
1553
) ;
1554
let t = text ( & g, & m) ;
1555
assert! ( t.contains ( " -------\n a\n =======" ) , " {t}" ) ;
1556
assert! ( t.contains ( " after-a\n >>>>>>>" ) , " {t}" ) ;
1557
1558
75167672 Andy McCall 1 month ago
1559
let deps = Deps(
1560
[ ( h ( 2 ) , vec! [ h ( 1 ) , h ( 3 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1561
.into_iter ( )
1562
.collect ( ) ,
1563
) ;
ff0af1ee unknown 1 month ago
1564
let m = g.materialize ( & deps) ;
1565
assert! ( ! m.is_conflicted ( ) ) ;
1566
assert_eq! ( text ( & g, & m) , " after-a\n b\n " ) ;
1567
}
1568
1569
# [ test ]
23b217d7 Andy McCall 1 month ago ↶
1570
fn insert_after_a_line_deleted_by_a_dependency_is_not_a_conflict ( ) {
1571
1572
1573
let mut g = FileGraph:: new( ) ;
1574
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1575
g.delete (
1576
h ( 2 ) ,
1577
& AtomRange {
1578
change: h ( 1 ) ,
1579
from: 1 ,
1580
to: 2 ,
1581
} ,
1582
) ;
1583
g.insert (
1584
h ( 3 ) ,
1585
0 ,
1586
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1587
Vertex:: End,
1588
& lines ( & [ " c\n " ] ) ,
1589
) ;
1590
let deps = Deps(
1591
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 2 ) ] ) ]
1592
.into_iter ( )
1593
.collect ( ) ,
1594
) ;
23b217d7 Andy McCall 1 month ago ↶
1595
let m = g.materialize ( & deps) ;
1596
assert! ( ! m.is_conflicted ( ) , " {:?}" , m.segments) ;
1597
assert_eq! ( text ( & g, & m) , " a\n c\n " ) ;
1598
1599
1600
let mut g = FileGraph:: new( ) ;
1601
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " x\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1602
g.delete (
1603
h ( 1 ) ,
1604
& AtomRange {
1605
change: h ( 1 ) ,
1606
from: 0 ,
1607
to: 1 ,
1608
} ,
1609
) ;
1610
g.insert (
1611
h ( 2 ) ,
1612
0 ,
1613
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1614
Vertex:: End,
1615
& lines ( & [ " y\n " ] ) ,
1616
) ;
23b217d7 Andy McCall 1 month ago ↶
1617
let deps = Deps( [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) ] .into_iter ( ) .collect ( ) ) ;
1618
let m = g.materialize ( & deps) ;
1619
assert! ( ! m.is_conflicted ( ) ) ;
1620
assert_eq! ( text ( & g, & m) , " y\n " ) ;
1621
}
1622
1623
# [ test ]
ff0af1ee unknown 1 month ago
1624
fn resolution_collapses_a_conflict ( ) {
1625
let mut g = FileGraph:: new( ) ;
1626
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1627
g.insert (
1628
h ( 2 ) ,
1629
0 ,
1630
Vertex:: Start,
1631
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1632
& lines ( & [ " x\n " ] ) ,
1633
) ;
1634
g.insert (
1635
h ( 3 ) ,
1636
0 ,
1637
Vertex:: Start,
1638
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1639
& lines ( & [ " y\n " ] ) ,
1640
) ;
1641
let mut deps: HashMap< _ , _ > = [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1642
.into_iter ( )
1643
.collect ( ) ;
ff0af1ee unknown 1 month ago
1644
assert! ( g.materialize ( & Deps( deps.clone ( ) ) ) .is_conflicted ( ) ) ;
1645
75167672 Andy McCall 1 month ago
1646
g.delete (
1647
h ( 4 ) ,
1648
& AtomRange {
1649
change: h ( 2 ) ,
1650
from: 0 ,
1651
to: 1 ,
1652
} ,
1653
) ;
ff0af1ee unknown 1 month ago
1654
deps.insert ( h ( 4 ) , vec! [ h ( 2 ) , h ( 3 ) ] ) ;
1655
let m = g.materialize ( & Deps( deps) ) ;
1656
assert! ( ! m.is_conflicted ( ) ) ;
1657
assert_eq! ( text ( & g, & m) , " y\n a\n " ) ;
1658
}
1659
1660
# [ test ]
1661
fn empty_and_unterminated_files ( ) {
1662
let g = FileGraph:: new( ) ;
1663
let m = g.materialize ( & NoDeps) ;
1664
assert_eq! ( m.segments, vec! [ ] ) ;
1665
assert_eq! ( text ( & g, & m) , " " ) ;
1666
let mut g = FileGraph:: new( ) ;
1667
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " no newline" ] ) ) ;
1668
assert_eq! ( text ( & g, & g.materialize ( & NoDeps) ) , " no newline" ) ;
1669
}
1670
252e8cb2 Andy McCall 1 month ago ↶
1671
# [ test ]
1672
fn serialization_round_trip ( ) {
1673
let mut g = FileGraph:: new( ) ;
1674
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1675
g.insert (
1676
h ( 2 ) ,
1677
0 ,
1678
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1679
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1680
& lines ( & [ " x\n " ] ) ,
1681
) ;
1682
g.delete (
1683
h ( 3 ) ,
1684
& AtomRange {
1685
change: h ( 1 ) ,
1686
from: 1 ,
1687
to: 2 ,
1688
} ,
1689
) ;
252e8cb2 Andy McCall 1 month ago ↶
1690
let v = g.to_value ( ) ;
1691
let bytes = crate :: cbor:: encode( & v) ;
1692
let back = FileGraph:: from_value( & crate :: cbor:: decode( & bytes) .unwrap ( ) ) .unwrap ( ) ;
75167672 Andy McCall 1 month ago
1693
let deps = Deps(
1694
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1695
.into_iter ( )
1696
.collect ( ) ,
1697
) ;
252e8cb2 Andy McCall 1 month ago ↶
1698
assert_eq! ( back.materialize ( & deps) , g.materialize ( & deps) ) ;
1699
assert_eq! ( text ( & back, & back.materialize ( & deps) ) , " a\n x\n " ) ;
75167672 Andy McCall 1 month ago
1700
assert_eq! (
1701
crate :: cbor:: encode( & back.to_value ( ) ) ,
1702
bytes,
1703
" deterministic"
1704
) ;
252e8cb2 Andy McCall 1 month ago ↶
1705
}
1706
ff0af1ee unknown 1 month ago
1707
1708
# [ test ]
1709
fn application_order_is_irrelevant ( ) {
1710
use rand:: seq:: SliceRandom;
75167672 Andy McCall 1 month ago
1711
type Op = (
1712
ChangeHash,
01a47cd7 Andy McCall 1 month ago ↶
1713
Vec< ( u32 , Vertex, Vertex, Lines) > ,
75167672 Andy McCall 1 month ago
1714
Vec< AtomRange> ,
1715
) ;
ff0af1ee unknown 1 month ago
1716
let ops: Vec< Op> = vec! [
75167672 Andy McCall 1 month ago
1717
(
1718
h ( 1 ) ,
1719
vec! [ ( 0 , Vertex:: Start, Vertex:: End, lines ( & [ " a\n " , " b\n " , " c\n " ] ) ) ] ,
1720
vec! [ ] ,
1721
) ,
1722
(
1723
h ( 2 ) ,
1724
vec! [ (
1725
0 ,
1726
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1727
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1728
lines ( & [ " p\n " ] ) ,
1729
) ] ,
1730
vec! [ ] ,
1731
) ,
1732
(
1733
h ( 3 ) ,
1734
vec! [ (
1735
0 ,
1736
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1737
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1738
lines ( & [ " q\n " , " r\n " ] ) ,
1739
) ] ,
1740
vec! [ AtomRange {
1741
change: h ( 1 ) ,
1742
from: 2 ,
1743
to: 3 ,
1744
} ] ,
1745
) ,
1746
(
1747
h ( 4 ) ,
1748
vec! [ (
1749
0 ,
1750
Vertex:: Atom( ( h ( 3 ) , 1 ) ) ,
1751
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1752
lines ( & [ " s\n " ] ) ,
1753
) ] ,
1754
vec! [ AtomRange {
1755
change: h ( 1 ) ,
1756
from: 1 ,
1757
to: 2 ,
1758
} ] ,
1759
) ,
1760
(
1761
h ( 5 ) ,
1762
vec! [ ( 0 , Vertex:: Atom( ( h ( 1 ) , 2 ) ) , Vertex:: End, lines ( & [ " z\n " ] ) ) ] ,
1763
vec! [ ] ,
1764
) ,
ff0af1ee unknown 1 month ago
1765
] ;
1766
let deps = Deps(
75167672 Andy McCall 1 month ago
1767
[
1768
( h ( 2 ) , vec! [ h ( 1 ) ] ) ,
1769
( h ( 3 ) , vec! [ h ( 1 ) ] ) ,
1770
( h ( 4 ) , vec! [ h ( 3 ) , h ( 1 ) ] ) ,
1771
( h ( 5 ) , vec! [ h ( 1 ) ] ) ,
1772
]
1773
.into_iter ( )
1774
.collect ( ) ,
ff0af1ee unknown 1 month ago
1775
) ;
1776
let build = | order : & [usize ]| {
1777
let mut g = FileGraph:: new( ) ;
1778
for & i in order {
1779
let ( c, ins, dels) = & ops[ i] ;
1780
for ( idx, a, b, l) in ins {
1781
g.insert ( * c, * idx, * a, * b, l) ;
1782
}
1783
for d in dels {
1784
g.delete ( * c, d) ;
1785
}
1786
}
1787
let m = g.materialize ( & deps) ;
1788
( m.clone ( ) , text ( & g, & m) )
1789
} ;
1790
let reference = build ( & [ 0 , 1 , 2 , 3 , 4 ] ) ;
1791
assert! ( reference.0. is_conflicted ( ) ) ;
1792
let mut rng = rand:: thread_rng( ) ;
1793
let mut order: Vec< usize > = ( 0 .. ops.len ( ) ) .collect ( ) ;
1794
for _ in 0 .. 50 {
1795
order.shuffle ( & mut rng) ;
1796
assert_eq! ( build ( & order) , reference, " order {order:?}" ) ;
1797
}
1798
}
1799
}