1- use  bstr:: { BStr ,  BString } ; 
2- 
3- use  crate :: blob:: pipeline:: DriverChoice ; 
4- use  crate :: blob:: { pipeline,  Pipeline ,  Platform ,  ResourceKind } ; 
1+ use  crate :: blob:: { pipeline,  BuiltinDriver ,  Pipeline ,  Platform ,  ResourceKind } ; 
2+ use  bstr:: { BStr ,  BString ,  ByteSlice } ; 
3+ use  gix_filter:: attributes; 
54
65/// A stored value representing a resource that participates in a merge. 
76#[ derive( Clone ,  Eq ,  PartialEq ,  Ord ,  PartialOrd ,  Debug ) ]  
@@ -10,8 +9,8 @@ pub(super) struct Resource {
109     id :  gix_hash:: ObjectId , 
1110    /// The repository-relative path where the resource lives in the tree. 
1211     rela_path :  BString , 
13-     /// The outcome of converting a resource into a diffable  format using [Pipeline::convert_to_mergeable()]. 
14-      conversion :   pipeline:: Outcome , 
12+     /// The outcome of converting a resource into a mergable  format using [Pipeline::convert_to_mergeable()]. 
13+      data :   Option < pipeline:: Data > , 
1514    /// The kind of the resource we are looking at. Only possible values are `Blob` and `BlobExecutable`. 
1615     mode :  gix_object:: tree:: EntryKind , 
1716    /// A possibly empty buffer, depending on `conversion.data` which may indicate the data is considered binary 
@@ -34,21 +33,61 @@ pub struct ResourceRef<'a> {
3433     pub  id :  & ' a  gix_hash:: oid , 
3534} 
3635
36+ /// Options for use in a [`Platform`]. 
37+ #[ derive( Default ,  Clone ,  PartialEq ,  Eq ,  Debug ,  Hash ,  Ord ,  PartialOrd ) ]  
38+ pub  struct  Options  { 
39+     /// Define which driver to use by name if the `merge` attribute for a resource is unspecified. 
40+      /// 
41+      /// This is the value of the `merge.default` git configuration. 
42+      pub  default_driver :  Option < BString > , 
43+ } 
44+ 
45+ /// The selection of the driver to use by a resource obtained with [`Pipeline::convert_to_mergeable()`]. 
46+ /// 
47+ /// If available, an index into the `drivers` field to access more diff-related information of the driver for items 
48+ /// at the given path, as previously determined by git-attributes. 
49+ /// 
50+ /// * `merge` is set 
51+ ///     - Use the [`BuiltinDriver::Text`] 
52+ /// * `-merge` is unset 
53+ ///     - Use the [`BuiltinDriver::Binary`] 
54+ /// * `!merge` is unspecified 
55+ ///     - Use [`Options::default_driver`] or [`BuiltinDriver::Text`]. 
56+ /// * `merge=name` 
57+ ///     - Search for a user-configured or built-in driver called `name`. 
58+ ///     - If not found, silently default to [`BuiltinDriver::Text`] 
59+ /// 
60+ /// Note that drivers are queried even if there is no object available. 
61+ #[ derive( Copy ,  Clone ,  Eq ,  PartialEq ,  Ord ,  PartialOrd ,  Debug ,  Hash ) ]  
62+ pub  enum  DriverChoice  { 
63+     /// Use the given built-in driver to perform the merge. 
64+      BuiltIn ( BuiltinDriver ) , 
65+     /// Use the user-provided driver program using the index into [the pipelines driver array](Pipeline::drivers(). 
66+      Index ( usize ) , 
67+ } 
68+ 
69+ impl  Default  for  DriverChoice  { 
70+     fn  default ( )  -> Self  { 
71+         DriverChoice :: BuiltIn ( Default :: default ( ) ) 
72+     } 
73+ } 
74+ 
3775/// 
3876pub  mod  resource { 
77+     use  crate :: blob:: platform:: DriverChoice ; 
3978    use  crate :: blob:: { 
4079        pipeline, 
4180        platform:: { Resource ,  ResourceRef } , 
4281    } ; 
4382
4483    impl < ' a >  ResourceRef < ' a >  { 
45-         pub ( super )  fn  new ( cache :  & ' a  Resource )  -> Self  { 
84+         pub ( super )  fn  new ( cache :  & ' a  Resource ,   driver :   DriverChoice )  -> Self  { 
4685            ResourceRef  { 
47-                 data :  cache. conversion . data . map_or ( Data :: Missing ,  |data| match  data { 
86+                 data :  cache. data . map_or ( Data :: Missing ,  |data| match  data { 
4887                    pipeline:: Data :: Buffer  => Data :: Buffer ( & cache. buffer ) , 
49-                     pipeline:: Data :: Binary  {  size }  => Data :: Binary  {  size } , 
88+                     pipeline:: Data :: TooLarge  {  size }  => Data :: Binary  {  size } , 
5089                } ) , 
51-                 driver_choice :  cache . conversion . driver , 
90+                 driver_choice :  driver, 
5291                rela_path :  cache. rela_path . as_ref ( ) , 
5392                id :  & cache. id , 
5493            } 
@@ -118,7 +157,7 @@ pub mod set_resource {
118157
119158/// 
120159pub  mod  merge { 
121-     use  crate :: blob:: pipeline :: DriverChoice ; 
160+     use  crate :: blob:: platform :: DriverChoice ; 
122161    use  crate :: blob:: platform:: ResourceRef ; 
123162    use  crate :: blob:: { builtin_driver,  BuiltinDriver ,  Driver ,  Resolution } ; 
124163    use  bstr:: BString ; 
@@ -269,7 +308,7 @@ pub mod merge {
269308         pub  fn  configured_driver ( & self )  -> Result < & ' parent  Driver ,  BuiltinDriver >  { 
270309            match  self . current . driver_choice  { 
271310                DriverChoice :: BuiltIn ( builtin)  => Err ( builtin) , 
272-                 DriverChoice :: Index ( idx)  => self . parent . filter . drivers . get ( idx) . ok_or ( BuiltinDriver :: default ( ) ) , 
311+                 DriverChoice :: Index ( idx)  => self . parent . drivers . get ( idx) . ok_or ( BuiltinDriver :: default ( ) ) , 
273312            } 
274313        } 
275314    } 
@@ -299,6 +338,9 @@ pub mod merge {
299338
300339/// 
301340pub  mod  prepare_merge { 
341+     use  crate :: blob:: ResourceKind ; 
342+     use  bstr:: BString ; 
343+ 
302344    /// The error returned by [Platform::prepare_merge()](super::Platform::prepare_merge_state()). 
303345     #[ derive( Debug ,  thiserror:: Error ) ]  
304346    #[ allow( missing_docs) ]  
@@ -307,6 +349,12 @@ pub mod prepare_merge {
307349        UnsetResource , 
308350        #[ error( "Tried to merge 'current' and 'other' where at least one of them is removed" ) ]  
309351        CurrentOrOtherRemoved , 
352+         #[ error( "Failed to obtain attributes for {kind:?} resource at '{rela_path}'" ) ]  
353+         Attributes  { 
354+             rela_path :  BString , 
355+             kind :  ResourceKind , 
356+             source :  std:: io:: Error , 
357+         } , 
310358    } 
311359} 
312360
@@ -315,18 +363,44 @@ impl Platform {
315363    /// Create a new instance with a way to `filter` data from the object database and turn it into something that is merge-able. 
316364     /// `filter_mode` decides how to do that specifically. 
317365     /// Use `attr_stack` to access attributes pertaining worktree filters and merge settings. 
318-      pub  fn  new ( filter :  Pipeline ,  filter_mode :  pipeline:: Mode ,  attr_stack :  gix_worktree:: Stack )  -> Self  { 
366+      /// `drivers` are the list of available merge drivers that individual paths can refer to by means of git attributes. 
367+      /// `options` further configure the operation. 
368+      pub  fn  new ( 
369+         filter :  Pipeline , 
370+         filter_mode :  pipeline:: Mode , 
371+         attr_stack :  gix_worktree:: Stack , 
372+         mut  drivers :  Vec < super :: Driver > , 
373+         options :  Options , 
374+     )  -> Self  { 
375+         drivers. sort_by ( |a,  b| a. name . cmp ( & b. name ) ) ; 
319376        Platform  { 
377+             drivers, 
320378            current :  None , 
321379            ancestor :  None , 
322380            other :  None , 
323381            filter, 
324382            filter_mode, 
325383            attr_stack, 
384+             attrs :  { 
385+                 let  mut  out = attributes:: search:: Outcome :: default ( ) ; 
386+                 out. initialize_with_selection ( & Default :: default ( ) ,  Some ( "merge" ) ) ; 
387+                 out
388+             } , 
389+             options, 
326390        } 
327391    } 
328392} 
329393
394+ /// Access 
395+ impl  Platform  { 
396+     /// Return all drivers that this instance was initialized with. 
397+      /// 
398+      /// They are sorted by [`name`](super::Driver::name) to support binary searches. 
399+      pub  fn  drivers ( & self )  -> & [ super :: Driver ]  { 
400+         & self . drivers 
401+     } 
402+ } 
403+ 
330404/// Preparation 
331405impl  Platform  { 
332406    /// Store enough information about a resource to eventually use it in a merge, where… 
@@ -351,30 +425,60 @@ impl Platform {
351425        self . set_resource_inner ( id,  mode,  rela_path,  kind,  objects) 
352426    } 
353427
354-     /// Returns the resource of the given kind if it was set. 
355-      pub  fn  resource ( & self ,  kind :  ResourceKind )  -> Option < ResourceRef < ' _ > >  { 
356-         let  cache = match  kind { 
357-             ResourceKind :: CurrentOrOurs  => self . current . as_ref ( ) , 
358-             ResourceKind :: CommonAncestorOrBase  => self . ancestor . as_ref ( ) , 
359-             ResourceKind :: OtherOrTheirs  => self . other . as_ref ( ) , 
360-         } ?; 
361-         ResourceRef :: new ( cache) . into ( ) 
362-     } 
363- 
364428    /// Prepare all state needed for performing a merge, using all [previously set](Self::set_resource()) resources. 
365-      pub  fn  prepare_merge_state ( & self )  -> Result < merge:: State < ' _ > ,  prepare_merge:: Error >  { 
429+      pub  fn  prepare_merge_state ( 
430+         & mut  self , 
431+         objects :  & impl  gix_object:: Find , 
432+     )  -> Result < merge:: State < ' _ > ,  prepare_merge:: Error >  { 
366433        let  current = self . current . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?; 
367434        let  ancestor = self . ancestor . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?; 
368435        let  other = self . other . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?; 
369436
437+         let  entry = self 
438+             . attr_stack 
439+             . at_entry ( current. rela_path . as_bstr ( ) ,  None ,  objects) 
440+             . map_err ( |err| prepare_merge:: Error :: Attributes  { 
441+                 source :  err, 
442+                 kind :  ResourceKind :: CurrentOrOurs , 
443+                 rela_path :  current. rela_path . clone ( ) , 
444+             } ) ?; 
445+         entry. matching_attributes ( & mut  self . attrs ) ; 
446+         let  attr = self . attrs . iter_selected ( ) . next ( ) . expect ( "pre-initialized with 'diff'" ) ; 
447+         let  driver = match  attr. assignment . state  { 
448+             attributes:: StateRef :: Set  => DriverChoice :: BuiltIn ( BuiltinDriver :: Text ) , 
449+             attributes:: StateRef :: Unset  => DriverChoice :: BuiltIn ( BuiltinDriver :: Binary ) , 
450+             attributes:: StateRef :: Value ( _)  | attributes:: StateRef :: Unspecified  => { 
451+                 let  name = match  attr. assignment . state  { 
452+                     attributes:: StateRef :: Value ( name)  => Some ( name. as_bstr ( ) ) , 
453+                     attributes:: StateRef :: Unspecified  => { 
454+                         self . options . default_driver . as_ref ( ) . map ( |name| name. as_bstr ( ) ) 
455+                     } 
456+                     _ => unreachable ! ( "only value and unspecified are possible here" ) , 
457+                 } ; 
458+                 name. and_then ( |name| { 
459+                     self . drivers 
460+                         . binary_search_by ( |d| d. name . as_bstr ( ) . cmp ( name) ) 
461+                         . ok ( ) 
462+                         . map ( DriverChoice :: Index ) 
463+                         . or_else ( || { 
464+                             name. to_str ( ) 
465+                                 . ok ( ) 
466+                                 . and_then ( BuiltinDriver :: by_name) 
467+                                 . map ( DriverChoice :: BuiltIn ) 
468+                         } ) 
469+                 } ) 
470+                 . unwrap_or_default ( ) 
471+             } 
472+         } ; 
473+ 
370474        let  out = merge:: State  { 
371475            parent :  self , 
372-             current :  ResourceRef :: new ( current) , 
373-             ancestor :  ResourceRef :: new ( ancestor) , 
374-             other :  ResourceRef :: new ( other) , 
476+             current :  ResourceRef :: new ( current,  driver ) , 
477+             ancestor :  ResourceRef :: new ( ancestor,  driver ) , 
478+             other :  ResourceRef :: new ( other,  driver ) , 
375479        } ; 
376480
377-         match  ( current. conversion . data ,  other. conversion . data )  { 
481+         match  ( current. data ,  other. data )  { 
378482            ( None ,  None )  => Err ( prepare_merge:: Error :: CurrentOrOtherRemoved ) , 
379483            ( _,  _)  => Ok ( out) , 
380484        } 
@@ -430,15 +534,15 @@ impl Platform {
430534                * storage = Some ( Resource  { 
431535                    id, 
432536                    rela_path :  rela_path. to_owned ( ) , 
433-                     conversion :  out, 
537+                     data :  out, 
434538                    mode, 
435539                    buffer :  buf_storage, 
436540                } ) ; 
437541            } 
438542            Some ( storage)  => { 
439543                storage. id  = id; 
440544                storage. rela_path  = rela_path. to_owned ( ) ; 
441-                 storage. conversion  = out; 
545+                 storage. data  = out; 
442546                storage. mode  = mode; 
443547            } 
444548        } ; 
0 commit comments