From f24123f943abaebffd098a12069bcca62181f862 Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Sat, 6 Aug 2022 15:06:18 -0300 Subject: Fix predicates --- Cargo.toml | 1 + src/lib.rs | 29 ++++++++++++++++++++++++----- src/pattern.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/vm.rs | 9 ++++++++- src/vm/de.rs | 6 ++++++ tests/basic_match.rs | 4 +++- 6 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 src/vm/de.rs diff --git a/Cargo.toml b/Cargo.toml index a0532df..1a85a35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ erased-serde = "0.3.21" proptest = "1.0.0" serde_json = "1.0.82" serde = {version = "1.0.140", features = ["derive"]} +charx = "1" [features] default = ['stable'] diff --git a/src/lib.rs b/src/lib.rs index 8fa727f..a3a6e1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,15 +106,34 @@ mod vm; pub use pattern::Pattern; /// A predicate. -pub type Predicate = dyn (for<'x, 'de, 'a> Fn( - &'x (dyn 'a + erased_serde::Deserializer<'de>) +pub type Predicate = dyn (Fn( + &mut dyn erased_serde::Deserializer<> ) -> bool) + Send + Sync; -/// Helper to build predicates because HRTB inference is the worst. +/// Helper to build predicates because closure inference is the worst. +/// +/// # Examples +/// +/// This doesn't work: +/// +/// ```rust compile_fail +/// use serde::Deserialize; +/// use datafu::Predicate; +/// +/// let x = Box::new(|v| String::deserialize(v).is_ok()) as Box; +/// ``` +/// +/// But this does: +/// +/// ```rust +/// use serde::Deserialize; +/// +/// let x = datafu::pred(|v| String::deserialize(v).is_ok()); +/// ``` pub fn pred(f: F) -> Box where - F: (for<'x, 'de, 'a> Fn( - &'x (dyn 'a + erased_serde::Deserializer<'de>) + F: (Fn( + &mut dyn erased_serde::Deserializer<> ) -> bool) + Send + Sync + 'static, { Box::new(f) diff --git a/src/pattern.rs b/src/pattern.rs index 3a8c91f..2e69714 100644 --- a/src/pattern.rs +++ b/src/pattern.rs @@ -1,6 +1,8 @@ // Copyright (C) 2021-2022 Soni L. // SPDX-License-Identifier: MIT OR Apache-2.0 +//! Datafu Patterns. + use std::borrow::Borrow; use std::collections::BTreeMap; @@ -15,12 +17,57 @@ use crate::parser::parse; use crate::vm::PatternConstants; //use crate::vm::MAX_CALLS; +/// A compiled Datafu pattern. +/// +/// # Examples +/// +/// ``` +/// use datafu::Pattern; +/// +/// let pattern = Pattern::<()>::compile::<&str, &str>( +/// "->'hello'", +/// None, None +/// ).expect("failed to compile pattern"); +/// ``` pub struct Pattern { consts: PatternConstants, } impl Pattern { /// Compiles the input into a pattern. + /// + /// # Examples + /// + /// ``` + /// use datafu::Pattern; + /// use serde::Deserialize; + /// use charx; + /// + /// let preds = vec![ + /// ("dict", datafu::pred(|v| { todo!() })), + /// ("str", datafu::pred(|v| { String::deserialize(v).is_ok() })), + /// ("commit", datafu::pred(|v| { + /// if let Ok(v) = String::deserialize(v) { + /// v.len() == 40 && v.trim_start_matches( + /// charx::is_ascii_hexdigit + /// ).is_empty() + /// } else { + /// false + /// } + /// })), + /// ("uri", datafu::pred(|v| { todo!() })), + /// ("bool", datafu::pred(|v| { todo!() })), + /// ].into_iter().collect(); + /// let pattern = Pattern::<()>::compile::<&str, &str>(" + /// ->'projects':$dict + /// ->commit[:?$str:?$commit]:?$dict + /// ->url[:?$str:?$uri]:?$dict + /// ->branch:?$dict + /// (->active'active'?:?$bool) + /// (->federate'federate'?:?$bool)?", + /// Some(preds), None + /// ).expect("failed to compile pattern"); + /// ``` pub fn compile<'s, PKey, OKey>( input: &'s str, preds: Option>>, diff --git a/src/vm.rs b/src/vm.rs index 6bcbf70..ac5c95d 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,17 +1,24 @@ // Copyright (C) 2021-2022 Soni L. // SPDX-License-Identifier: MIT OR Apache-2.0 +//! The Datafu Virtual Machine. +//! +//! This is the stuff that actually matches the pattern. + use regex::Regex; use serde::Serialize; use crate::Predicate; //use crate::errors::MatchError; +mod de; + +/// Max depth for VM/serde recursion. pub(crate) const MAX_CALLS: usize = 250; //type Matches<'a, 'b, T> = BTreeMap<&'a str, KVPair<'b, T>>; -// TODO: use a builder for this? +// maybe we should use a builder for this? /// The constant pool for a pattern. pub(crate) struct PatternConstants { // last proto is implicitly the whole pattern. diff --git a/src/vm/de.rs b/src/vm/de.rs new file mode 100644 index 0000000..7039ea9 --- /dev/null +++ b/src/vm/de.rs @@ -0,0 +1,6 @@ +// Copyright (C) 2022 Soni L. +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use crate::vm; + + diff --git a/tests/basic_match.rs b/tests/basic_match.rs index 1500356..5c03a48 100644 --- a/tests/basic_match.rs +++ b/tests/basic_match.rs @@ -4,10 +4,12 @@ use serde_json::Deserializer as JsonDer; use serde::Deserialize; +use datafu::Predicate; + #[test] fn test_basic() { let mut der = JsonDer::from_str(r#"{"foo": 1, "bar": {"baz": 2}}"#); - let preds = vec![("dict", datafu::pred(|v| { todo!() }))].into_iter().collect(); + let preds = vec![("dict", datafu::pred(|v| { todo!(); false }))].into_iter().collect(); let pat = datafu::Pattern::<()>::compile::<&str, &str>("->[x]:?$dict->y[yk]", Some(preds), None).unwrap(); #[derive(Deserialize)] struct Values { -- cgit 1.4.1