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> ,
49
}
50
51
52
53
# [ derive ( Clone, Debug, Default, PartialEq, Eq ) ]
54
enum Edges {
55
# [ default ]
56
None ,
57
One( Vertex) ,
58
Many( Vec< Vertex> ) ,
ff0af1ee unknown 1 month ago
59
}
60
0bdc3f91 Andy McCall 1 month ago ↶
61
impl Edges {
62
fn insert ( & mut self , v : Vertex) {
63
match self {
64
Edges:: None => * self = Edges:: One( v) ,
65
Edges:: One( a) if * a = = v => { }
66
Edges:: One( a) => {
67
let a = * a;
68
* self = Edges:: Many( if a < v { vec! [ a, v] } else { vec! [ v, a] } ) ;
69
}
70
Edges:: Many( list) => {
71
if let Err ( i) = list.binary_search ( & v) {
72
list.insert ( i, v) ;
73
}
74
}
75
}
76
}
77
78
fn as_slice ( & self ) -> & [ Vertex] {
79
match self {
80
Edges:: None => & [ ] ,
81
Edges:: One( v) => std:: slice:: from_ref( v) ,
82
Edges:: Many( list) => list,
83
}
84
}
85
86
fn iter ( & self ) -> std:: slice:: Iter< '_ , Vertex> {
87
self .as_slice ( ) .iter ( )
88
}
89
}
90
ff0af1ee unknown 1 month ago
91
impl Default for FileGraph {
92
fn default ( ) -> Self {
93
Self :: new( )
94
}
95
}
96
97
98
# [ derive ( Clone, Debug, PartialEq, Eq ) ]
99
pub enum Segment {
100
Lines( Vec< AtomKey> ) ,
101
102
Conflict( Vec< Vec< AtomKey> > ) ,
103
104
75167672 Andy McCall 1 month ago
105
Zombie {
106
deleted: Vec< AtomKey> ,
107
inserted: Vec< AtomKey> ,
108
} ,
ff0af1ee unknown 1 month ago
109
}
110
111
# [ derive ( Clone, Debug, PartialEq, Eq, Default ) ]
112
pub struct Materialized {
113
pub segments : Vec< Segment> ,
114
}
115
116
impl Materialized {
117
pub fn is_conflicted ( & self ) -> bool {
75167672 Andy McCall 1 month ago
118
self .segments
119
.iter ( )
120
.any ( | s | ! matches! ( s, Segment:: Lines( _ ) ) )
ff0af1ee unknown 1 month ago
121
}
122
pub fn conflict_count ( & self ) -> usize {
75167672 Andy McCall 1 month ago
123
self .segments
124
.iter ( )
125
.filter ( | s | ! matches! ( s, Segment:: Lines( _ ) ) )
126
.count ( )
ff0af1ee unknown 1 month ago
127
}
128
129
pub fn live_atoms ( & self ) -> Vec< AtomKey> {
130
let mut out = Vec :: new( ) ;
131
for s in & self .segments {
132
match s {
133
Segment:: Lines( a) => out.extend ( a) ,
134
Segment:: Conflict( sides) => sides.iter ( ) .for_each ( | x | out.extend ( x) ) ,
135
Segment:: Zombie { inserted, .. } => out.extend ( inserted) ,
136
}
137
}
138
out
139
}
140
}
141
142
impl FileGraph {
143
pub fn new ( ) -> Self {
75167672 Andy McCall 1 month ago
144
let mut g = FileGraph {
0bdc3f91 Andy McCall 1 month ago ↶
145
atoms: HashMap:: default( ) ,
146
succ: HashMap:: default( ) ,
75167672 Andy McCall 1 month ago
147
} ;
ff0af1ee unknown 1 month ago
148
g.edge ( Vertex:: Start, Vertex:: End) ;
149
g
150
}
151
152
fn edge ( & mut self , a : Vertex, b : Vertex) {
153
self .succ.entry ( a) .or_default ( ) .insert ( b) ;
154
self .succ.entry ( b) .or_default ( ) ;
155
}
156
157
75167672 Andy McCall 1 month ago
158
pub fn insert (
159
& mut self ,
160
change : ChangeHash,
161
first_index : u32 ,
162
after : Vertex,
163
before : Vertex,
01a47cd7 Andy McCall 1 month ago ↶
164
lines : & Lines,
0bdc3f91 Andy McCall 1 month ago ↶
165
) {
01a47cd7 Andy McCall 1 month ago ↶
166
self .insert_owned ( change, first_index, after, before, lines.clone ( ) ) ;
0bdc3f91 Andy McCall 1 month ago ↶
167
}
168
169
170
171
172
pub fn insert_owned (
173
& mut self ,
174
change : ChangeHash,
175
first_index : u32 ,
176
after : Vertex,
177
before : Vertex,
01a47cd7 Andy McCall 1 month ago ↶
178
lines : Lines,
75167672 Andy McCall 1 month ago
179
) {
0bdc3f91 Andy McCall 1 month ago ↶
180
self .atoms.reserve ( lines.len ( ) ) ;
181
self .succ.reserve ( lines.len ( ) + 1 ) ;
ff0af1ee unknown 1 month ago
182
let mut prev = after;
01a47cd7 Andy McCall 1 month ago ↶
183
for i in 0 .. lines.len ( ) {
ff0af1ee unknown 1 month ago
184
let key = ( change, first_index + i as u32 ) ;
01a47cd7 Andy McCall 1 month ago ↶
185
self .atoms.entry ( key) .or_default ( ) .content =
186
Some ( LineRef:: new( lines.clone ( ) , i as u32 ) ) ;
ff0af1ee unknown 1 month ago
187
let v = Vertex:: Atom( key) ;
0bdc3f91 Andy McCall 1 month ago ↶
188
self .succ.entry ( prev) .or_default ( ) .insert ( v) ;
ff0af1ee unknown 1 month ago
189
prev = v;
190
}
0bdc3f91 Andy McCall 1 month ago ↶
191
self .succ.entry ( prev) .or_default ( ) .insert ( before) ;
192
self .succ.entry ( before) .or_default ( ) ;
ff0af1ee unknown 1 month ago
193
}
194
195
196
pub fn delete ( & mut self , by : ChangeHash, range : & AtomRange) {
197
for i in range.from.. range.to {
75167672 Andy McCall 1 month ago
198
self .atoms
199
.entry ( ( range.change, i) )
200
.or_default ( )
201
.deleted_by
202
.insert ( by) ;
ff0af1ee unknown 1 month ago
203
}
204
}
205
206
pub fn is_live ( & self , k : & AtomKey) -> bool {
75167672 Andy McCall 1 month ago
207
self .atoms
208
.get ( k)
209
.is_some_and ( | a | a.content.is_some ( ) & & a.deleted_by.is_empty ( ) )
ff0af1ee unknown 1 month ago
210
}
211
212
pub fn content ( & self , k : & AtomKey) -> Option< & [ u8 ] > {
01a47cd7 Andy McCall 1 month ago ↶
213
self .atoms
214
.get ( k)
215
.and_then ( | a | a.content.as_ref ( ) .map ( LineRef:: bytes) )
ff0af1ee unknown 1 month ago
216
}
217
218
pub fn deleters ( & self , k : & AtomKey) -> impl Iterator< Item = & ChangeHash> {
75167672 Andy McCall 1 month ago
219
self .atoms
220
.get ( k)
221
.into_iter ( )
222
.flat_map ( | a | a.deleted_by.iter ( ) )
ff0af1ee unknown 1 month ago
223
}
224
225
226
pub fn atom_count ( & self ) -> usize {
227
self .atoms.len ( )
228
}
229
62794ecc Andy McCall 1 month ago ↶
230
231
232
83d61e80 Andy McCall 1 month ago ↶
233
234
235
236
237
pub fn between ( & self , first : & AtomKey, last : & AtomKey) -> Vec< AtomKey> {
238
let ( from, to) = ( Vertex:: Atom( * first) , Vertex:: Atom( * last) ) ;
239
let mut ahead: HashSet< Vertex> = HashSet:: default( ) ;
240
let mut stack = vec! [ from] ;
241
while let Some ( v) = stack.pop ( ) {
242
if ahead.insert ( v) {
243
stack.extend (
244
self .succ
245
.get ( & v)
246
.map ( | e | e.as_slice ( ) )
247
.unwrap_or ( & [ ] )
248
.iter ( )
249
.copied ( ) ,
250
) ;
251
}
252
}
253
if ! ahead.contains ( & to) {
254
return vec! [ ] ;
255
}
256
let mut pred: HashMap< Vertex, Vec< Vertex> > = HashMap:: default( ) ;
257
for ( u, es) in & self .succ {
258
if ahead.contains ( u) {
259
for w in es.iter ( ) {
260
pred.entry ( * w) .or_default ( ) .push ( * u) ;
261
}
262
}
263
}
264
let mut behind: HashSet< Vertex> = HashSet:: default( ) ;
265
let mut stack = vec! [ to] ;
266
while let Some ( v) = stack.pop ( ) {
267
if behind.insert ( v) {
268
stack.extend ( pred.get ( & v) .into_iter ( ) .flatten ( ) .copied ( ) ) ;
269
}
270
}
271
let mut out: Vec< AtomKey> = ahead
272
.intersection ( & behind)
273
.filter_map ( | v | match v {
274
Vertex:: Atom( k) if self .atoms.contains_key ( k) => Some ( * k) ,
275
_ => None ,
276
} )
277
.collect ( ) ;
278
out.sort ( ) ;
279
out
280
}
281
282
283
pub fn touching ( & self , atoms : & [AtomKey]) -> BTreeSet< ChangeHash> {
284
let mut out = BTreeSet:: new( ) ;
285
for k in atoms {
286
out.insert ( k.0 ) ;
287
if let Some ( info) = self .atoms.get ( k) {
288
out.extend ( info.deleted_by.iter ( ) .copied ( ) ) ;
289
}
290
}
291
out
292
}
293
62794ecc Andy McCall 1 month ago ↶
294
pub fn live_successor_changes ( & self , k : & AtomKey) -> Vec< ChangeHash> {
295
self .succ
296
.get ( & Vertex:: Atom( * k) )
297
.map ( | ss | {
298
ss.iter ( )
299
.filter_map ( | s | match s {
300
Vertex:: Atom( y) if self .is_live ( y) => Some ( y.0 ) ,
301
_ => None ,
302
} )
303
.collect ( )
304
} )
305
.unwrap_or_default ( )
306
}
307
ff0af1ee unknown 1 month ago
308
fn is_ghost ( & self , k : & AtomKey, info : & AtomInfo, deps : & dyn DepOracle) -> bool {
23b217d7 Andy McCall 1 month ago ↶
309
310
311
312
ff0af1ee unknown 1 month ago
313
self .succ.get ( & Vertex:: Atom( * k) ) .is_some_and ( | ss | {
314
ss.iter ( ) .any ( | s | match s {
75167672 Andy McCall 1 month ago
315
Vertex:: Atom( y) if self .is_live ( y) => ! info
316
.deleted_by
317
.iter ( )
318
.any ( | d | deps.depends_on ( d, & y.0 ) | | deps.depends_on ( & y.0 , d) ) ,
ff0af1ee unknown 1 month ago
319
_ => false ,
320
} )
321
} )
322
}
323
324
75167672 Andy McCall 1 month ago
325
fn reduced_succ (
326
& self ,
327
v : Vertex,
328
kept : & HashSet< Vertex> ,
329
memo : & mut HashMap< Vertex, BTreeSet< Vertex> > ,
330
) -> BTreeSet< Vertex> {
ff0af1ee unknown 1 month ago
331
let mut out = BTreeSet:: new( ) ;
75167672 Andy McCall 1 month ago
332
let mut stack: Vec< Vertex> = self
333
.succ
334
.get ( & v)
335
.map ( | s | s.iter ( ) .copied ( ) .collect ( ) )
336
.unwrap_or_default ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
337
let mut seen = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
338
while let Some ( s) = stack.pop ( ) {
339
if kept.contains ( & s) {
340
out.insert ( s) ;
341
} else if seen.insert ( s) {
342
if let Some ( m) = memo.get ( & s) {
343
out.extend ( m.iter ( ) .copied ( ) ) ;
344
} else if let Some ( next) = self .succ.get ( & s) {
345
stack.extend ( next.iter ( ) .copied ( ) ) ;
346
}
347
}
348
}
349
out
350
}
351
352
353
pub fn materialize ( & self , deps : & dyn DepOracle) -> Materialized {
354
0bdc3f91 Andy McCall 1 month ago ↶
355
let mut kept: HashSet< Vertex> = HashSet:: default( ) ;
356
let mut ghosts: HashSet< AtomKey> = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
357
kept.insert ( Vertex:: Start) ;
358
kept.insert ( Vertex:: End) ;
359
for ( k, info) in & self .atoms {
360
if info.content.is_none ( ) {
361
continue ;
362
}
363
if info.deleted_by.is_empty ( ) {
364
kept.insert ( Vertex:: Atom( * k) ) ;
365
} else if self .is_ghost ( k, info, deps) {
366
kept.insert ( Vertex:: Atom( * k) ) ;
367
ghosts.insert ( * k) ;
368
}
369
}
370
371
0bdc3f91 Andy McCall 1 month ago ↶
372
let mut memo = HashMap:: default( ) ;
373
let mut rsucc: HashMap< Vertex, BTreeSet< Vertex> > = HashMap:: default( ) ;
374
let mut indeg: HashMap< Vertex, usize > = HashMap:: default( ) ;
ff0af1ee unknown 1 month ago
375
for & u in & kept {
376
indeg.entry ( u) .or_insert ( 0 ) ;
377
let rs = self .reduced_succ ( u, & kept, & mut memo) ;
378
for & w in & rs {
379
* indeg.entry ( w) .or_insert ( 0 ) + = 1 ;
380
}
381
rsucc.insert ( u, rs) ;
382
}
383
384
75167672 Andy McCall 1 month ago
385
let mut ready: BTreeSet< Vertex> = indeg
386
.iter ( )
387
.filter ( | ( _, &d ) | d = = 0 )
388
.map ( | ( v , _) | * v)
389
.collect ( ) ;
0bdc3f91 Andy McCall 1 month ago ↶
390
let mut side: HashMap< Vertex, u32 > = HashMap:: default( ) ;
391
let mut joins: HashSet< Vertex> = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
392
let mut next_side = 0 u32 ;
393
let mut plain: Vec< Vertex> = Vec :: new( ) ;
394
let mut conflict: Option< BTreeMap< u32 , Vec< Vertex> > > = None ;
395
let mut segments: Vec< Segment> = Vec :: new( ) ;
396
397
let flush_plain = | plain : & mut Vec< Vertex> , segments : & mut Vec< Segment> | {
75167672 Andy McCall 1 month ago
398
let atoms: Vec< AtomKey> = plain
399
.iter ( )
400
.filter_map ( | v | {
401
if let Vertex:: Atom( k) = v {
402
Some ( * k)
403
} else {
404
None
405
}
406
} )
407
.collect ( ) ;
ff0af1ee unknown 1 month ago
408
plain.clear ( ) ;
409
if ! atoms.is_empty ( ) {
410
segments.extend ( split_zombies ( atoms, & ghosts) ) ;
411
}
412
} ;
413
let finish_conflict = | c : BTreeMap< u32 , Vec< Vertex> > , segments : & mut Vec< Segment> | {
414
let sides: Vec< Vec< AtomKey> > = c
415
.into_values ( )
416
.map ( | vs | {
417
vs.into_iter ( )
418
.filter_map ( | v | match v {
419
Vertex:: Atom( k) if ! ghosts.contains ( & k) => Some ( k) ,
420
_ => None ,
421
} )
422
.collect:: < Vec< _ > > ( )
423
} )
424
.filter ( | s | ! s.is_empty ( ) )
425
.collect ( ) ;
426
match sides.len ( ) {
427
0 => { }
428
1 => segments.push ( Segment:: Lines( sides.into_iter ( ) .next ( ) .unwrap ( ) ) ) ,
429
_ => segments.push ( Segment:: Conflict( sides) ) ,
430
}
431
} ;
432
433
while ! ready.is_empty ( ) {
434
if ready.len ( ) > = 2 {
435
if conflict.is_none ( ) {
436
flush_plain ( & mut plain, & mut segments) ;
437
conflict = Some ( BTreeMap:: new( ) ) ;
438
}
439
for r in & ready {
440
if ! side.contains_key ( r) {
441
side.insert ( * r, next_side) ;
442
next_side + = 1 ;
443
}
444
}
445
}
446
let v = ready.pop_first ( ) .unwrap ( ) ;
447
let my_side = side.get ( & v) .copied ( ) ;
448
match ( & mut conflict, my_side) {
449
( Some ( c) , Some ( s) ) => c.entry ( s) .or_default ( ) .push ( v) ,
450
( Some ( _ ) , None ) => {
451
let c = conflict.take ( ) .unwrap ( ) ;
452
finish_conflict ( c, & mut segments) ;
453
plain.push ( v) ;
454
}
455
( None , _ ) => plain.push ( v) ,
456
}
457
for & w in & rsucc[ & v] {
458
let d = indeg.get_mut ( & w) .unwrap ( ) ;
459
* d - = 1 ;
460
if conflict.is_some ( ) & & ! joins.contains ( & w) {
461
match ( my_side, side.get ( & w) .copied ( ) ) {
462
( Some ( s) , None ) => {
463
side.insert ( w, s) ;
464
}
465
( Some ( s) , Some ( t) ) if s ! = t => {
466
side.remove ( & w) ;
467
joins.insert ( w) ;
468
}
469
( None , Some ( _ ) ) => {
470
side.remove ( & w) ;
471
joins.insert ( w) ;
472
}
473
_ => { }
474
}
475
}
476
if * d = = 0 {
477
ready.insert ( w) ;
478
}
479
}
480
}
481
if let Some ( c) = conflict.take ( ) {
482
finish_conflict ( c, & mut segments) ;
483
}
484
flush_plain ( & mut plain, & mut segments) ;
485
Materialized { segments }
486
}
487
488
489
490
pub fn render ( & self , m : & Materialized, label : & dyn Fn( &ChangeHash ) -> String) -> Vec< u8 > {
491
let total = m.conflict_count ( ) ;
492
let mut n = 0 ;
493
let mut out: Vec< u8 > = Vec :: new( ) ;
494
let push_atoms = | out : & mut Vec< u8 > , atoms : & [AtomKey]| {
495
for a in atoms {
496
if let Some ( c) = self .content ( a) {
497
out.extend_from_slice ( c) ;
498
}
499
}
500
} ;
501
let newline_if_needed = | out : & mut Vec< u8 > | {
502
if ! out.is_empty ( ) & & * out.last ( ) .unwrap ( ) ! = b ' \n ' {
503
out.push ( b ' \n ' ) ;
504
}
505
} ;
506
for seg in & m.segments {
507
match seg {
508
Segment:: Lines( a) => push_atoms ( & mut out, a) ,
509
Segment:: Conflict( sides) => {
510
n + = 1 ;
511
let k = sides.len ( ) ;
512
for ( i, s) in sides.iter ( ) .enumerate ( ) {
513
newline_if_needed ( & mut out) ;
514
let who = s.first ( ) .map ( | a | label ( & a.0 ) ) .unwrap_or_default ( ) ;
515
let marker = if i = = 0 { " <<<<<<<" } else { " =======" } ;
516
out.extend_from_slice (
517
format! ( " {marker} oxy conflict {n} of {total} , side {} of {k} : change {who} \n " , i + 1 ) .as_bytes ( ) ,
518
) ;
519
push_atoms ( & mut out, s) ;
520
}
521
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
522
out.extend_from_slice (
523
format! ( " >>>>>>> oxy conflict {n} of {total} end\n " ) .as_bytes ( ) ,
524
) ;
ff0af1ee unknown 1 month ago
525
}
526
Segment:: Zombie { deleted, inserted } => {
527
n + = 1 ;
528
newline_if_needed ( & mut out) ;
529
let deleter = deleted
530
.first ( )
531
.and_then ( | a | self .deleters ( a) .next ( ) .copied ( ) )
532
.map ( | d | label ( & d) )
533
.unwrap_or_default ( ) ;
534
let inserter = inserted.first ( ) .map ( | a | label ( & a.0 ) ) .unwrap_or_default ( ) ;
535
out.extend_from_slice (
536
format! ( " <<<<<<< oxy conflict {n} of {total} , side 1 of 2: deleted by change {deleter} \n -------\n " ) .as_bytes ( ) ,
537
) ;
538
push_atoms ( & mut out, deleted) ;
539
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
540
out.extend_from_slice (
541
format! (
542
" ======= oxy conflict {n} of {total} , side 2 of 2: change {inserter} \n "
543
)
544
.as_bytes ( ) ,
545
) ;
ff0af1ee unknown 1 month ago
546
push_atoms ( & mut out, inserted) ;
547
newline_if_needed ( & mut out) ;
75167672 Andy McCall 1 month ago
548
out.extend_from_slice (
549
format! ( " >>>>>>> oxy conflict {n} of {total} end\n " ) .as_bytes ( ) ,
550
) ;
ff0af1ee unknown 1 month ago
551
}
552
}
553
}
554
out
555
}
556
}
557
252e8cb2 Andy McCall 1 month ago ↶
558
fn vertex_value ( v : & Vertex) -> crate:: cbor:: Value {
559
use crate :: cbor:: Value;
560
match v {
561
Vertex:: Start => Value:: Uint( 0 ) ,
562
Vertex:: End => Value:: Uint( 1 ) ,
75167672 Andy McCall 1 month ago
563
Vertex:: Atom( ( c, i) ) => {
564
Value:: Array( vec! [ Value:: Bytes( c.0. to_vec ( ) ) , Value:: Uint( * i as u64 ) ] )
565
}
252e8cb2 Andy McCall 1 month ago ↶
566
}
567
}
568
569
fn vertex_from ( v : & crate:: cbor:: Value) -> Result< Vertex, crate:: objects:: ObjectError> {
570
use crate :: cbor:: Value;
571
use crate :: objects:: ObjectError;
572
match v {
573
Value:: Uint( 0 ) => Ok ( Vertex:: Start) ,
574
Value:: Uint( 1 ) => Ok ( Vertex:: End) ,
75167672 Andy McCall 1 month ago
575
Value:: Array( a) if a.len ( ) = = 2 => Ok ( Vertex:: Atom( (
576
crate :: objects:: oref( & a[ 0 ] , " vertex" ) ? ,
577
crate :: objects:: u32_( & a[ 1 ] , " vertex" ) ? ,
578
) ) ) ,
579
_ => Err ( ObjectError:: Schema(
580
" vertex: expected 0, 1, or [hash, index]" .into ( ) ,
581
) ) ,
252e8cb2 Andy McCall 1 month ago ↶
582
}
583
}
584
585
impl FileGraph {
586
587
pub fn to_value ( & self ) -> crate:: cbor:: Value {
588
use crate :: cbor:: Value;
589
let mut atoms: Vec< ( & AtomKey, & AtomInfo) > = self .atoms.iter ( ) .collect ( ) ;
590
atoms.sort_by_key ( | ( k , _) | * * k) ;
75167672 Andy McCall 1 month ago
591
let mut edges: Vec< ( Vertex, Vertex) > = self
592
.succ
593
.iter ( )
594
.flat_map ( | ( a , bs ) | bs.iter ( ) .map ( move | b| ( * a, * b) ) )
595
.collect ( ) ;
252e8cb2 Andy McCall 1 month ago ↶
596
edges.sort ( ) ;
597
Value:: map( [
598
(
599
0 ,
600
Value:: Array(
601
atoms
602
.into_iter ( )
603
.map ( | ( (c , i ) , info) | {
604
Value:: Array( vec! [
605
Value:: Bytes( c.0. to_vec ( ) ) ,
606
Value:: Uint( * i as u64 ) ,
75167672 Andy McCall 1 month ago
607
info.content
608
.as_ref ( )
01a47cd7 Andy McCall 1 month ago ↶
609
.map ( | b | Value:: Bytes( b.bytes ( ) .to_vec ( ) ) )
75167672 Andy McCall 1 month ago
610
.unwrap_or ( Value:: Null) ,
611
Value:: Array(
612
info.deleted_by
613
.iter ( )
614
.map ( | d | Value:: Bytes( d.0. to_vec ( ) ) )
615
.collect ( ) ,
616
) ,
252e8cb2 Andy McCall 1 month ago ↶
617
] )
618
} )
619
.collect ( ) ,
620
) ,
621
),
75167672 Andy McCall 1 month ago
622
(
623
1 ,
624
Value:: Array(
625
edges
626
.iter ( )
627
.map ( | ( a , b ) | Value:: Array( vec! [ vertex_value ( a) , vertex_value ( b) ] ) )
628
.collect ( ) ,
629
) ,
630
) ,
252e8cb2 Andy McCall 1 month ago ↶
631
] )
632
}
633
634
pub fn from_value ( v : & crate:: cbor:: Value) -> Result< FileGraph, crate:: objects:: ObjectError> {
635
use crate :: objects:: { array, bytes, field, map, oref, u32_, ObjectError} ;
636
let m = map ( v, " file graph" ) ? ;
75167672 Andy McCall 1 month ago
637
let mut g = FileGraph {
0bdc3f91 Andy McCall 1 month ago ↶
638
atoms: HashMap:: default( ) ,
639
succ: HashMap:: default( ) ,
75167672 Andy McCall 1 month ago
640
} ;
01a47cd7 Andy McCall 1 month ago ↶
641
let atoms = array ( field ( m, 0 , " atoms" ) ? , " atoms" ) ? ;
642
643
let mut texts: Vec< & [ u8 ] > = Vec :: new( ) ;
644
for a in atoms {
645
let e = array ( a, " atom" ) ? ;
646
if e.len ( ) = = 4 & & ! e[ 2 ] .is_null ( ) {
647
texts.push ( bytes ( & e[ 2 ] , " atom content" ) ? ) ;
648
}
649
}
650
let all: Lines = texts.into_iter ( ) .collect ( ) ;
651
let mut next = 0 u32 ;
652
for a in atoms {
252e8cb2 Andy McCall 1 month ago ↶
653
let e = array ( a, " atom" ) ? ;
654
if e.len ( ) ! = 4 {
655
return Err ( ObjectError:: Schema( " atom: expected 4 fields" .into ( ) ) ) ;
656
}
657
let key = ( oref ( & e[ 0 ] , " atom change" ) ? , u32_ ( & e[ 1 ] , " atom index" ) ? ) ;
75167672 Andy McCall 1 month ago
658
let content = if e[ 2 ] .is_null ( ) {
659
None
660
} else {
01a47cd7 Andy McCall 1 month ago ↶
661
next + = 1 ;
662
Some ( LineRef:: new( all.clone ( ) , next - 1 ) )
75167672 Andy McCall 1 month ago
663
} ;
664
let deleted_by = array ( & e[ 3 ] , " deleters" ) ?
665
.iter ( )
666
.map ( | d | oref ( d, " deleter" ) )
667
.collect:: < Result< BTreeSet< _ > , _ > > ( ) ? ;
668
g.atoms.insert (
669
key,
670
AtomInfo {
671
content,
672
deleted_by,
673
} ,
674
) ;
252e8cb2 Andy McCall 1 month ago ↶
675
}
676
for e in array ( field ( m, 1 , " edges" ) ? , " edges" ) ? {
677
let pair = array ( e, " edge" ) ? ;
678
if pair.len ( ) ! = 2 {
679
return Err ( ObjectError:: Schema( " edge: expected [from, to]" .into ( ) ) ) ;
680
}
681
g.edge ( vertex_from ( & pair[ 0 ] ) ? , vertex_from ( & pair[ 1 ] ) ? ) ;
682
}
683
Ok ( g)
684
}
685
}
686
ff0af1ee unknown 1 month ago
687
688
fn split_zombies ( atoms : Vec< AtomKey> , ghosts : & HashSet< AtomKey> ) -> Vec< Segment> {
689
let mut out = Vec :: new( ) ;
690
let mut lines: Vec< AtomKey> = Vec :: new( ) ;
691
let mut i = 0 ;
692
while i < atoms.len ( ) {
693
if ! ghosts.contains ( & atoms[ i] ) {
694
lines.push ( atoms[ i] ) ;
695
i + = 1 ;
696
continue ;
697
}
698
if ! lines.is_empty ( ) {
699
out.push ( Segment:: Lines( std:: mem:: take( & mut lines) ) ) ;
700
}
701
let mut deleted = Vec :: new( ) ;
702
while i < atoms.len ( ) & & ghosts.contains ( & atoms[ i] ) {
703
deleted.push ( atoms[ i] ) ;
704
i + = 1 ;
705
}
706
let mut inserted = Vec :: new( ) ;
707
if i < atoms.len ( ) {
708
let ch = atoms[ i] .0 ;
709
while i < atoms.len ( ) & & atoms[ i] .0 = = ch & & ! ghosts.contains ( & atoms[ i] ) {
710
inserted.push ( atoms[ i] ) ;
711
i + = 1 ;
712
}
713
}
714
out.push ( Segment:: Zombie { deleted, inserted } ) ;
715
}
716
if ! lines.is_empty ( ) {
717
out.push ( Segment:: Lines( lines) ) ;
718
}
719
out
720
}
721
722
# [ cfg ( test ) ]
723
mod tests {
724
use super :: * ;
725
use crate :: hash:: ObjectRef;
726
727
fn h ( n : u8 ) -> ChangeHash {
728
ObjectRef( [ n; 32 ] )
729
}
01a47cd7 Andy McCall 1 month ago ↶
730
fn lines ( v : & [& str ]) -> Lines {
731
v.iter ( ) .map ( | s | s.as_bytes ( ) ) .collect ( )
ff0af1ee unknown 1 month ago
732
}
733
fn text ( g : & FileGraph, m : & Materialized) -> String {
734
String :: from_utf8( g.render ( m, & | c| c.short ( 4 ) ) ) .unwrap ( )
735
}
736
737
struct Deps ( HashMap< ChangeHash, Vec< ChangeHash> > ) ;
738
impl DepOracle for Deps {
739
fn depends_on ( & self , a : & ChangeHash, b : & ChangeHash) -> bool {
740
if a = = b {
741
return true ;
742
}
743
let mut stack = vec! [ * a] ;
0bdc3f91 Andy McCall 1 month ago ↶
744
let mut seen = HashSet:: default( ) ;
ff0af1ee unknown 1 month ago
745
while let Some ( x) = stack.pop ( ) {
746
if let Some ( ds) = self .0. get ( & x) {
747
for d in ds {
748
if d = = b {
749
return true ;
750
}
751
if seen.insert ( * d) {
752
stack.push ( * d) ;
753
}
754
}
755
}
756
}
757
false
758
}
759
}
760
761
# [ test ]
762
fn sequential_inserts_and_deletes ( ) {
763
let mut g = FileGraph:: new( ) ;
75167672 Andy McCall 1 month ago
764
g.insert (
765
h ( 1 ) ,
766
0 ,
767
Vertex:: Start,
768
Vertex:: End,
769
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
770
) ;
ff0af1ee unknown 1 month ago
771
let m = g.materialize ( & NoDeps) ;
772
assert! ( ! m.is_conflicted ( ) ) ;
773
assert_eq! ( text ( & g, & m) , " a\n b\n c\n " ) ;
774
775
75167672 Andy McCall 1 month ago
776
g.insert (
777
h ( 2 ) ,
778
0 ,
779
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
780
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
781
& lines ( & [ " x\n " ] ) ,
782
) ;
783
g.delete (
784
h ( 2 ) ,
785
& AtomRange {
786
change: h ( 1 ) ,
787
from: 0 ,
788
to: 1 ,
789
} ,
790
) ;
ff0af1ee unknown 1 month ago
791
let deps = Deps( [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) ] .into_iter ( ) .collect ( ) ) ;
792
let m = g.materialize ( & deps) ;
793
assert! ( ! m.is_conflicted ( ) ) ;
794
assert_eq! ( text ( & g, & m) , " b\n x\n c\n " ) ;
795
assert_eq! ( m.live_atoms ( ) , vec! [ ( h ( 1 ) , 1 ) , ( h ( 2 ) , 0 ) , ( h ( 1 ) , 2 ) ] ) ;
796
}
797
798
# [ test ]
799
fn concurrent_inserts_at_same_anchor_conflict ( ) {
800
let mut g = FileGraph:: new( ) ;
801
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
802
g.insert (
803
h ( 2 ) ,
804
0 ,
805
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
806
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
807
& lines ( & [ " from-2\n " ] ) ,
808
) ;
809
g.insert (
810
h ( 3 ) ,
811
0 ,
812
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
813
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
814
& lines ( & [ " from-3\n " , " more-3\n " ] ) ,
815
) ;
816
let deps = Deps(
817
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
818
.into_iter ( )
819
.collect ( ) ,
820
) ;
ff0af1ee unknown 1 month ago
821
let m = g.materialize ( & deps) ;
822
assert! ( m.is_conflicted ( ) ) ;
823
assert_eq! ( m.conflict_count ( ) , 1 ) ;
824
assert_eq! (
825
m.segments,
826
vec! [
827
Segment:: Lines( vec! [ ( h ( 1 ) , 0 ) ] ) ,
828
Segment:: Conflict( vec! [ vec! [ ( h ( 2 ) , 0 ) ] , vec! [ ( h ( 3 ) , 0 ) , ( h ( 3 ) , 1 ) ] ] ) ,
829
Segment:: Lines( vec! [ ( h ( 1 ) , 1 ) ] ) ,
830
]
831
) ;
832
let t = text ( & g, & m) ;
833
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}" ) ;
834
}
835
836
# [ test ]
837
fn concurrent_inserts_at_different_anchors_do_not_conflict ( ) {
838
let mut g = FileGraph:: new( ) ;
75167672 Andy McCall 1 month ago
839
g.insert (
840
h ( 1 ) ,
841
0 ,
842
Vertex:: Start,
843
Vertex:: End,
844
& lines ( & [ " a\n " , " b\n " , " c\n " ] ) ,
845
) ;
846
g.insert (
847
h ( 2 ) ,
848
0 ,
849
Vertex:: Start,
850
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
851
& lines ( & [ " top\n " ] ) ,
852
) ;
853
g.insert (
854
h ( 3 ) ,
855
0 ,
856
Vertex:: Atom( ( h ( 1 ) , 2 ) ) ,
857
Vertex:: End,
858
& lines ( & [ " bottom\n " ] ) ,
859
) ;
860
let deps = Deps(
861
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
862
.into_iter ( )
863
.collect ( ) ,
864
) ;
ff0af1ee unknown 1 month ago
865
let m = g.materialize ( & deps) ;
866
assert! ( ! m.is_conflicted ( ) ) ;
867
assert_eq! ( text ( & g, & m) , " top\n a\n b\n c\n bottom\n " ) ;
868
}
869
870
# [ test ]
871
fn concurrent_deletes_of_the_same_line_agree ( ) {
872
let mut g = FileGraph:: new( ) ;
873
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
874
g.delete (
875
h ( 2 ) ,
876
& AtomRange {
877
change: h ( 1 ) ,
878
from: 0 ,
879
to: 1 ,
880
} ,
881
) ;
882
g.delete (
883
h ( 3 ) ,
884
& AtomRange {
885
change: h ( 1 ) ,
886
from: 0 ,
887
to: 1 ,
888
} ,
889
) ;
890
let deps = Deps(
891
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
892
.into_iter ( )
893
.collect ( ) ,
894
) ;
ff0af1ee unknown 1 month ago
895
let m = g.materialize ( & deps) ;
896
assert! ( ! m.is_conflicted ( ) ) ;
897
assert_eq! ( text ( & g, & m) , " b\n " ) ;
898
}
899
900
# [ test ]
901
fn delete_insert_conflict_is_a_zombie ( ) {
902
let mut g = FileGraph:: new( ) ;
903
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
904
75167672 Andy McCall 1 month ago
905
g.delete (
906
h ( 2 ) ,
907
& AtomRange {
908
change: h ( 1 ) ,
909
from: 0 ,
910
to: 1 ,
911
} ,
912
) ;
913
g.insert (
914
h ( 3 ) ,
915
0 ,
916
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
917
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
918
& lines ( & [ " after-a\n " ] ) ,
919
) ;
920
let deps = Deps(
921
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
922
.into_iter ( )
923
.collect ( ) ,
924
) ;
ff0af1ee unknown 1 month ago
925
let m = g.materialize ( & deps) ;
926
assert! ( m.is_conflicted ( ) ) ;
927
assert_eq! (
928
m.segments,
929
vec! [
75167672 Andy McCall 1 month ago
930
Segment:: Zombie {
931
deleted: vec! [ ( h ( 1 ) , 0 ) ] ,
932
inserted: vec! [ ( h ( 3 ) , 0 ) ]
933
} ,
ff0af1ee unknown 1 month ago
934
Segment:: Lines( vec! [ ( h ( 1 ) , 1 ) ] ) ,
935
]
936
) ;
937
let t = text ( & g, & m) ;
938
assert! ( t.contains ( " -------\n a\n =======" ) , " {t}" ) ;
939
assert! ( t.contains ( " after-a\n >>>>>>>" ) , " {t}" ) ;
940
941
75167672 Andy McCall 1 month ago
942
let deps = Deps(
943
[ ( h ( 2 ) , vec! [ h ( 1 ) , h ( 3 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
944
.into_iter ( )
945
.collect ( ) ,
946
) ;
ff0af1ee unknown 1 month ago
947
let m = g.materialize ( & deps) ;
948
assert! ( ! m.is_conflicted ( ) ) ;
949
assert_eq! ( text ( & g, & m) , " after-a\n b\n " ) ;
950
}
951
952
# [ test ]
23b217d7 Andy McCall 1 month ago ↶
953
fn insert_after_a_line_deleted_by_a_dependency_is_not_a_conflict ( ) {
954
955
956
let mut g = FileGraph:: new( ) ;
957
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
958
g.delete (
959
h ( 2 ) ,
960
& AtomRange {
961
change: h ( 1 ) ,
962
from: 1 ,
963
to: 2 ,
964
} ,
965
) ;
966
g.insert (
967
h ( 3 ) ,
968
0 ,
969
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
970
Vertex:: End,
971
& lines ( & [ " c\n " ] ) ,
972
) ;
973
let deps = Deps(
974
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 2 ) ] ) ]
975
.into_iter ( )
976
.collect ( ) ,
977
) ;
23b217d7 Andy McCall 1 month ago ↶
978
let m = g.materialize ( & deps) ;
979
assert! ( ! m.is_conflicted ( ) , " {:?}" , m.segments) ;
980
assert_eq! ( text ( & g, & m) , " a\n c\n " ) ;
981
982
983
let mut g = FileGraph:: new( ) ;
984
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " x\n " ] ) ) ;
75167672 Andy McCall 1 month ago
985
g.delete (
986
h ( 1 ) ,
987
& AtomRange {
988
change: h ( 1 ) ,
989
from: 0 ,
990
to: 1 ,
991
} ,
992
) ;
993
g.insert (
994
h ( 2 ) ,
995
0 ,
996
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
997
Vertex:: End,
998
& lines ( & [ " y\n " ] ) ,
999
) ;
23b217d7 Andy McCall 1 month ago ↶
1000
let deps = Deps( [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) ] .into_iter ( ) .collect ( ) ) ;
1001
let m = g.materialize ( & deps) ;
1002
assert! ( ! m.is_conflicted ( ) ) ;
1003
assert_eq! ( text ( & g, & m) , " y\n " ) ;
1004
}
1005
1006
# [ test ]
ff0af1ee unknown 1 month ago
1007
fn resolution_collapses_a_conflict ( ) {
1008
let mut g = FileGraph:: new( ) ;
1009
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1010
g.insert (
1011
h ( 2 ) ,
1012
0 ,
1013
Vertex:: Start,
1014
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1015
& lines ( & [ " x\n " ] ) ,
1016
) ;
1017
g.insert (
1018
h ( 3 ) ,
1019
0 ,
1020
Vertex:: Start,
1021
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1022
& lines ( & [ " y\n " ] ) ,
1023
) ;
1024
let mut deps: HashMap< _ , _ > = [ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1025
.into_iter ( )
1026
.collect ( ) ;
ff0af1ee unknown 1 month ago
1027
assert! ( g.materialize ( & Deps( deps.clone ( ) ) ) .is_conflicted ( ) ) ;
1028
75167672 Andy McCall 1 month ago
1029
g.delete (
1030
h ( 4 ) ,
1031
& AtomRange {
1032
change: h ( 2 ) ,
1033
from: 0 ,
1034
to: 1 ,
1035
} ,
1036
) ;
ff0af1ee unknown 1 month ago
1037
deps.insert ( h ( 4 ) , vec! [ h ( 2 ) , h ( 3 ) ] ) ;
1038
let m = g.materialize ( & Deps( deps) ) ;
1039
assert! ( ! m.is_conflicted ( ) ) ;
1040
assert_eq! ( text ( & g, & m) , " y\n a\n " ) ;
1041
}
1042
1043
# [ test ]
1044
fn empty_and_unterminated_files ( ) {
1045
let g = FileGraph:: new( ) ;
1046
let m = g.materialize ( & NoDeps) ;
1047
assert_eq! ( m.segments, vec! [ ] ) ;
1048
assert_eq! ( text ( & g, & m) , " " ) ;
1049
let mut g = FileGraph:: new( ) ;
1050
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " no newline" ] ) ) ;
1051
assert_eq! ( text ( & g, & g.materialize ( & NoDeps) ) , " no newline" ) ;
1052
}
1053
252e8cb2 Andy McCall 1 month ago ↶
1054
# [ test ]
1055
fn serialization_round_trip ( ) {
1056
let mut g = FileGraph:: new( ) ;
1057
g.insert ( h ( 1 ) , 0 , Vertex:: Start, Vertex:: End, & lines ( & [ " a\n " , " b\n " ] ) ) ;
75167672 Andy McCall 1 month ago
1058
g.insert (
1059
h ( 2 ) ,
1060
0 ,
1061
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1062
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1063
& lines ( & [ " x\n " ] ) ,
1064
) ;
1065
g.delete (
1066
h ( 3 ) ,
1067
& AtomRange {
1068
change: h ( 1 ) ,
1069
from: 1 ,
1070
to: 2 ,
1071
} ,
1072
) ;
252e8cb2 Andy McCall 1 month ago ↶
1073
let v = g.to_value ( ) ;
1074
let bytes = crate :: cbor:: encode( & v) ;
1075
let back = FileGraph:: from_value( & crate :: cbor:: decode( & bytes) .unwrap ( ) ) .unwrap ( ) ;
75167672 Andy McCall 1 month ago
1076
let deps = Deps(
1077
[ ( h ( 2 ) , vec! [ h ( 1 ) ] ) , ( h ( 3 ) , vec! [ h ( 1 ) ] ) ]
1078
.into_iter ( )
1079
.collect ( ) ,
1080
) ;
252e8cb2 Andy McCall 1 month ago ↶
1081
assert_eq! ( back.materialize ( & deps) , g.materialize ( & deps) ) ;
1082
assert_eq! ( text ( & back, & back.materialize ( & deps) ) , " a\n x\n " ) ;
75167672 Andy McCall 1 month ago
1083
assert_eq! (
1084
crate :: cbor:: encode( & back.to_value ( ) ) ,
1085
bytes,
1086
" deterministic"
1087
) ;
252e8cb2 Andy McCall 1 month ago ↶
1088
}
1089
ff0af1ee unknown 1 month ago
1090
1091
# [ test ]
1092
fn application_order_is_irrelevant ( ) {
1093
use rand:: seq:: SliceRandom;
75167672 Andy McCall 1 month ago
1094
type Op = (
1095
ChangeHash,
01a47cd7 Andy McCall 1 month ago ↶
1096
Vec< ( u32 , Vertex, Vertex, Lines) > ,
75167672 Andy McCall 1 month ago
1097
Vec< AtomRange> ,
1098
) ;
ff0af1ee unknown 1 month ago
1099
let ops: Vec< Op> = vec! [
75167672 Andy McCall 1 month ago
1100
(
1101
h ( 1 ) ,
1102
vec! [ ( 0 , Vertex:: Start, Vertex:: End, lines ( & [ " a\n " , " b\n " , " c\n " ] ) ) ] ,
1103
vec! [ ] ,
1104
) ,
1105
(
1106
h ( 2 ) ,
1107
vec! [ (
1108
0 ,
1109
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1110
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1111
lines ( & [ " p\n " ] ) ,
1112
) ] ,
1113
vec! [ ] ,
1114
) ,
1115
(
1116
h ( 3 ) ,
1117
vec! [ (
1118
0 ,
1119
Vertex:: Atom( ( h ( 1 ) , 0 ) ) ,
1120
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1121
lines ( & [ " q\n " , " r\n " ] ) ,
1122
) ] ,
1123
vec! [ AtomRange {
1124
change: h ( 1 ) ,
1125
from: 2 ,
1126
to: 3 ,
1127
} ] ,
1128
) ,
1129
(
1130
h ( 4 ) ,
1131
vec! [ (
1132
0 ,
1133
Vertex:: Atom( ( h ( 3 ) , 1 ) ) ,
1134
Vertex:: Atom( ( h ( 1 ) , 1 ) ) ,
1135
lines ( & [ " s\n " ] ) ,
1136
) ] ,
1137
vec! [ AtomRange {
1138
change: h ( 1 ) ,
1139
from: 1 ,
1140
to: 2 ,
1141
} ] ,
1142
) ,
1143
(
1144
h ( 5 ) ,
1145
vec! [ ( 0 , Vertex:: Atom( ( h ( 1 ) , 2 ) ) , Vertex:: End, lines ( & [ " z\n " ] ) ) ] ,
1146
vec! [ ] ,
1147
) ,
ff0af1ee unknown 1 month ago
1148
] ;
1149
let deps = Deps(
75167672 Andy McCall 1 month ago
1150
[
1151
( h ( 2 ) , vec! [ h ( 1 ) ] ) ,
1152
( h ( 3 ) , vec! [ h ( 1 ) ] ) ,
1153
( h ( 4 ) , vec! [ h ( 3 ) , h ( 1 ) ] ) ,
1154
( h ( 5 ) , vec! [ h ( 1 ) ] ) ,
1155
]
1156
.into_iter ( )
1157
.collect ( ) ,
ff0af1ee unknown 1 month ago
1158
) ;
1159
let build = | order : & [usize ]| {
1160
let mut g = FileGraph:: new( ) ;
1161
for & i in order {
1162
let ( c, ins, dels) = & ops[ i] ;
1163
for ( idx, a, b, l) in ins {
1164
g.insert ( * c, * idx, * a, * b, l) ;
1165
}
1166
for d in dels {
1167
g.delete ( * c, d) ;
1168
}
1169
}
1170
let m = g.materialize ( & deps) ;
1171
( m.clone ( ) , text ( & g, & m) )
1172
} ;
1173
let reference = build ( & [ 0 , 1 , 2 , 3 , 4 ] ) ;
1174
assert! ( reference.0. is_conflicted ( ) ) ;
1175
let mut rng = rand:: thread_rng( ) ;
1176
let mut order: Vec< usize > = ( 0 .. ops.len ( ) ) .collect ( ) ;
1177
for _ in 0 .. 50 {
1178
order.shuffle ( & mut rng) ;
1179
assert_eq! ( build ( & order) , reference, " order {order:?}" ) ;
1180
}
1181
}
1182
}