Skip to main content

ferroui_reactiveui/binding/command_binding/
command_binder_service.rs

1//! `CommandBinderService` (ReactiveUI.Binding, `CommandBinding/CommandBinderService.cs`), with the
2//! check of `CommandBindingAffinityChecker` (`Fallback/CommandBindingAffinityChecker.cs`).
3
4use crate::binding::interfaces::ICreatesCommandBinding;
5use ferroui_splat::AppLocator;
6use std::any::TypeId;
7use std::rc::Rc;
8
9/// Finds the [`ICreatesCommandBinding`] with the highest affinity for a type of control
10/// (`CommandBinderService`), as the property observation finds its observer.
11pub struct CommandBinderService;
12
13impl CommandBinderService {
14    /// The registered binder with the highest positive affinity for the control type `T`; of equal
15    /// affinities the first registered wins; `None` when every binder answers zero or less
16    /// (`GetBinder<T>(bool hasEventTarget)`).
17    pub fn get_binder<T: ?Sized + 'static>(has_event_target: bool) -> Option<Rc<dyn ICreatesCommandBinding>> {
18        Self::get_binder_for(TypeId::of::<T>(), has_event_target)
19    }
20
21    /// [`get_binder`](Self::get_binder) for the control type `target_type`.
22    pub fn get_binder_for(target_type: TypeId, has_event_target: bool) -> Option<Rc<dyn ICreatesCommandBinding>> {
23        let mut best_binder = None;
24        let mut best_affinity = 0;
25        for binder in AppLocator::get_services::<dyn ICreatesCommandBinding>() {
26            let affinity = binder.get_affinity_for_object(target_type, has_event_target);
27            if affinity <= best_affinity {
28                continue;
29            }
30            best_affinity = affinity;
31            best_binder = Some(binder);
32        }
33        best_binder
34    }
35
36    /// The registered binder with the highest affinity for `target_type` when it outranks
37    /// `own_affinity`, the affinity of the binding the caller would make itself
38    /// (`CommandBindingAffinityChecker.HasHigherAffinityPlugin<T>` and `GetBinder<T>`).
39    pub fn get_binder_above(target_type: TypeId, own_affinity: i32, has_event_target: bool) -> Option<Rc<dyn ICreatesCommandBinding>> {
40        let binder = Self::get_binder_for(target_type, has_event_target)?;
41        (binder.get_affinity_for_object(target_type, has_event_target) > own_affinity).then_some(binder)
42    }
43}