use abi_stable::pointer_trait::ImmutableRef;
use abi_stable::std_types::{RArc, ROption, RStr, RString};
use abi_stable::{sabi_trait, traits::IntoReprC, RRef, StableAbi};
use std::fmt::Debug;
pub const MAX_SCORE: u32 = u32::MAX;
pub const MIN_SCORE: u32 = u32::MIN;
pub type ArcDynHit = Hit_TO<'static, RArc<()>>;
#[sabi_trait]
pub trait Hit: Sync + Send + Debug {
fn title(&self) -> RStr<'_>;
fn subtitle(&self) -> RStr<'_> {
RStr::default()
}
fn override_score(&self) -> ROption<u32> {
ROption::RNone
}
fn action(&self, context: RefDynHitActionContext<'_>);
fn secondary_action(&self, context: RefDynHitActionContext<'_>) {
log::trace!("no secondary action set for hit '{}'", self.title());
self.action(context);
}
}
pub fn clone_hit_arc(hit: &ArcDynHit) -> ArcDynHit {
ArcDynHit::from_sabi(hit.obj.shallow_clone())
}
#[repr(C)]
#[derive(StableAbi, Debug, PartialEq, Eq, Copy, Clone)]
pub enum ActionKind {
Primary,
Secondary,
}
#[repr(C)]
#[derive(StableAbi, Debug)]
pub struct ScoredHit {
pub hit: ArcDynHit,
pub score: u32,
}
impl ScoredHit {
pub fn from(hit: ArcDynHit, score: u32) -> Self {
Self { hit, score }
}
}
pub type RefDynHitActionContext<'a> = HitActionContext_TO<'static, RRef<'a, ()>>;
#[sabi_trait]
pub trait HitActionContext {
fn hide_frontend(&self);
fn refresh_frontend(&self);
fn exit(&self);
fn restart(&self);
fn set_query(&self, query: RString);
fn clear_caches(&self);
}
type SimpleHitAction = Box<dyn Fn(&SimpleHit, RefDynHitActionContext<'_>) + Send + Sync>;
#[repr(C)]
pub struct SimpleHit {
pub title: RString,
pub subtitle: RString,
pub override_score: ROption<u32>,
#[allow(clippy::type_complexity)]
pub action: SimpleHitAction,
pub secondary_action: Option<SimpleHitAction>,
}
impl Debug for SimpleHit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SimpleHit")
.field("title", &self.title)
.field("subtitle", &self.subtitle)
.field("override_score", &self.override_score)
.field("action", &format_args!("Fn@{:p}", self.action.to_raw_ptr()))
.finish()
}
}
impl SimpleHit {
#[must_use]
pub fn new(
title: impl Into<RString>,
subtitle: impl Into<RString>,
func: impl Fn(&Self, RefDynHitActionContext<'_>) + Send + Sync + 'static,
) -> Self {
Self {
title: title.into(),
subtitle: subtitle.into(),
override_score: ROption::RNone,
action: Box::new(func),
secondary_action: None,
}
}
#[must_use]
pub fn with_score(mut self, score: impl Into<Option<u32>>) -> Self {
let option: Option<u32> = score.into();
self.override_score = option.into_c();
self
}
#[must_use]
pub fn with_secondary(
mut self,
action: impl Fn(&Self, RefDynHitActionContext<'_>) + Send + Sync + 'static,
) -> Self {
self.secondary_action = Some(Box::new(action));
self
}
}
impl Hit for SimpleHit {
fn action(&self, context: RefDynHitActionContext<'_>) {
(self.action)(self, context);
}
fn secondary_action(&self, context: RefDynHitActionContext<'_>) {
let Some(action) = &self.secondary_action else {
log::trace!("no secondary action set for hit '{}'", self.title());
return self.action(context);
};
(action)(self, context);
}
#[must_use]
fn title(&self) -> RStr<'_> {
self.title.as_rstr()
}
#[must_use]
fn subtitle(&self) -> RStr<'_> {
self.subtitle.as_rstr()
}
#[must_use]
fn override_score(&self) -> ROption<u32> {
self.override_score
}
}
impl From<SimpleHit> for ArcDynHit {
fn from(value: SimpleHit) -> Self {
Self::from_ptr(RArc::new(value), sabi_trait::TD_Opaque)
}
}