Skip to content

Commit

Permalink
#79 "sober" features
Browse files Browse the repository at this point in the history
  • Loading branch information
yegor256 committed Jan 14, 2023
1 parent 8617c38 commit a8736a3
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 8 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/cargo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- run: cargo test -vv
- run: cargo test -vv -- --nocapture
- run: cargo test --features sober -vv -- --nocapture
- run: cargo fmt --check
- run: cargo clippy
3 changes: 2 additions & 1 deletion .rultor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ release:
[[ "${tag}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || exit -1
sed -i -e "s/^version = \"0.0.0\"/version = \"${tag}\"/" Cargo.toml
sed -i -e "s/0.0.0/${tag}/" src/lib.rs
cargo --color=never test -vv
cargo --color=never test -vv -- --nocapture
cargo --color=never test --features sober -vv -- --nocapture
cargo --color=never fmt --check
cargo clippy
git commit -am "${tag}"
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ homepage = "https://github.com/objectionary/sodg"
keywords = ["graph", "oop"]
categories = ["data-structures", "memory-management"]

[features]
sober = []

[dependencies]
anyhow = "1.0.68"
log = "0.4.17"
Expand Down
5 changes: 5 additions & 0 deletions src/ctors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ use crate::Sodg;
use rstest::rstest;
use std::collections::HashMap;

#[cfg(feature = "sober")]
use std::collections::HashSet;

impl Sodg {
/// Make an empty [`Sodg`], with no vertices and no edges.
pub fn empty() -> Self {
Expand All @@ -30,6 +33,8 @@ impl Sodg {
next_v: 0,
alerts: vec![],
alerts_active: true,
#[cfg(feature = "sober")]
finds: HashSet::new(),
};
g.alert_on(|g, vx| {
let mut errors = Vec::new();
Expand Down
51 changes: 45 additions & 6 deletions src/find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::{Sodg, DeadRelay, LambdaRelay, Relay};
use crate::{DeadRelay, LambdaRelay, Relay, Sodg};
use anyhow::{anyhow, Context, Result};
use log::trace;
use std::collections::VecDeque;
Expand Down Expand Up @@ -97,7 +97,30 @@ impl Sodg {
/// If searching algorithm fails to find the destination,
/// an `Err` will be returned.
pub fn find<T: Relay>(&self, v1: u32, loc: &str, relay: &T) -> Result<u32> {
self.find_with_indent(v1, loc, relay, 0)
#[cfg(feature = "sober")]
let badge = format!("{v1}.{loc}");
#[cfg(feature = "sober")]
{
if self.finds.contains(&badge) {
return Err(anyhow!("Most probably a recursive call to {badge}"));
}
let cp = self as *const Self;
let mp = cp as *mut Self;
unsafe {
(&mut *mp).finds.insert(badge.clone());
}
}
#[allow(clippy::let_and_return)]
let v = self.find_with_indent(v1, loc, relay, 0);
#[cfg(feature = "sober")]
{
let cp = self as *const Self;
let mp = cp as *mut Self;
unsafe {
(&mut *mp).finds.remove(&badge);
}
}
v
}

/// Find a vertex, printing the log with an indentation prefix.
Expand All @@ -110,6 +133,12 @@ impl Sodg {
relay: &T,
depth: usize,
) -> Result<u32> {
#[cfg(feature = "sober")]
{
if depth > 16 {
return Err(anyhow!("The depth {depth} is too big"));
}
}
let mut v = v1;
let mut locator: VecDeque<String> = VecDeque::new();
loc.split('.')
Expand All @@ -119,6 +148,12 @@ impl Sodg {
let mut jumps = 0;
loop {
jumps += 1;
#[cfg(sober)]
{
if jumps > 64 {
return Err(anyhow!("Too many jumps ({jumps})"));
}
}
let next = locator.pop_front();
if next.is_none() {
break;
Expand Down Expand Up @@ -260,29 +295,33 @@ fn relay_modifies_sodg_back() -> Result<()> {
}

#[cfg(test)]
#[cfg(feature = "sober")]
struct RecursiveRelay<'a> {
g: &'a Sodg,
}

#[cfg(test)]
#[cfg(feature = "sober")]
impl<'a> RecursiveRelay<'a> {
pub fn new(g: &'a Sodg) -> RecursiveRelay {
RecursiveRelay { g }
}
}

#[cfg(test)]
#[cfg(feature = "sober")]
impl<'a> Relay for RecursiveRelay<'a> {
fn re(&self, v: u32, a: &str) -> Result<String> {
Ok(format!("ν{}", self.g.find(v, a, self).unwrap()))
Ok(format!("ν{}", self.g.find(v, a, self)?))
}
}

#[test]
#[cfg(feature = "sober")]
fn handles_endless_recursion_gracefully() -> Result<()> {
let g : Sodg = Sodg::empty();
let mut g: Sodg = Sodg::empty();
g.add(0).unwrap();
let r = &g;
assert_eq!(42, g.find(0, "foo", &RecursiveRelay::new(r))?);
assert!(g.find(0, "foo", &RecursiveRelay::new(r)).is_err());
Ok(())
}

5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ pub use crate::hex::Hex;
pub use crate::script::Script;
pub(crate) use crate::vertex::Vertex;

#[cfg(feature = "sober")]
use std::collections::HashSet;

/// A struct that represents a Surging Object DiGraph (SODG).
///
/// You add vertices to it, bind them one to one with edges,
Expand Down Expand Up @@ -95,6 +98,8 @@ pub struct Sodg {
alerts: Vec<Alert>,
#[serde(skip_serializing, skip_deserializing)]
alerts_active: bool,
#[cfg(feature = "sober")]
finds: HashSet<String>,
}

/// A relay that is used by [`Sodg::find()`] when it can't find an attribute.
Expand Down
2 changes: 2 additions & 0 deletions src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ impl Sodg {
next_v: self.next_v,
alerts: self.alerts.clone(),
alerts_active: self.alerts_active,
#[cfg(feature = "sober")]
finds: HashSet::new(),
})
}
}
Expand Down

0 comments on commit a8736a3

Please sign in to comment.