1use std::{
4 borrow::Cow,
5 cell::{Cell, RefCell},
6 cmp::Reverse,
7 collections::{BTreeSet, HashSet, LinkedList, VecDeque},
8 ffi::{CStr, CString},
9 net::{IpAddr, Ipv4Addr, Ipv6Addr},
10 num::{
11 NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64,
12 NonZeroU8,
13 },
14 sync::{
15 atomic::{
16 AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicU16, AtomicU32, AtomicU64, AtomicU8,
17 },
18 Mutex, RwLock,
19 },
20};
21
22use indexmap::IndexMap;
23use serde::{Serialize, Serializer};
24
25mod param;
26pub use {param::Params, param::Value as ParamValue};
27
28pub trait ToMapping {
32 fn to_mapping() -> Mapping {
34 Self::to_mapping_with_params(Params::default())
35 }
36
37 #[doc(hidden)]
41 fn to_mapping_with_params(options: Params) -> Mapping;
42}
43
44#[derive(Debug, Clone)]
78pub enum Mapping {
79 #[doc(hidden)]
80 Scalar(Property),
81 #[doc(hidden)]
82 Object(Object),
83}
84
85#[doc(hidden)]
87impl Mapping {
88 pub fn scalar(type_name: &'static str, options: impl Into<Params>) -> Self {
89 Self::Scalar(Property {
90 ty: type_name,
91 options: options.into(),
92 })
93 }
94
95 pub fn object(
96 i: impl Iterator<Item = (&'static str, Mapping)>,
97 options: impl Into<Params>,
98 ) -> Self {
99 Self::Object(Object {
100 properties: i.collect(),
101 options: options.into(),
102 })
103 }
104}
105
106impl Serialize for Mapping {
107 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
108 where
109 S: Serializer,
110 {
111 match self {
112 Mapping::Scalar(type_name) => type_name.serialize(serializer),
113 Mapping::Object(map) => map.serialize(serializer),
114 }
115 }
116}
117
118#[derive(Serialize, Debug, Clone)]
120pub struct Property {
121 #[serde(rename = "type")]
122 ty: &'static str,
123
124 #[serde(flatten)]
125 options: Params,
126}
127
128#[derive(Serialize, Debug, Clone)]
130pub struct Object {
131 properties: IndexMap<&'static str, Mapping>,
132
133 #[serde(flatten)]
134 options: Params,
135}
136
137macro_rules! impl_scalar_mapping {
138 ($name:literal, $($ty:ty),+) => {
139 $(
140 impl $crate::ToMapping for $ty {
141 fn to_mapping_with_params(options: $crate::Params) -> $crate::Mapping {
142 $crate::Mapping::scalar($name, options)
143 }
144 }
145 )+
146 };
147}
148
149impl_scalar_mapping!("binary", &[u8], &CStr, CString);
152
153impl_scalar_mapping!("boolean", bool);
154
155impl_scalar_mapping!("long", i64, NonZeroI64, AtomicI64);
157impl_scalar_mapping!("unsigned_long", u64, NonZeroU64, AtomicU64);
158impl_scalar_mapping!("integer", i32, NonZeroI32, AtomicI32);
159impl_scalar_mapping!("unsigned_long", u32, NonZeroU32, AtomicU32);
160impl_scalar_mapping!("short", i16, NonZeroI16, AtomicI16);
161impl_scalar_mapping!("unsigned_long", u16, NonZeroU16, AtomicU16);
162impl_scalar_mapping!("byte", i8, NonZeroI8, AtomicI8);
163impl_scalar_mapping!("unsigned_long", u8, NonZeroU8, AtomicU8);
164impl_scalar_mapping!("double", f64);
165impl_scalar_mapping!("float", f32);
166
167#[cfg(feature = "nightly")]
168impl_scalar_mapping!("half_float", f16);
169
170impl_scalar_mapping!("date", std::time::SystemTime);
172
173impl_scalar_mapping!("ip", IpAddr, Ipv4Addr, Ipv6Addr);
175
176macro_rules! impl_string_mapping {
181 ($($ty:ty),+) => {
182 $(
183 impl $crate::ToMapping for $ty {
184 fn to_mapping_with_params(options: $crate::Params) -> $crate::Mapping {
185 let mut local = $crate::default_string_options();
186 local.extend(options);
187
188 $crate::Mapping::scalar("text", local)
189 }
190 }
191 )+
192 }
193}
194
195pub fn default_string_options() -> Params {
201 [(
202 "fields",
203 ParamValue::Nested(
204 [(
205 "keyword",
206 ParamValue::Nested(
207 [
208 ("ignore_above", ParamValue::Uint(256)),
209 ("type", ParamValue::String("keyword")),
210 ]
211 .into_iter()
212 .collect(),
213 ),
214 )]
215 .into_iter()
216 .collect(),
217 ),
218 )]
219 .into_iter()
220 .collect()
221}
222
223impl_string_mapping!(String, &str, Cow<'_, str>);
224
225#[cfg(feature = "chrono")]
227impl_scalar_mapping!("date", chrono::NaiveDateTime, chrono::NaiveDate);
228
229#[cfg(feature = "chrono")]
230macro_rules! impl_chrono_mapping {
231 ($name:literal, $generic:ident, $($ty:ty),+) => {
232 $(
233 #[allow(deprecated)]
234 #[cfg(feature = "chrono")]
235 impl<$generic: chrono::TimeZone> $crate::ToMapping for $ty {
236 fn to_mapping_with_params(options: $crate::Params) -> $crate::Mapping {
237 $crate::Mapping::scalar($name, options)
238 }
239 }
240 )+
241 }
242}
243
244#[cfg(feature = "chrono")]
245impl_chrono_mapping!("date", T, chrono::DateTime<T>, chrono::Date<T>);
246
247macro_rules! impl_container_mapping {
248 (<$($generics:tt),+> $inner:ident for $ty:ty where $($where:ident: $trait:ident),*) => {
249 impl<$($generics),+> ToMapping for $ty
250 where
251 $inner: ToMapping,
252 $($where: $trait),*
253 {
254 fn to_mapping_with_params(options: Params) -> Mapping {
255 $inner::to_mapping_with_params(options)
256 }
257 }
258 };
259 (<$($generics:tt),+> $inner:ident for $ty:ty) => {
260 impl_container_mapping!(<$($generics),+> $inner for $ty where);
261 };
262 ($generic:ident for $ty:ty) => {
263 impl_container_mapping!(<$generic> $generic for $ty);
264 };
265}
266
267impl_container_mapping!(T for Option<T>);
269
270impl_container_mapping!(T for BTreeSet<T>);
273impl_container_mapping!(T for Box<T>);
274impl_container_mapping!(T for Cell<T>);
275impl_container_mapping!(<'a, T> T for Cow<'a, T> where T: Clone);
276impl_container_mapping!(T for HashSet<T>);
277impl_container_mapping!(T for LinkedList<T>);
278impl_container_mapping!(T for Mutex<T>);
279impl_container_mapping!(T for RefCell<T>);
280impl_container_mapping!(T for Reverse<T>);
281impl_container_mapping!(T for RwLock<T>);
282impl_container_mapping!(T for Vec<T>);
283impl_container_mapping!(T for VecDeque<T>);
284
285#[cfg(feature = "rc")]
286impl_container_mapping!(T for std::sync::Arc<T>);
287#[cfg(feature = "rc")]
288impl_container_mapping!(T for std::rc::Rc<T>);
289#[cfg(feature = "rc")]
290impl_container_mapping!(T for std::rc::Weak<T>);
291#[cfg(feature = "rc")]
292impl_container_mapping!(T for std::sync::Weak<T>);