@@ -266,6 +266,8 @@ pub(super) mod inner {
266
266
267
267
///
268
268
pub mod builtin_merge {
269
+ use crate :: blob:: platform:: resource;
270
+ use crate :: blob:: platform:: resource:: Data ;
269
271
use crate :: blob:: { builtin_driver, BuiltinDriver , PlatformRef , Resolution } ;
270
272
271
273
/// An identifier to tell us how a merge conflict was resolved by [builtin_merge](PlatformRef::builtin_merge).
@@ -307,19 +309,20 @@ pub(super) mod inner {
307
309
input : & mut imara_diff:: intern:: InternedInput < & ' parent [ u8 ] > ,
308
310
labels : builtin_driver:: text:: Labels < ' _ > ,
309
311
) -> ( Pick , Resolution ) {
310
- let base = self . ancestor . data . as_slice ( ) ;
311
- let ours = self . current . data . as_slice ( ) ;
312
- let theirs = self . other . data . as_slice ( ) ;
312
+ let base = self . ancestor . data . as_slice ( ) . unwrap_or_default ( ) ;
313
+ let ours = self . current . data . as_slice ( ) . unwrap_or_default ( ) ;
314
+ let theirs = self . other . data . as_slice ( ) . unwrap_or_default ( ) ;
313
315
let driver = if driver != BuiltinDriver :: Binary
314
- && ( is_binary_buf ( ours) || is_binary_buf ( theirs) || is_binary_buf ( base) )
316
+ && ( is_binary_buf ( self . ancestor . data )
317
+ || is_binary_buf ( self . other . data )
318
+ || is_binary_buf ( self . current . data ) )
315
319
{
316
320
BuiltinDriver :: Binary
317
321
} else {
318
322
driver
319
323
} ;
320
324
match driver {
321
325
BuiltinDriver :: Text => {
322
- let ( ( base, ours) , theirs) = base. zip ( ours) . zip ( theirs) . expect ( "would use binary if missing" ) ;
323
326
let resolution =
324
327
builtin_driver:: text ( out, input, labels, ours, base, theirs, self . options . text ) ;
325
328
( Pick :: Buffer , resolution)
@@ -334,7 +337,6 @@ pub(super) mod inner {
334
337
( pick, resolution)
335
338
}
336
339
BuiltinDriver :: Union => {
337
- let ( ( base, ours) , theirs) = base. zip ( ours) . zip ( theirs) . expect ( "would use binary if missing" ) ;
338
340
let resolution = builtin_driver:: text (
339
341
out,
340
342
input,
@@ -353,11 +355,15 @@ pub(super) mod inner {
353
355
}
354
356
}
355
357
356
- fn is_binary_buf ( buf : Option < & [ u8 ] > ) -> bool {
357
- buf. map_or ( true , |buf| {
358
- let buf = & buf[ ..buf. len ( ) . min ( 8000 ) ] ;
359
- buf. contains ( & 0 )
360
- } )
358
+ fn is_binary_buf ( data : resource:: Data < ' _ > ) -> bool {
359
+ match data {
360
+ Data :: Missing => false ,
361
+ Data :: Buffer ( buf) => {
362
+ let buf = & buf[ ..buf. len ( ) . min ( 8000 ) ] ;
363
+ buf. contains ( & 0 )
364
+ }
365
+ Data :: TooLarge { .. } => true ,
366
+ }
361
367
}
362
368
}
363
369
}
@@ -412,13 +418,45 @@ impl<'parent> PlatformRef<'parent> {
412
418
}
413
419
414
420
/// Using a `pick` obtained from [`merge()`](Self::merge), obtain the respective buffer suitable for reading or copying.
415
- /// Return `None` if the buffer is too large, or if the `pick` corresponds to a buffer (that was written separately).
416
- pub fn buffer_by_pick ( & self , pick : inner:: builtin_merge:: Pick ) -> Option < & ' parent [ u8 ] > {
421
+ /// Return `Ok(None)` if the `pick` corresponds to a buffer (that was written separately).
422
+ /// Return `Err(())` if the buffer is *too large*, so it was never read.
423
+ #[ allow( clippy:: result_unit_err) ]
424
+ pub fn buffer_by_pick ( & self , pick : inner:: builtin_merge:: Pick ) -> Result < Option < & ' parent [ u8 ] > , ( ) > {
417
425
match pick {
418
- inner:: builtin_merge:: Pick :: Ancestor => self . ancestor . data . as_slice ( ) ,
419
- inner:: builtin_merge:: Pick :: Ours => self . current . data . as_slice ( ) ,
420
- inner:: builtin_merge:: Pick :: Theirs => self . other . data . as_slice ( ) ,
421
- inner:: builtin_merge:: Pick :: Buffer => None ,
426
+ inner:: builtin_merge:: Pick :: Ancestor => self . ancestor . data . as_slice ( ) . map ( Some ) . ok_or ( ( ) ) ,
427
+ inner:: builtin_merge:: Pick :: Ours => self . current . data . as_slice ( ) . map ( Some ) . ok_or ( ( ) ) ,
428
+ inner:: builtin_merge:: Pick :: Theirs => self . other . data . as_slice ( ) . map ( Some ) . ok_or ( ( ) ) ,
429
+ inner:: builtin_merge:: Pick :: Buffer => Ok ( None ) ,
430
+ }
431
+ }
432
+
433
+ /// Use `pick` to return the object id of the merged result, assuming that `buf` was passed as `out` to [merge()](Self::merge).
434
+ /// In case of binary or large files, this will simply be the existing ID of the resource.
435
+ /// In case of resources available in the object DB for binary merges, the object ID will be returned.
436
+ /// If new content was produced due to a content merge, `buf` will be written out
437
+ /// to the object database using `write_blob`.
438
+ /// Beware that the returned ID could be `Ok(None)` if the underlying resource was loaded
439
+ /// from the worktree *and* was too large so it was never loaded from disk.
440
+ /// `Ok(None)` will also be returned if one of the resources was missing.
441
+ /// `write_blob()` is used to turn buffers.
442
+ pub fn id_by_pick < E > (
443
+ & self ,
444
+ pick : inner:: builtin_merge:: Pick ,
445
+ buf : & [ u8 ] ,
446
+ mut write_blob : impl FnMut ( & [ u8 ] ) -> Result < gix_hash:: ObjectId , E > ,
447
+ ) -> Result < Option < gix_hash:: ObjectId > , E > {
448
+ let field = match pick {
449
+ inner:: builtin_merge:: Pick :: Ancestor => & self . ancestor ,
450
+ inner:: builtin_merge:: Pick :: Ours => & self . current ,
451
+ inner:: builtin_merge:: Pick :: Theirs => & self . other ,
452
+ inner:: builtin_merge:: Pick :: Buffer => return write_blob ( buf) . map ( Some ) ,
453
+ } ;
454
+ use crate :: blob:: platform:: resource:: Data ;
455
+ match field. data {
456
+ Data :: TooLarge { .. } | Data :: Missing if !field. id . is_null ( ) => Ok ( Some ( field. id . to_owned ( ) ) ) ,
457
+ Data :: TooLarge { .. } | Data :: Missing => Ok ( None ) ,
458
+ Data :: Buffer ( buf) if field. id . is_null ( ) => write_blob ( buf) . map ( Some ) ,
459
+ Data :: Buffer ( _) => Ok ( Some ( field. id . to_owned ( ) ) ) ,
422
460
}
423
461
}
424
462
}
0 commit comments