@@ -266,6 +266,8 @@ pub(super) mod inner {
266266
267267 ///
268268 pub mod builtin_merge {
269+ use crate :: blob:: platform:: resource;
270+ use crate :: blob:: platform:: resource:: Data ;
269271 use crate :: blob:: { builtin_driver, BuiltinDriver , PlatformRef , Resolution } ;
270272
271273 /// 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 {
307309 input : & mut imara_diff:: intern:: InternedInput < & ' parent [ u8 ] > ,
308310 labels : builtin_driver:: text:: Labels < ' _ > ,
309311 ) -> ( 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 ( ) ;
313315 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 ) )
315319 {
316320 BuiltinDriver :: Binary
317321 } else {
318322 driver
319323 } ;
320324 match driver {
321325 BuiltinDriver :: Text => {
322- let ( ( base, ours) , theirs) = base. zip ( ours) . zip ( theirs) . expect ( "would use binary if missing" ) ;
323326 let resolution =
324327 builtin_driver:: text ( out, input, labels, ours, base, theirs, self . options . text ) ;
325328 ( Pick :: Buffer , resolution)
@@ -334,7 +337,6 @@ pub(super) mod inner {
334337 ( pick, resolution)
335338 }
336339 BuiltinDriver :: Union => {
337- let ( ( base, ours) , theirs) = base. zip ( ours) . zip ( theirs) . expect ( "would use binary if missing" ) ;
338340 let resolution = builtin_driver:: text (
339341 out,
340342 input,
@@ -353,11 +355,15 @@ pub(super) mod inner {
353355 }
354356 }
355357
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+ }
361367 }
362368 }
363369}
@@ -412,13 +418,45 @@ impl<'parent> PlatformRef<'parent> {
412418 }
413419
414420 /// 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 ] > , ( ) > {
417425 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 ( ) ) ) ,
422460 }
423461 }
424462}
0 commit comments