Skip to content

Commit 3c0a452

Browse files
committed
feature: matcher are clonable so there is no need to raise an exception when the matcher was used for second time
1 parent 8eb14e5 commit 3c0a452

2 files changed

Lines changed: 35 additions & 43 deletions

File tree

src/lib.rs

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use pyo3::create_exception;
2-
use pyo3::exceptions;
3-
use pyo3::prelude::*;
1+
use pyo3::{class::PyNumberProtocol, create_exception, exceptions, prelude::*};
42

53
use std::sync::{Arc, Mutex};
64
use streamson_lib::{error, handler, matcher, Collector};
@@ -18,7 +16,7 @@ impl From<error::General> for StreamsonError {
1816
#[pyclass]
1917
#[derive(Debug)]
2018
pub struct RustMatcher {
21-
inner: Option<matcher::Combinator>,
19+
inner: matcher::Combinator,
2220
}
2321

2422
#[pymethods]
@@ -31,7 +29,7 @@ impl RustMatcher {
3129
#[staticmethod]
3230
pub fn simple(path: String) -> PyResult<Self> {
3331
Ok(Self {
34-
inner: Some(matcher::Combinator::new(matcher::Simple::new(path))),
32+
inner: matcher::Combinator::new(matcher::Simple::new(path)),
3533
})
3634
}
3735

@@ -43,46 +41,33 @@ impl RustMatcher {
4341
#[staticmethod]
4442
pub fn depth(min_depth: usize, max_depth: Option<usize>) -> PyResult<Self> {
4543
Ok(Self {
46-
inner: Some(matcher::Combinator::new(matcher::Depth::new(
47-
min_depth, max_depth,
48-
))),
44+
inner: matcher::Combinator::new(matcher::Depth::new(min_depth, max_depth)),
4945
})
5046
}
47+
}
5148

52-
pub fn inv(&mut self) -> PyResult<Self> {
53-
if let Some(inner) = self.inner.take() {
54-
Ok(Self {
55-
inner: Some(!inner),
56-
})
57-
} else {
58-
Err(MatcherUsed.into())
49+
#[pyproto]
50+
impl PyNumberProtocol for RustMatcher {
51+
/// Inverts the matcher
52+
fn __invert__(&self) -> Self {
53+
Self {
54+
inner: !self.inner.clone(),
5955
}
6056
}
6157

62-
pub fn any(&mut self, right: &mut RustMatcher) -> PyResult<Self> {
63-
if let (Some(left), Some(right)) = (self.inner.take(), right.inner.take()) {
64-
Ok(Self {
65-
inner: Some(left | right),
66-
})
67-
} else {
68-
Err(MatcherUsed.into())
58+
/// One of the matcher should match
59+
fn __or__(lhs: PyRef<'p, Self>, rhs: PyRef<'p, Self>) -> Self {
60+
Self {
61+
inner: lhs.inner.clone() | rhs.inner.clone(),
6962
}
7063
}
7164

72-
pub fn all(&mut self, right: &mut RustMatcher) -> PyResult<Self> {
73-
if let (Some(left), Some(right)) = (self.inner.take(), right.inner.take()) {
74-
Ok(Self {
75-
inner: Some(left & right),
76-
})
77-
} else {
78-
Err(MatcherUsed.into())
65+
/// All matchers should match
66+
fn __and__(lhs: PyRef<'p, Self>, rhs: PyRef<'p, Self>) -> Self {
67+
Self {
68+
inner: lhs.inner.clone() & rhs.inner.clone(),
7969
}
8070
}
81-
82-
#[getter]
83-
pub fn _used(&self) -> bool {
84-
self.inner.is_none()
85-
}
8671
}
8772

8873
/// Low level Python wrapper for Simple matcher and Buffer handler
@@ -99,10 +84,10 @@ impl Streamson {
9984
/// # Arguments
10085
/// * `matches` - a list of valid simple matches (e.g. `{"users"}`, `[]{"name"}`, `[0]{}`)
10186
#[new]
102-
pub fn new(matcher: &mut RustMatcher) -> PyResult<Self> {
87+
pub fn new(matcher: &RustMatcher) -> PyResult<Self> {
10388
let handler = Arc::new(Mutex::new(handler::Buffer::new()));
104-
let matcher = matcher.inner.take().ok_or(MatcherUsed)?;
105-
let collector = Collector::new().add_matcher(Box::new(matcher), &[handler.clone()]);
89+
let collector =
90+
Collector::new().add_matcher(Box::new(matcher.inner.clone()), &[handler.clone()]);
10691
Ok(Self { collector, handler })
10792
}
10893

streamson/__init__.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,32 @@ def __init__(self, rust_matcher: _RustMatcher):
1111
self.inner = rust_matcher
1212

1313
def __invert__(self):
14-
self.inner = self.inner.inv()
15-
return self
14+
return Matcher(~self.inner)
1615

1716
def __or__(self, other):
18-
self.inner = self.inner.any(other.inner)
19-
return self
17+
return Matcher(self.inner | other.inner)
2018

2119
def __and__(self, other):
22-
self.inner = self.inner.all(other.inner)
23-
return self
20+
return Matcher(self.inner & other.inner)
2421

2522

2623
class DepthMatcher(Matcher):
2724
def __init__(self, min_depth: int, max_depth: typing.Optional[int] = None):
25+
""" Depth matcher which matches the depth in json.
26+
:param: min_depth: minimal matched depth
27+
:param: max_depth: maximal matched depth (optinal if not set it will match all higher)
28+
"""
2829
super().__init__(_RustMatcher.depth(min_depth, max_depth))
2930

3031

3132
class SimpleMatcher(Matcher):
3233
def __init__(self, path: str):
34+
""" Simple matcher to use for json matching
35+
e.g.
36+
{"user"}[] will match {"user"}[0], {"user"}[1], ...
37+
{}[0] will match {"user"}[0], {"group"}[0]
38+
39+
"""
3340
super().__init__(_RustMatcher.simple(path))
3441

3542

0 commit comments

Comments
 (0)