Skip to content

Commit

Permalink
finish effector stream (#145)
Browse files Browse the repository at this point in the history
* finish effector stream

* simplify code

* bump version

* add assert to make sure that when we call current it's already finished

* Fix: clippy warnings
  • Loading branch information
GopherJ authored May 12, 2020
1 parent 7344df3 commit e99cfa3
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 84 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "casbin"
version = "0.7.6"
version = "0.8.1"
authors = ["Joey <[email protected]>", "Cheng JIANG <[email protected]>"]
edition = "2018"
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Add this package to `Cargo.toml` of your project. (Check https://crates.io/crate

```toml
[dependencies]
casbin = { version = "0.7.6", default-features = false, features = ["runtime-async-std", "logging"] }
casbin = { version = "0.8.1", default-features = false, features = ["runtime-async-std", "logging"] }
async-std = { version = "1.5.0", features = ["attributes"] }
env_logger = "0.7.1"
```
Expand Down
119 changes: 70 additions & 49 deletions src/effector.rs
Original file line number Diff line number Diff line change
@@ -1,67 +1,88 @@
pub trait Effector: Send + Sync {
fn merge_effects(&self, expr: &str, effects: Vec<EffectKind>) -> bool;
}

#[derive(PartialEq, Clone)]
#[derive(PartialEq, Clone, Copy)]
pub enum EffectKind {
Allow = 0,
Indeterminate = 1,
Deny = 2,
}

pub trait Effector: Send + Sync {
fn new_stream(&self, expr: &str, cap: usize) -> Box<dyn EffectorStream>;
}

pub trait EffectorStream: Send + Sync {
fn current(&self) -> bool;
fn push_effect(&mut self, eft: EffectKind) -> (bool, bool);
}

pub struct DefaultEffectStream {
done: bool,
res: bool,
expr: String,
effects: Vec<EffectKind>,
}

#[derive(Default)]
pub struct DefaultEffector;

impl Effector for DefaultEffector {
fn merge_effects(&self, expr: &str, effects: Vec<EffectKind>) -> bool {
if expr == "some(where (p_eft == allow))" {
let mut result = false;
for eft in effects {
if eft == EffectKind::Allow {
result = true;
break;
}
}
fn new_stream(&self, expr: &str, cap: usize) -> Box<dyn EffectorStream> {
let res = match &*expr {
"some(where (p_eft == allow))"
| "some(where (p_eft == allow)) && !some(where (p_eft == deny))"
| "priority(p_eft) || deny" => false,
"!some(where (p_eft == deny))" => true,
_ => panic!("unsupported effect: `{}`", expr),
};

result
} else if expr == "!some(where (p_eft == deny))" {
let mut result = true;
for eft in effects {
if eft == EffectKind::Deny {
result = false;
break;
}
}
Box::new(DefaultEffectStream {
done: false,
res,
expr: expr.to_owned(),
effects: Vec::with_capacity(cap),
})
}
}

result
} else if expr == "some(where (p_eft == allow)) && !some(where (p_eft == deny))" {
let mut result = false;
for eft in effects {
if eft == EffectKind::Allow {
result = true;
} else if eft == EffectKind::Deny {
result = false;
break;
}
}
impl EffectorStream for DefaultEffectStream {
fn current(&self) -> bool {
assert!(self.done);
self.res
}

fn push_effect(&mut self, eft: EffectKind) -> (bool, bool) {
let cap = self.effects.capacity();
self.effects.push(eft);

result
} else if expr == "priority(p_eft) || deny" {
let mut result = false;
for eft in effects {
if eft != EffectKind::Indeterminate {
if eft == EffectKind::Allow {
result = true
} else {
result = false
}
break;
}
if self.expr == "some(where (p_eft == allow))" {
if eft == EffectKind::Allow {
self.done = true;
self.res = true;
}
} else if self.expr == "some(where (p_eft == allow)) && !some(where (p_eft == deny))" {
if eft == EffectKind::Allow {
self.res = true;
} else if eft == EffectKind::Deny {
self.done = true;
self.res = false;
}
} else if self.expr == "!some(where (p_eft == deny))" {
if eft == EffectKind::Deny {
self.done = true;
self.res = false;
}
} else if self.expr == "priority(p_eft) || deny" && eft != EffectKind::Indeterminate {
if eft == EffectKind::Allow {
self.res = true;
} else {
self.res = false;
}
self.done = true;
}

result
} else {
panic!("unsupported effect: `{}`", expr);
if cap == self.effects.len() {
self.done = true;
}

(self.done, self.res)
}
}
62 changes: 30 additions & 32 deletions src/enforcer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,14 @@ impl Enforcer {
}
}

let mut policy_effects: Vec<EffectKind> = vec![];
let policies = p_ast.get_policy();
let policy_len = policies.len();
let mut eft_stream = self
.eft
.new_stream(&e_ast.value, if policy_len > 0 { policy_len } else { 1 });
let scope_size = scope.len();

if policy_len != 0 {
policy_effects = vec![EffectKind::Deny; policy_len];
for (i, pvals) in policies.iter().enumerate() {
if i != 0 {
scope.rewind(scope_size);
Expand All @@ -175,34 +176,30 @@ impl Enforcer {
let eval_result = self
.engine
.eval_with_scope::<bool>(&mut scope, &expstring)?;
if !eval_result {
policy_effects[i] = EffectKind::Indeterminate;
continue;
}
if let Some(j) = p_ast.tokens.iter().position(|x| x == "p_eft") {
let eft = &pvals[j];
if eft == "allow" {
policy_effects[i] = EffectKind::Allow;
} else if eft == "deny" {
policy_effects[i] = EffectKind::Deny;
let mut eft = if !eval_result {
EffectKind::Indeterminate
} else {
EffectKind::Allow
};
eft = if eft == EffectKind::Indeterminate {
EffectKind::Indeterminate
} else if let Some(j) = p_ast.tokens.iter().position(|x| x == "p_eft") {
let p_eft = &pvals[j];
if p_eft == "allow" {
EffectKind::Allow
} else if p_eft == "deny" {
EffectKind::Deny
} else {
policy_effects[i] = EffectKind::Indeterminate;
EffectKind::Indeterminate
}
} else {
policy_effects[i] = EffectKind::Allow;
}
if e_ast.value == "priority(p_eft) || deny" {
break;
} else if e_ast.value == "some(where (p_eft == allow))"
&& policy_effects[i] == EffectKind::Allow
{
return Ok(true);
} else if policy_effects[i] == EffectKind::Deny
&& (e_ast.value == "!some(where (p_eft == deny))"
|| e_ast.value
== "some(where (p_eft == allow)) && !some(where (p_eft == deny))")
{
return Ok(false);
EffectKind::Allow
};
match eft_stream.push_effect(eft) {
(true, res) => {
return Ok(res);
}
(false, _) => continue,
}
}
} else {
Expand All @@ -212,14 +209,15 @@ impl Enforcer {
let eval_result = self
.engine
.eval_with_scope::<bool>(&mut scope, &m_ast.value)?;
if eval_result {
policy_effects.push(EffectKind::Allow);
let eft = if eval_result {
EffectKind::Allow
} else {
policy_effects.push(EffectKind::Indeterminate);
}
EffectKind::Indeterminate
};
eft_stream.push_effect(eft);
}

Ok(self.eft.merge_effects(&e_ast.value, policy_effects))
Ok(eft_stream.current())
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub use cached_api::CachedApi;
pub use cached_enforcer::CachedEnforcer;
pub use convert::{TryIntoAdapter, TryIntoModel};
pub use core_api::CoreApi;
pub use effector::{DefaultEffector, EffectKind, Effector};
pub use effector::{DefaultEffectStream, DefaultEffector, EffectKind, Effector, EffectorStream};
pub use emitter::{Event, EventData, EventEmitter, EventKey};
pub use enforcer::Enforcer;
pub use error::Error;
Expand Down

1 comment on commit e99cfa3

@GopherJ
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rust Benchmark

Benchmark suite Current: e99cfa3 Previous: 1ed84ea Ratio
b_benchmark_abac_model 7430 ns/iter (± 505) 53309 ns/iter (± 22316) 0.14
b_benchmark_basic_model 7599 ns/iter (± 494) 78163 ns/iter (± 8585) 0.09721991223468905
b_benchmark_key_match 25752 ns/iter (± 1693) 120899 ns/iter (± 9597) 0.21
b_benchmark_priority_model 9230 ns/iter (± 865) 89611 ns/iter (± 11510) 0.10
b_benchmark_raw 8 ns/iter (± 0) 8 ns/iter (± 0) 1
b_benchmark_rbac_model 22119 ns/iter (± 2127) 71003 ns/iter (± 5172) 0.31
b_benchmark_rbac_model_large 66038660 ns/iter (± 3265971) 66814948 ns/iter (± 1921795) 0.99
b_benchmark_rbac_model_medium 6290208 ns/iter (± 822761) 6420130 ns/iter (± 360340) 0.98
b_benchmark_rbac_model_small 634671 ns/iter (± 16311) 683168 ns/iter (± 62901) 0.93
b_benchmark_rbac_model_with_domains 12935 ns/iter (± 1399) 85420 ns/iter (± 17004) 0.15
b_benchmark_rbac_with_deny 37612 ns/iter (± 3101) 79068 ns/iter (± 9563) 0.48
b_benchmark_rbac_with_resource_roles 10113 ns/iter (± 556) 67024 ns/iter (± 14352) 0.15

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.