Graph

Struct Graph 

Source
pub struct Graph {
    pub def: GraphDef,
    pub context: Context,
}

Fields§

§def: GraphDef§context: Context

Implementations§

Source§

impl Graph

Source

pub fn new(def: GraphDef) -> Self

Examples found in repository?
examples/parallel_execution.rs (line 308)
290async fn analyze_and_execute(def: GraphDef) -> anyhow::Result<()> {
291    // Create parallel executor
292    let mut executor = ParallelExecutor::new(ParallelConfig {
293        max_concurrent: 10,
294        verbose: true,
295    });
296
297    // Register nodes
298    for node_id in def.nodes.keys() {
299        let node: Box<dyn Node> = Box::new(RuleNode::new(node_id, "true"));
300        executor.register_node(node);
301    }
302
303    // Analyze parallelism
304    let stats = executor.get_parallelism_stats(&def)?;
305    stats.print_summary();
306
307    // Execute the graph
308    let mut graph = Graph::new(def);
309    let start = Instant::now();
310    executor.execute(&mut graph).await?;
311    let duration = start.elapsed();
312
313    println!("Execution completed in {:?}", duration);
314
315    Ok(())
316}
More examples
Hide additional examples
examples/simple_flow.rs (line 22)
6async fn main() -> anyhow::Result<()> {
7    // Initialize tracing
8    tracing_subscriber::fmt()
9        .with_max_level(tracing::Level::INFO)
10        .init();
11
12    println!("=== Rust Logic Graph - Simple Flow Example ===\n");
13
14    // Load graph definition from JSON
15    let def = GraphIO::load_from_file("examples/simple_flow.json")?;
16    println!("Loaded graph with {} nodes and {} edges\n",
17        def.nodes.len(),
18        def.edges.len()
19    );
20
21    // Create graph
22    let mut graph = Graph::new(def);
23
24    // Execute the graph
25    println!("Starting graph execution...\n");
26    Orchestrator::execute_graph(&mut graph).await?;
27
28    // Display final context
29    println!("\n=== Final Context ===");
30    for (key, value) in &graph.context.data {
31        println!("{}: {}", key, value);
32    }
33
34    println!("\n=== Execution Complete ===");
35    Ok(())
36}
examples/advanced_flow.rs (line 53)
6async fn main() -> anyhow::Result<()> {
7    // Initialize tracing
8    tracing_subscriber::fmt()
9        .with_max_level(tracing::Level::DEBUG)
10        .init();
11
12    println!("=== Rust Logic Graph - Advanced Flow Example ===");
13    println!("Scenario: User Analytics Report Generation with Permission Checks\n");
14
15    // Load graph definition
16    let def = GraphIO::load_from_file("examples/advanced_flow.json")?;
17
18    // Create custom executor with specific node configurations
19    let mut executor = Executor::new();
20
21    // Register nodes with custom logic
22    executor.register_node(Box::new(RuleNode::new(
23        "validate_input",
24        "user_id > 0"
25    )));
26
27    executor.register_node(Box::new(DBNode::new(
28        "fetch_user_data",
29        "SELECT * FROM users WHERE id = ?"
30    )));
31
32    executor.register_node(Box::new(RuleNode::new(
33        "check_permissions",
34        "user_role == \"admin\""
35    )));
36
37    executor.register_node(Box::new(DBNode::new(
38        "query_analytics",
39        "SELECT * FROM analytics WHERE user_id = ?"
40    )));
41
42    executor.register_node(Box::new(AINode::new(
43        "generate_report",
44        "Generate comprehensive analytics report from data"
45    )));
46
47    executor.register_node(Box::new(AINode::new(
48        "send_notification",
49        "Send notification to user about report status"
50    )));
51
52    // Create graph and set initial context
53    let mut graph = Graph::new(def);
54
55    // Simulate input data
56    graph.context.data.insert("user_id".to_string(), json!(1001));
57    graph.context.data.insert("user_role".to_string(), json!("admin"));
58
59    println!("Initial Context:");
60    println!("  - user_id: 1001");
61    println!("  - user_role: admin\n");
62
63    // Execute the graph
64    println!("Starting advanced flow execution...\n");
65    executor.execute(&mut graph).await?;
66
67    // Display results
68    println!("\n=== Execution Results ===");
69    println!("\nContext Data:");
70    for (key, value) in &graph.context.data {
71        if key.ends_with("_result") {
72            println!("  {}: {}", key, serde_json::to_string_pretty(&value)?);
73        }
74    }
75
76    println!("\n=== Flow Complete ===");
77    Ok(())
78}
examples/cache_flow.rs (line 114)
84async fn demo_basic_caching() -> anyhow::Result<()> {
85    println!("\n=== Demo 1: Basic Caching ===\n");
86
87    // Create cache with default configuration
88    let cache_config = CacheConfig {
89        max_entries: 100,
90        max_memory_bytes: 10 * 1024 * 1024, // 10MB
91        default_ttl: None,                   // No expiration
92        eviction_policy: EvictionPolicy::LRU,
93        enable_background_cleanup: false,
94    };
95
96    let cache = CacheManager::new(cache_config).await?;
97
98    // Create executor with cache
99    let mut executor = Executor::with_cache(cache.clone());
100
101    // Register expensive computation node
102    executor.register_node(Box::new(ExpensiveComputeNode::new("compute", 1000)));
103
104    // Create simple graph
105    let graph_def = GraphDef {
106        nodes: vec![("compute".to_string(), NodeType::RuleNode)]
107            .into_iter()
108            .collect(),
109        edges: vec![],
110    };
111
112    // First execution - cache miss
113    info!("First execution (cache miss):");
114    let mut graph1 = Graph::new(graph_def.clone());
115    graph1.context.set("input", json!(5))?;
116
117    let start = std::time::Instant::now();
118    executor.execute(&mut graph1).await?;
119    let duration1 = start.elapsed();
120
121    println!("First execution time: {:?}", duration1);
122    println!("Cache stats: {:?}", cache.stats());
123
124    // Second execution - cache hit
125    info!("\nSecond execution (cache hit):");
126    let mut graph2 = Graph::new(graph_def.clone());
127    graph2.context.set("input", json!(5))?; // Same input
128
129    let start = std::time::Instant::now();
130    executor.execute(&mut graph2).await?;
131    let duration2 = start.elapsed();
132
133    println!("Second execution time: {:?}", duration2);
134    println!("Cache stats: {:?}", cache.stats());
135    println!("Speedup: {:.2}x", duration1.as_secs_f64() / duration2.as_secs_f64());
136
137    // Third execution with different input - cache miss
138    info!("\nThird execution with different input (cache miss):");
139    let mut graph3 = Graph::new(graph_def);
140    graph3.context.set("input", json!(10))?; // Different input
141
142    let start = std::time::Instant::now();
143    executor.execute(&mut graph3).await?;
144    let duration3 = start.elapsed();
145
146    println!("Third execution time: {:?}", duration3);
147    println!("Final cache stats: {:?}", cache.stats());
148    println!("Hit rate: {:.1}%", cache.stats().hit_rate());
149
150    Ok(())
151}
152
153async fn demo_ttl_expiration() -> anyhow::Result<()> {
154    println!("\n\n=== Demo 2: TTL Expiration ===\n");
155
156    // Create cache with short TTL
157    let cache_config = CacheConfig {
158        max_entries: 100,
159        max_memory_bytes: 10 * 1024 * 1024,
160        default_ttl: Some(Duration::from_secs(2)), // 2 second TTL
161        eviction_policy: EvictionPolicy::LRU,
162        enable_background_cleanup: true,
163    };
164
165    let cache = CacheManager::new(cache_config).await?;
166    let mut executor = Executor::with_cache(cache.clone());
167    executor.register_node(Box::new(ExpensiveComputeNode::new("compute", 500)));
168
169    let graph_def = GraphDef {
170        nodes: vec![("compute".to_string(), NodeType::RuleNode)]
171            .into_iter()
172            .collect(),
173        edges: vec![],
174    };
175
176    // First execution
177    info!("First execution:");
178    let mut graph1 = Graph::new(graph_def.clone());
179    graph1.context.set("input", json!(7))?;
180    executor.execute(&mut graph1).await?;
181    println!("Cache stats after first execution: {:?}", cache.stats());
182
183    // Immediate second execution - should hit cache
184    info!("\nImmediate second execution (within TTL):");
185    let mut graph2 = Graph::new(graph_def.clone());
186    graph2.context.set("input", json!(7))?;
187    executor.execute(&mut graph2).await?;
188    println!("Cache stats: {:?}", cache.stats());
189
190    // Wait for TTL to expire
191    println!("\nWaiting for TTL to expire (3 seconds)...");
192    tokio::time::sleep(Duration::from_secs(3)).await;
193
194    // Third execution after TTL - should miss cache
195    info!("\nThird execution (after TTL expiration):");
196    let mut graph3 = Graph::new(graph_def);
197    graph3.context.set("input", json!(7))?;
198    executor.execute(&mut graph3).await?;
199    println!("Cache stats after expiration: {:?}", cache.stats());
200
201    Ok(())
202}
203
204async fn demo_eviction_policies() -> anyhow::Result<()> {
205    println!("\n\n=== Demo 3: Eviction Policies ===\n");
206
207    for policy in [EvictionPolicy::LRU, EvictionPolicy::FIFO, EvictionPolicy::LFU] {
208        println!("\n--- Testing {:?} Policy ---", policy);
209
210        let cache_config = CacheConfig {
211            max_entries: 3, // Small limit to trigger eviction
212            max_memory_bytes: 10 * 1024 * 1024,
213            default_ttl: None,
214            eviction_policy: policy,
215            enable_background_cleanup: false,
216        };
217
218        let cache = CacheManager::new(cache_config).await?;
219        let mut executor = Executor::with_cache(cache.clone());
220        executor.register_node(Box::new(ExpensiveComputeNode::new("compute", 100)));
221
222        let graph_def = GraphDef {
223            nodes: vec![("compute".to_string(), NodeType::RuleNode)]
224                .into_iter()
225                .collect(),
226            edges: vec![],
227        };
228
229        // Add 4 entries (should evict 1)
230        for i in 1..=4 {
231            let mut graph = Graph::new(graph_def.clone());
232            graph.context.set("input", json!(i))?;
233            executor.execute(&mut graph).await?;
234            println!("Added entry {}, cache size: {}", i, cache.len());
235        }
236
237        let stats = cache.stats();
238        println!("Final stats: entries={}, evictions={}", 
239                 stats.current_entries, stats.evictions);
240    }
241
242    Ok(())
243}
244
245async fn demo_memory_limits() -> anyhow::Result<()> {
246    println!("\n\n=== Demo 4: Memory Limits ===\n");
247
248    // Create cache with small memory limit
249    let cache_config = CacheConfig {
250        max_entries: 1000,
251        max_memory_bytes: 1024, // Only 1KB
252        default_ttl: None,
253        eviction_policy: EvictionPolicy::LRU,
254        enable_background_cleanup: false,
255    };
256
257    let cache = CacheManager::new(cache_config).await?;
258    let mut executor = Executor::with_cache(cache.clone());
259    executor.register_node(Box::new(ExpensiveComputeNode::new("compute", 50)));
260
261    let graph_def = GraphDef {
262        nodes: vec![("compute".to_string(), NodeType::RuleNode)]
263            .into_iter()
264            .collect(),
265        edges: vec![],
266    };
267
268    // Add entries until memory limit is reached
269    for i in 1..=20 {
270        let mut graph = Graph::new(graph_def.clone());
271        graph.context.set("input", json!(i))?;
272        graph.context.set("large_data", json!(vec![i; 100]))?; // Add some bulk
273        executor.execute(&mut graph).await?;
274
275        let stats = cache.stats();
276        println!(
277            "Entry {}: size={} entries, memory={} bytes, evictions={}",
278            i, stats.current_entries, stats.current_memory_bytes, stats.evictions
279        );
280    }
281
282    let stats = cache.stats();
283    println!("\nFinal memory usage: {} bytes (limit: 1024 bytes)", 
284             stats.current_memory_bytes);
285    println!("Total evictions: {}", stats.evictions);
286
287    Ok(())
288}
289
290async fn demo_cache_invalidation() -> anyhow::Result<()> {
291    println!("\n\n=== Demo 5: Cache Invalidation ===\n");
292
293    let cache = CacheManager::new(CacheConfig::default()).await?;
294    let mut executor = Executor::with_cache(cache.clone());
295    executor.register_node(Box::new(ExpensiveComputeNode::new("compute", 200)));
296
297    let graph_def = GraphDef {
298        nodes: vec![("compute".to_string(), NodeType::RuleNode)]
299            .into_iter()
300            .collect(),
301        edges: vec![],
302    };
303
304    // Execute multiple times with different inputs
305    for i in 1..=5 {
306        let mut graph = Graph::new(graph_def.clone());
307        graph.context.set("input", json!(i))?;
308        executor.execute(&mut graph).await?;
309    }
310
311    println!("Cache populated with {} entries", cache.len());
312    println!("Cache stats: {:?}", cache.stats());
313
314    // Invalidate specific node
315    println!("\nInvalidating all entries for node 'compute'...");
316    let invalidated = cache.invalidate_node("compute");
317    println!("Invalidated {} entries", invalidated);
318    println!("Cache size after invalidation: {}", cache.len());
319
320    // Re-execute - should be cache miss
321    info!("\nRe-executing after invalidation:");
322    let mut graph = Graph::new(graph_def);
323    graph.context.set("input", json!(1))?;
324    executor.execute(&mut graph).await?;
325    println!("Final cache stats: {:?}", cache.stats());
326
327    Ok(())
328}
examples/grl_graph_flow.rs (line 58)
6async fn main() -> anyhow::Result<()> {
7    // Initialize tracing
8    tracing_subscriber::fmt()
9        .with_max_level(tracing::Level::INFO)
10        .init();
11
12    println!("=== Rust Logic Graph - GRL Integration Example ===");
13    println!("Scenario: Loan Application with Advanced GRL Rules\n");
14
15    // Load graph definition
16    let def = GraphIO::load_from_file("examples/grl_graph_flow.json")?;
17
18    // Create custom executor with GRL-powered nodes
19    let mut executor = Executor::new();
20
21    // Input validation with GRL
22    executor.register_node(Box::new(RuleNode::new(
23        "input_validation",
24        "loan_amount > 0 && loan_amount <= 1000000"
25    )));
26
27    // Fetch customer data
28    executor.register_node(Box::new(DBNode::new(
29        "fetch_customer",
30        "SELECT * FROM customers WHERE id = ?"
31    )));
32
33    // Risk assessment with complex GRL rules
34    executor.register_node(Box::new(RuleNode::new(
35        "risk_assessment",
36        "credit_score >= 600 && income >= loan_amount * 3"
37    )));
38
39    // Fraud detection AI
40    executor.register_node(Box::new(AINode::new(
41        "fraud_detection",
42        "Analyze transaction patterns for fraud indicators"
43    )));
44
45    // Final approval decision
46    executor.register_node(Box::new(RuleNode::new(
47        "approval_decision",
48        "risk_score < 50 && fraud_score < 30"
49    )));
50
51    // Notification
52    executor.register_node(Box::new(AINode::new(
53        "notification",
54        "Generate approval/rejection notification email"
55    )));
56
57    // Create graph with initial context
58    let mut graph = Graph::new(def);
59
60    // Set application data
61    graph.context.data.insert("loan_amount".to_string(), json!(50000));
62    graph.context.data.insert("credit_score".to_string(), json!(720));
63    graph.context.data.insert("income".to_string(), json!(180000));
64    graph.context.data.insert("customer_id".to_string(), json!(12345));
65
66    println!("Application Data:");
67    println!("  Loan Amount: $50,000");
68    println!("  Credit Score: 720");
69    println!("  Annual Income: $180,000");
70    println!("  Customer ID: 12345\n");
71
72    // Execute the graph
73    println!("Processing loan application through GRL-powered workflow...\n");
74    executor.execute(&mut graph).await?;
75
76    // Display results
77    println!("\n=== Application Results ===\n");
78
79    if let Some(validation) = graph.context.data.get("input_validation_result") {
80        println!("✓ Input Validation: {}", validation);
81    }
82
83    if let Some(customer) = graph.context.data.get("fetch_customer_result") {
84        println!("✓ Customer Data Retrieved");
85    }
86
87    if let Some(risk) = graph.context.data.get("risk_assessment_result") {
88        println!("✓ Risk Assessment: {}", risk);
89    }
90
91    if let Some(fraud) = graph.context.data.get("fraud_detection_result") {
92        println!("✓ Fraud Detection Completed");
93    }
94
95    if let Some(decision) = graph.context.data.get("approval_decision_result") {
96        println!("✓ Approval Decision: {}", decision);
97    }
98
99    println!("\n=== GRL-Powered Workflow Complete ===");
100
101    // Demonstrate standalone GRL engine
102    println!("\n=== Bonus: Advanced GRL Rules ===\n");
103
104    let mut grl_engine = RuleEngine::new();
105
106    let advanced_rules = r#"
107rule "HighValueLoan" salience 100 {
108    when
109        loan_amount > 100000 && credit_score < 750
110    then
111        requires_manual_review = true;
112        approval_tier = "senior";
113}
114
115rule "StandardApproval" salience 50 {
116    when
117        loan_amount <= 100000 && credit_score >= 650
118    then
119        auto_approve = true;
120        approval_tier = "standard";
121}
122
123rule "RiskMitigation" salience 25 {
124    when
125        debt_to_income_ratio > 0.4
126    then
127        requires_collateral = true;
128        interest_rate_adjustment = 1.5;
129}
130"#;
131
132    grl_engine.add_grl_rule(advanced_rules)?;
133
134    println!("Advanced GRL rules loaded:");
135    println!("  - High Value Loan Review");
136    println!("  - Standard Approval Process");
137    println!("  - Risk Mitigation Measures");
138
139    println!("\n✅ All systems operational with rust-rule-engine integration!");
140
141    Ok(())
142}

Auto Trait Implementations§

§

impl Freeze for Graph

§

impl RefUnwindSafe for Graph

§

impl Send for Graph

§

impl Sync for Graph

§

impl Unpin for Graph

§

impl UnwindSafe for Graph

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more