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 
@@ -26,14 +25,51 @@ pub struct ResourceRef<'a> {
2625     pub  data :  resource:: Data < ' a > , 
2726    /// The location of the resource, relative to the working tree. 
2827     pub  rela_path :  & ' a  BStr , 
29-     /// Which driver to use according to the resource's configuration. 
30-      pub  driver_choice :  DriverChoice , 
3128    /// The id of the content as it would be stored in `git`, or `null` if the content doesn't exist anymore at 
3229     /// `rela_path` or if it was never computed. This can happen with content read from the worktree, which 
3330     /// after its 'to-git' conversion never had its hash computed. 
3431     pub  id :  & ' a  gix_hash:: oid , 
3532} 
3633
34+ /// Options for use in a [`Platform`]. 
35+ #[ derive( Default ,  Clone ,  PartialEq ,  Eq ,  Debug ,  Hash ,  Ord ,  PartialOrd ) ]  
36+ pub  struct  Options  { 
37+     /// Define which driver to use by name if the `merge` attribute for a resource is unspecified. 
38+      /// 
39+      /// This is the value of the `merge.default` git configuration. 
40+      pub  default_driver :  Option < BString > , 
41+ } 
42+ 
43+ /// The selection of the driver to use by a resource obtained with [`Pipeline::convert_to_mergeable()`]. 
44+ /// 
45+ /// If available, an index into the `drivers` field to access more diff-related information of the driver for items 
46+ /// at the given path, as previously determined by git-attributes. 
47+ /// 
48+ /// * `merge` is set 
49+ ///     - Use the [`BuiltinDriver::Text`] 
50+ /// * `-merge` is unset 
51+ ///     - Use the [`BuiltinDriver::Binary`] 
52+ /// * `!merge` is unspecified 
53+ ///     - Use [`Options::default_driver`] or [`BuiltinDriver::Text`]. 
54+ /// * `merge=name` 
55+ ///     - Search for a user-configured or built-in driver called `name`. 
56+ ///     - If not found, silently default to [`BuiltinDriver::Text`] 
57+ /// 
58+ /// Note that drivers are queried even if there is no object available. 
59+ #[ derive( Copy ,  Clone ,  Eq ,  PartialEq ,  Ord ,  PartialOrd ,  Debug ,  Hash ) ]  
60+ pub  enum  DriverChoice  { 
61+     /// Use the given built-in driver to perform the merge. 
62+      BuiltIn ( BuiltinDriver ) , 
63+     /// Use the user-provided driver program using the index into [the pipelines driver array](Pipeline::drivers(). 
64+      Index ( usize ) , 
65+ } 
66+ 
67+ impl  Default  for  DriverChoice  { 
68+     fn  default ( )  -> Self  { 
69+         DriverChoice :: BuiltIn ( Default :: default ( ) ) 
70+     } 
71+ } 
72+ 
3773/// 
3874pub  mod  resource { 
3975    use  crate :: blob:: { 
@@ -44,11 +80,10 @@ pub mod resource {
4480    impl < ' a >  ResourceRef < ' a >  { 
4581        pub ( super )  fn  new ( cache :  & ' a  Resource )  -> Self  { 
4682            ResourceRef  { 
47-                 data :  cache. conversion . data . map_or ( Data :: Missing ,  |data| match  data { 
83+                 data :  cache. data . map_or ( Data :: Missing ,  |data| match  data { 
4884                    pipeline:: Data :: Buffer  => Data :: Buffer ( & cache. buffer ) , 
49-                     pipeline:: Data :: Binary  {  size }  => Data :: Binary  {  size } , 
85+                     pipeline:: Data :: TooLarge  {  size }  => Data :: Binary  {  size } , 
5086                } ) , 
51-                 driver_choice :  cache. conversion . driver , 
5287                rela_path :  cache. rela_path . as_ref ( ) , 
5388                id :  & cache. id , 
5489            } 
@@ -118,7 +153,7 @@ pub mod set_resource {
118153
119154/// 
120155pub  mod  merge { 
121-     use  crate :: blob:: pipeline :: DriverChoice ; 
156+     use  crate :: blob:: platform :: DriverChoice ; 
122157    use  crate :: blob:: platform:: ResourceRef ; 
123158    use  crate :: blob:: { builtin_driver,  BuiltinDriver ,  Driver ,  Resolution } ; 
124159    use  bstr:: BString ; 
@@ -135,6 +170,9 @@ pub mod merge {
135170         pub  ancestor :  ResourceRef < ' parent > , 
136171        /// The other or their side of the merge operation. 
137172         pub  other :  ResourceRef < ' parent > , 
173+         /// Which driver to use according to the resource's configuration, 
174+          /// using the path of `current` to read git-attributes. 
175+          pub  driver_choice :  DriverChoice , 
138176    } 
139177
140178    #[ derive( Copy ,  Clone ,  Debug ,  Eq ,  PartialEq ) ]  
@@ -267,9 +305,9 @@ pub mod merge {
267305        /// Return the configured driver program for use with [`Self::prepare_external_driver()`], or `Err` 
268306         /// with the built-in driver to use instead. 
269307         pub  fn  configured_driver ( & self )  -> Result < & ' parent  Driver ,  BuiltinDriver >  { 
270-             match  self . current . driver_choice  { 
308+             match  self . driver_choice  { 
271309                DriverChoice :: BuiltIn ( builtin)  => Err ( builtin) , 
272-                 DriverChoice :: Index ( idx)  => self . parent . filter . drivers . get ( idx) . ok_or ( BuiltinDriver :: default ( ) ) , 
310+                 DriverChoice :: Index ( idx)  => self . parent . drivers . get ( idx) . ok_or ( BuiltinDriver :: default ( ) ) , 
273311            } 
274312        } 
275313    } 
@@ -299,14 +337,21 @@ pub mod merge {
299337
300338/// 
301339pub  mod  prepare_merge { 
340+     use  crate :: blob:: ResourceKind ; 
341+     use  bstr:: BString ; 
342+ 
302343    /// The error returned by [Platform::prepare_merge()](super::Platform::prepare_merge_state()). 
303344     #[ derive( Debug ,  thiserror:: Error ) ]  
304345    #[ allow( missing_docs) ]  
305346    pub  enum  Error  { 
306347        #[ error( "The 'current', 'ancestor' or 'other' resource for the merge operation were not set" ) ]  
307348        UnsetResource , 
308-         #[ error( "Tried to merge 'current' and 'other' where at least one of them is removed" ) ]  
309-         CurrentOrOtherRemoved , 
349+         #[ error( "Failed to obtain attributes for {kind:?} resource at '{rela_path}'" ) ]  
350+         Attributes  { 
351+             rela_path :  BString , 
352+             kind :  ResourceKind , 
353+             source :  std:: io:: Error , 
354+         } , 
310355    } 
311356} 
312357
@@ -315,18 +360,44 @@ impl Platform {
315360    /// Create a new instance with a way to `filter` data from the object database and turn it into something that is merge-able. 
316361     /// `filter_mode` decides how to do that specifically. 
317362     /// 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  { 
363+      /// `drivers` are the list of available merge drivers that individual paths can refer to by means of git attributes. 
364+      /// `options` further configure the operation. 
365+      pub  fn  new ( 
366+         filter :  Pipeline , 
367+         filter_mode :  pipeline:: Mode , 
368+         attr_stack :  gix_worktree:: Stack , 
369+         mut  drivers :  Vec < super :: Driver > , 
370+         options :  Options , 
371+     )  -> Self  { 
372+         drivers. sort_by ( |a,  b| a. name . cmp ( & b. name ) ) ; 
319373        Platform  { 
374+             drivers, 
320375            current :  None , 
321376            ancestor :  None , 
322377            other :  None , 
323378            filter, 
324379            filter_mode, 
325380            attr_stack, 
381+             attrs :  { 
382+                 let  mut  out = attributes:: search:: Outcome :: default ( ) ; 
383+                 out. initialize_with_selection ( & Default :: default ( ) ,  Some ( "merge" ) ) ; 
384+                 out
385+             } , 
386+             options, 
326387        } 
327388    } 
328389} 
329390
391+ /// Access 
392+ impl  Platform  { 
393+     /// Return all drivers that this instance was initialized with. 
394+      /// 
395+      /// They are sorted by [`name`](super::Driver::name) to support binary searches. 
396+      pub  fn  drivers ( & self )  -> & [ super :: Driver ]  { 
397+         & self . drivers 
398+     } 
399+ } 
400+ 
330401/// Preparation 
331402impl  Platform  { 
332403    /// Store enough information about a resource to eventually use it in a merge, where… 
@@ -351,33 +422,62 @@ impl Platform {
351422        self . set_resource_inner ( id,  mode,  rela_path,  kind,  objects) 
352423    } 
353424
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- 
364425    /// 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 >  { 
426+      /// Note that no additional validation is performed here to facilitate inspection. 
427+      pub  fn  prepare_merge_state ( 
428+         & mut  self , 
429+         objects :  & impl  gix_object:: Find , 
430+     )  -> Result < merge:: State < ' _ > ,  prepare_merge:: Error >  { 
366431        let  current = self . current . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?; 
367432        let  ancestor = self . ancestor . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?; 
368433        let  other = self . other . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?; 
369434
435+         let  entry = self 
436+             . attr_stack 
437+             . at_entry ( current. rela_path . as_bstr ( ) ,  None ,  objects) 
438+             . map_err ( |err| prepare_merge:: Error :: Attributes  { 
439+                 source :  err, 
440+                 kind :  ResourceKind :: CurrentOrOurs , 
441+                 rela_path :  current. rela_path . clone ( ) , 
442+             } ) ?; 
443+         entry. matching_attributes ( & mut  self . attrs ) ; 
444+         let  attr = self . attrs . iter_selected ( ) . next ( ) . expect ( "pre-initialized with 'diff'" ) ; 
445+         let  driver = match  attr. assignment . state  { 
446+             attributes:: StateRef :: Set  => DriverChoice :: BuiltIn ( BuiltinDriver :: Text ) , 
447+             attributes:: StateRef :: Unset  => DriverChoice :: BuiltIn ( BuiltinDriver :: Binary ) , 
448+             attributes:: StateRef :: Value ( _)  | attributes:: StateRef :: Unspecified  => { 
449+                 let  name = match  attr. assignment . state  { 
450+                     attributes:: StateRef :: Value ( name)  => Some ( name. as_bstr ( ) ) , 
451+                     attributes:: StateRef :: Unspecified  => { 
452+                         self . options . default_driver . as_ref ( ) . map ( |name| name. as_bstr ( ) ) 
453+                     } 
454+                     _ => unreachable ! ( "only value and unspecified are possible here" ) , 
455+                 } ; 
456+                 name. and_then ( |name| { 
457+                     self . drivers 
458+                         . binary_search_by ( |d| d. name . as_bstr ( ) . cmp ( name) ) 
459+                         . ok ( ) 
460+                         . map ( DriverChoice :: Index ) 
461+                         . or_else ( || { 
462+                             name. to_str ( ) 
463+                                 . ok ( ) 
464+                                 . and_then ( BuiltinDriver :: by_name) 
465+                                 . map ( DriverChoice :: BuiltIn ) 
466+                         } ) 
467+                 } ) 
468+                 . unwrap_or_default ( ) 
469+             } 
470+         } ; 
471+ 
370472        let  out = merge:: State  { 
371473            parent :  self , 
474+             driver_choice :  driver, 
372475            current :  ResourceRef :: new ( current) , 
373476            ancestor :  ResourceRef :: new ( ancestor) , 
374477            other :  ResourceRef :: new ( other) , 
375478        } ; 
376479
377-         match  ( current. conversion . data ,  other. conversion . data )  { 
378-             ( None ,  None )  => Err ( prepare_merge:: Error :: CurrentOrOtherRemoved ) , 
379-             ( _,  _)  => Ok ( out) , 
380-         } 
480+         Ok ( out) 
381481    } 
382482} 
383483
@@ -430,15 +530,15 @@ impl Platform {
430530                * storage = Some ( Resource  { 
431531                    id, 
432532                    rela_path :  rela_path. to_owned ( ) , 
433-                     conversion :  out, 
533+                     data :  out, 
434534                    mode, 
435535                    buffer :  buf_storage, 
436536                } ) ; 
437537            } 
438538            Some ( storage)  => { 
439539                storage. id  = id; 
440540                storage. rela_path  = rela_path. to_owned ( ) ; 
441-                 storage. conversion  = out; 
541+                 storage. data  = out; 
442542                storage. mode  = mode; 
443543            } 
444544        } ; 
0 commit comments