nvim_oxi_api/
trait_utils.rs

1use std::error::Error as StdError;
2use std::iter::FusedIterator;
3
4use luajit::{Poppable, Pushable};
5use types::{Array, Function, LuaRef, Object};
6use types::{HlGroupId, Integer};
7
8use crate::IntoResult;
9
10/// A super trait of most common traits implemented on iterators.
11pub trait SuperIterator<I>:
12    Iterator<Item = I> + ExactSizeIterator + DoubleEndedIterator + FusedIterator
13{
14}
15
16impl<I, T> SuperIterator<I> for T where
17    T: Iterator<Item = I>
18        + ExactSizeIterator
19        + DoubleEndedIterator
20        + FusedIterator
21{
22}
23
24macro_rules! impl_into {
25    ($trait:ident, $type:ty) => {
26        impl $trait for $type {
27            fn to_object(self) -> Object {
28                self.into()
29            }
30        }
31    };
32}
33
34/// A trait implemented by strings and integers.
35pub trait StringOrInt {
36    fn to_object(self) -> Object;
37}
38
39impl_into!(StringOrInt, &str);
40impl_into!(StringOrInt, String);
41impl_into!(StringOrInt, i8);
42impl_into!(StringOrInt, u8);
43impl_into!(StringOrInt, i16);
44impl_into!(StringOrInt, u16);
45impl_into!(StringOrInt, i32);
46impl_into!(StringOrInt, u32);
47impl_into!(StringOrInt, i64);
48
49/// A trait implemented by strings and list of strings.
50pub trait StringOrListOfStrings {
51    fn to_object(self) -> Object;
52}
53
54impl_into!(StringOrListOfStrings, &str);
55impl_into!(StringOrListOfStrings, String);
56
57// Here I'd like to use `IntoIterator` instead of `Vec`, but without
58// specilization that'd cause conflicting impls.
59impl<S: Into<String>> StringOrListOfStrings for Vec<S> {
60    #[inline]
61    fn to_object(self) -> Object {
62        Array::from_iter(self.into_iter().map(Into::into)).into()
63    }
64}
65
66/// A trait implemented by closures and [`Function`]s.
67pub trait ToFunction<A, R> {
68    fn into_luaref(self) -> LuaRef;
69}
70
71impl<A, R, F, O> ToFunction<A, R> for F
72where
73    A: Poppable,
74    R: Pushable,
75    F: FnMut(A) -> O + 'static,
76    O: IntoResult<R>,
77    O::Error: StdError + 'static,
78{
79    #[inline]
80    fn into_luaref(self) -> LuaRef {
81        Function::from_fn_mut(self).lua_ref()
82    }
83}
84
85impl<A, R> ToFunction<A, R> for Function<A, R> {
86    #[inline]
87    fn into_luaref(self) -> LuaRef {
88        self.lua_ref()
89    }
90}
91
92/// A trait implemented by closures, [`Function`]s and strings.
93pub trait StringOrFunction<A, R> {
94    fn to_object(self) -> Object;
95}
96
97impl<A, R> StringOrFunction<A, R> for &str {
98    #[inline]
99    fn to_object(self) -> Object {
100        self.into()
101    }
102}
103
104impl<A, R> StringOrFunction<A, R> for String {
105    #[inline]
106    fn to_object(self) -> Object {
107        self.into()
108    }
109}
110
111impl<F, A, R, O> StringOrFunction<A, R> for F
112where
113    F: FnMut(A) -> O + 'static,
114    A: Poppable,
115    R: Pushable,
116    O: IntoResult<R>,
117    O::Error: StdError + 'static,
118{
119    #[inline]
120    fn to_object(self) -> Object {
121        Function::from_fn_mut(self).into()
122    }
123}
124
125impl<A, R> StringOrFunction<A, R> for Function<A, R> {
126    #[inline]
127    fn to_object(self) -> Object {
128        self.into()
129    }
130}
131
132/// A trait implemented by types that can be converted to a highlight group ID.
133pub trait HlGroup: sealed::Sealed {
134    type Error;
135
136    fn to_hl_id(&self) -> Result<HlGroupId, Self::Error>;
137}
138
139impl HlGroup for Integer {
140    type Error = core::convert::Infallible;
141
142    #[inline(always)]
143    fn to_hl_id(&self) -> Result<HlGroupId, Self::Error> {
144        Ok(*self)
145    }
146}
147
148impl HlGroup for &str {
149    type Error = crate::Error;
150
151    #[inline]
152    fn to_hl_id(&self) -> Result<HlGroupId, Self::Error> {
153        let obj = types::String::from(*self).into();
154        let mut err = types::Error::default();
155        let hl_id = unsafe {
156            crate::ffi::helpers::object_to_hl_id(
157                obj,
158                c"hl_group".as_ptr() as *const _,
159                &mut err,
160            )
161        };
162        if err.is_err() { Err(err.into()) } else { Ok(hl_id) }
163    }
164}
165
166/// A trait implemented by types that can be passed to
167/// [`SetExtmarkOptsBuilder::hl_group`](crate::opts::SetExtmarkOptsBuilder::hl_group).
168#[cfg(feature = "neovim-0-11")] // On 0.11 and Nightly.
169#[cfg_attr(docsrs, doc(cfg(feature = "neovim-0-11")))]
170pub trait SetExtmarkHlGroup {
171    fn into_object(self) -> Object;
172}
173
174#[cfg(feature = "neovim-0-11")] // On 0.11 and Nightly.
175impl SetExtmarkHlGroup for Integer {
176    #[inline]
177    fn into_object(self) -> Object {
178        self.into()
179    }
180}
181
182#[cfg(feature = "neovim-0-11")] // On 0.11 and Nightly.
183impl SetExtmarkHlGroup for &str {
184    #[inline]
185    fn into_object(self) -> Object {
186        self.into()
187    }
188}
189
190#[cfg(feature = "neovim-0-11")] // On 0.11 and Nightly.
191impl<T: StringOrInt> SetExtmarkHlGroup for Vec<T> {
192    #[inline]
193    fn into_object(self) -> Object {
194        self.into_iter().map(StringOrInt::to_object).collect::<Array>().into()
195    }
196}
197
198mod sealed {
199    pub trait Sealed {}
200
201    impl Sealed for types::Integer {}
202
203    impl Sealed for &str {}
204}