1#![cfg_attr(feature = "specialized", feature(specialization))]
96
97pub use crate::errors::{ErrorReason, JmespathError, RuntimeError};
98pub use crate::parser::{parse, ParseResult};
99pub use crate::runtime::Runtime;
100pub use crate::variable::Variable;
101
102pub mod ast;
103pub mod functions;
104
105use serde::ser;
106#[cfg(feature = "specialized")]
107use serde_json::Value;
108#[cfg(feature = "specialized")]
109use std::convert::TryInto;
110use std::fmt;
111
112use lazy_static::*;
113
114use crate::ast::Ast;
115use crate::interpreter::{interpret, SearchResult};
116
117mod errors;
118mod interpreter;
119mod lexer;
120mod parser;
121mod runtime;
122mod variable;
123
124lazy_static! {
125 pub static ref DEFAULT_RUNTIME: Runtime = {
126 let mut runtime = Runtime::new();
127 runtime.register_builtin_functions();
128 runtime
129 };
130}
131
132#[cfg(not(feature = "sync"))]
134pub type Rcvar = std::rc::Rc<Variable>;
135#[cfg(feature = "sync")]
137pub type Rcvar = std::sync::Arc<Variable>;
138
139#[inline]
147pub fn compile(expression: &str) -> Result<Expression<'static>, JmespathError> {
148 DEFAULT_RUNTIME.compile(expression)
149}
150
151#[cfg_attr(
154 feature = "specialized",
155 doc = "\
156There is a generic serde Serialize implementation, and since this
157documentation was compiled with the `specialized` feature turned
158**on**, there are also a number of specialized implementations for
159`ToJmespath` built into the library that should work for most
160cases."
161)]
162#[cfg_attr(
163 not(feature = "specialized"),
164 doc = "\
165There is a generic serde Serialize implementation. Since this
166documentation was compiled with the `specialized` feature turned
167**off**, this is the only implementation available.
168
169(If the `specialized` feature were turned on, there there would be
170a number of additional specialized implementations for `ToJmespath`
171built into the library that should work for most cases.)"
172)]
173pub trait ToJmespath {
174 fn to_jmespath(self) -> Result<Rcvar, JmespathError>;
175}
176
177impl<'a, T: ser::Serialize> ToJmespath for T {
179 #[cfg(not(feature = "specialized"))]
180 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
181 Ok(Variable::from_serializable(self).map(Rcvar::new)?)
182 }
183
184 #[cfg(feature = "specialized")]
185 default fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
186 Ok(Variable::from_serializable(self).map(|var| Rcvar::new(var))?)
187 }
188}
189
190#[cfg(feature = "specialized")]
191impl ToJmespath for Value {
192 #[inline]
193 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
194 self.try_into().map(|var: Variable| Rcvar::new(var))
195 }
196}
197
198#[cfg(feature = "specialized")]
199impl<'a> ToJmespath for &'a Value {
200 #[inline]
201 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
202 self.try_into().map(|var: Variable| Rcvar::new(var))
203 }
204}
205
206#[cfg(feature = "specialized")]
207impl ToJmespath for Rcvar {
209 #[inline]
210 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
211 Ok(self)
212 }
213}
214
215#[cfg(feature = "specialized")]
216impl<'a> ToJmespath for &'a Rcvar {
217 #[inline]
218 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
219 Ok(self.clone())
220 }
221}
222
223#[cfg(feature = "specialized")]
224impl ToJmespath for Variable {
225 #[inline]
226 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
227 Ok(Rcvar::new(self))
228 }
229}
230
231#[cfg(feature = "specialized")]
232impl<'a> ToJmespath for &'a Variable {
233 #[inline]
234 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
235 Ok(Rcvar::new(self.clone()))
236 }
237}
238
239#[cfg(feature = "specialized")]
240impl ToJmespath for String {
241 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
242 Ok(Rcvar::new(Variable::String(self)))
243 }
244}
245
246#[cfg(feature = "specialized")]
247impl<'a> ToJmespath for &'a str {
248 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
249 Ok(Rcvar::new(Variable::String(self.to_owned())))
250 }
251}
252
253#[cfg(feature = "specialized")]
254impl ToJmespath for i8 {
255 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
256 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
257 }
258}
259
260#[cfg(feature = "specialized")]
261impl ToJmespath for i16 {
262 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
263 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
264 }
265}
266
267#[cfg(feature = "specialized")]
268impl ToJmespath for i32 {
269 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
270 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
271 }
272}
273
274#[cfg(feature = "specialized")]
275impl ToJmespath for i64 {
276 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
277 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
278 }
279}
280
281#[cfg(feature = "specialized")]
282impl ToJmespath for u8 {
283 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
284 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
285 }
286}
287
288#[cfg(feature = "specialized")]
289impl ToJmespath for u16 {
290 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
291 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
292 }
293}
294
295#[cfg(feature = "specialized")]
296impl ToJmespath for u32 {
297 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
298 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
299 }
300}
301
302#[cfg(feature = "specialized")]
303impl ToJmespath for u64 {
304 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
305 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
306 }
307}
308
309#[cfg(feature = "specialized")]
310impl ToJmespath for isize {
311 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
312 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
313 }
314}
315
316#[cfg(feature = "specialized")]
317impl ToJmespath for usize {
318 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
319 Ok(Rcvar::new(Variable::Number(serde_json::Number::from(self))))
320 }
321}
322
323#[cfg(feature = "specialized")]
324impl ToJmespath for f32 {
325 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
326 (self as f64).to_jmespath()
327 }
328}
329
330#[cfg(feature = "specialized")]
331impl ToJmespath for f64 {
332 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
333 Ok(Rcvar::new(Variable::Number(
334 serde_json::Number::from_f64(self).ok_or_else(|| {
335 JmespathError::new(
336 "",
337 0,
338 ErrorReason::Parse(format!("Cannot parse {} into a Number", self)),
339 )
340 })?,
341 )))
342 }
343}
344
345#[cfg(feature = "specialized")]
346impl ToJmespath for () {
347 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
348 Ok(Rcvar::new(Variable::Null))
349 }
350}
351
352#[cfg(feature = "specialized")]
353impl ToJmespath for bool {
354 fn to_jmespath(self) -> Result<Rcvar, JmespathError> {
355 Ok(Rcvar::new(Variable::Bool(self)))
356 }
357}
358
359#[derive(Clone)]
367pub struct Expression<'a> {
368 ast: Ast,
369 expression: String,
370 runtime: &'a Runtime,
371}
372
373impl<'a> Expression<'a> {
374 #[inline]
379 pub fn new<S>(expression: S, ast: Ast, runtime: &'a Runtime) -> Expression<'a>
380 where
381 S: Into<String>,
382 {
383 Expression {
384 expression: expression.into(),
385 ast,
386 runtime,
387 }
388 }
389
390 pub fn search<T: ToJmespath>(&self, data: T) -> SearchResult {
397 let mut ctx = Context::new(&self.expression, self.runtime);
398 interpret(&data.to_jmespath()?, &self.ast, &mut ctx)
399 }
400
401 pub fn as_str(&self) -> &str {
406 &self.expression
407 }
408
409 pub fn as_ast(&self) -> &Ast {
413 &self.ast
414 }
415}
416
417impl<'a> fmt::Display for Expression<'a> {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420 write!(f, "{}", self.as_str())
421 }
422}
423
424impl<'a> fmt::Debug for Expression<'a> {
425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426 fmt::Display::fmt(self, f)
427 }
428}
429
430impl<'a> PartialEq for Expression<'a> {
431 fn eq(&self, other: &Expression<'_>) -> bool {
432 self.as_str() == other.as_str()
433 }
434}
435
436pub struct Context<'a> {
442 pub expression: &'a str,
444 pub runtime: &'a Runtime,
446 pub offset: usize,
448}
449
450impl<'a> Context<'a> {
451 #[inline]
453 pub fn new(expression: &'a str, runtime: &'a Runtime) -> Context<'a> {
454 Context {
455 expression,
456 runtime,
457 offset: 0,
458 }
459 }
460}
461
462#[cfg(test)]
463mod test {
464 use super::ast::Ast;
465 use super::*;
466
467 #[test]
468 fn formats_expression_as_string_or_debug() {
469 let expr = compile("foo | baz").unwrap();
470 assert_eq!("foo | baz/foo | baz", format!("{}/{:?}", expr, expr));
471 }
472
473 #[test]
474 fn implements_partial_eq() {
475 let a = compile("@").unwrap();
476 let b = compile("@").unwrap();
477 assert!(a == b);
478 }
479
480 #[test]
481 fn can_evaluate_jmespath_expression() {
482 let expr = compile("foo.bar").unwrap();
483 let var = Variable::from_json("{\"foo\":{\"bar\":true}}").unwrap();
484 assert_eq!(Rcvar::new(Variable::Bool(true)), expr.search(var).unwrap());
485 }
486
487 #[test]
488 fn can_get_expression_ast() {
489 let expr = compile("foo").unwrap();
490 assert_eq!(
491 &Ast::Field {
492 offset: 0,
493 name: "foo".to_string(),
494 },
495 expr.as_ast()
496 );
497 }
498
499 #[test]
500 fn test_creates_rcvar_from_tuple_serialization() {
501 use super::ToJmespath;
502 let t = (true, false);
503 assert_eq!("[true,false]", t.to_jmespath().unwrap().to_string());
504 }
505
506 #[test]
507 fn expression_clone() {
508 let expr = compile("foo").unwrap();
509 let _ = expr.clone();
510 }
511}