@@ -2,20 +2,97 @@ use std::{cell::RefCell, time::SystemTime};
22
33use crate :: error:: EngineError ;
44
5- /// Hold information about limitations and constraints of operations execution:
6- /// - max_number_of_states: the maximum number of states that a non-determinitic finite automaton can hold.
7- /// - start_execution_time: timestamp of when the execution has started.
8- /// - execution_timeout: the longest time in milliseconds that an operation execution can last.
9- /// - max_number_of_terms: the maximum number of terms that an operation can have.
5+ /// Hold settings about limitations and constraints of operations execution within the engine.
6+ ///
7+ /// To apply the settings on the current thread you need to call the following function:
8+ /// ```
9+ /// use regexsolver::execution_profile::{ExecutionProfile, ThreadLocalParams};
10+ ///
11+ /// let execution_profile = ExecutionProfile {
12+ /// max_number_of_states: 1,
13+ /// start_execution_time: None,
14+ /// execution_timeout: 1000,
15+ /// max_number_of_terms: 10,
16+ /// };
17+ ///
18+ /// // Store the settings on the current thread.
19+ /// ThreadLocalParams::init_profile(&execution_profile);
20+ /// ```
21+ ///
22+ /// # Examples:
23+ ///
24+ /// ## Limiting the number of states
25+ /// ```
26+ /// use regexsolver::{Term, execution_profile::{ExecutionProfile, ThreadLocalParams}, error::EngineError};
27+ ///
28+ /// let term1 = Term::from_regex(".*abc.*").unwrap();
29+ /// let term2 = Term::from_regex(".*def.*").unwrap();
30+ ///
31+ /// let execution_profile = ExecutionProfile {
32+ /// max_number_of_states: 1,
33+ /// start_execution_time: None,
34+ /// execution_timeout: 1000,
35+ /// max_number_of_terms: 10,
36+ /// };
37+ /// ThreadLocalParams::init_profile(&execution_profile);
38+ ///
39+ /// assert_eq!(EngineError::AutomatonHasTooManyStates, term1.intersection(&[term2]).unwrap_err());
40+ /// ```
41+ ///
42+ /// ## Limiting the number of terms
43+ /// ```
44+ /// use regexsolver::{Term, execution_profile::{ExecutionProfile, ThreadLocalParams}, error::EngineError};
45+ ///
46+ /// let term1 = Term::from_regex(".*abc.*").unwrap();
47+ /// let term2 = Term::from_regex(".*def.*").unwrap();
48+ /// let term3 = Term::from_regex(".*hij.*").unwrap();
49+ ///
50+ /// let execution_profile = ExecutionProfile {
51+ /// max_number_of_states: 8192,
52+ /// start_execution_time: None,
53+ /// execution_timeout: 1000,
54+ /// max_number_of_terms: 2,
55+ /// };
56+ /// ThreadLocalParams::init_profile(&execution_profile);
57+ ///
58+ /// assert_eq!(EngineError::TooMuchTerms(2,3), term1.intersection(&[term2, term3]).unwrap_err());
59+ /// ```
60+ ///
61+ /// ## Limiting the execution time
62+ /// ```
63+ /// use regexsolver::{Term, execution_profile::{ExecutionProfile, ThreadLocalParams}, error::EngineError};
64+ /// use std::time::SystemTime;
65+ ///
66+ /// let term = Term::from_regex(".*abc.*cdef.*sqdsqf.*").unwrap();
67+ ///
68+ /// let execution_profile = ExecutionProfile {
69+ /// max_number_of_states: 8192,
70+ /// start_execution_time: Some(SystemTime::now()),
71+ /// execution_timeout: 1,
72+ /// max_number_of_terms: 50,
73+ /// };
74+ /// ThreadLocalParams::init_profile(&execution_profile);
75+ ///
76+ /// assert_eq!(EngineError::OperationTimeOutError, term.generate_strings(100).unwrap_err());
77+ /// ```
1078pub struct ExecutionProfile {
79+ /// The maximum number of states that a non-determinitic finite automaton can hold, this is checked during the convertion of regular expression to automaton.
1180 pub max_number_of_states : usize ,
81+ /// Timestamp of when the execution has started, if this value is not set the operations will never timeout.
1282 pub start_execution_time : Option < SystemTime > ,
83+ /// The longest time in milliseconds that an operation execution can last, there are no guaranties that the exact time will be respected.
1384 pub execution_timeout : u128 ,
85+ /// The maximum number of terms that an operation can have.
1486 pub max_number_of_terms : usize ,
1587}
1688
1789impl ExecutionProfile {
18- pub fn is_timed_out ( & self ) -> Result < ( ) , EngineError > {
90+ /// Assert that `execution_timeout` is not exceeded.
91+ ///
92+ /// Return empty if `execution_timeout` is not exceeded or if `start_execution_time` is not set.
93+ ///
94+ /// Return [`EngineError::OperationTimeOutError`] otherwise.
95+ pub fn assert_not_timed_out ( & self ) -> Result < ( ) , EngineError > {
1996 if let Some ( start) = self . start_execution_time {
2097 let run_duration = SystemTime :: now ( )
2198 . duration_since ( start)
@@ -33,6 +110,20 @@ impl ExecutionProfile {
33110 }
34111}
35112
113+
114+ /// Hold [`ExecutionProfile`] on the current thread.
115+ ///
116+ /// The default [`ExecutionProfile`] is the following:
117+ /// ```
118+ /// use regexsolver::execution_profile::ExecutionProfile;
119+ ///
120+ /// ExecutionProfile {
121+ /// max_number_of_states: 8192,
122+ /// start_execution_time: None,
123+ /// execution_timeout: 1500,
124+ /// max_number_of_terms: 50,
125+ /// };
126+ /// ```
36127pub struct ThreadLocalParams ;
37128impl ThreadLocalParams {
38129 thread_local ! {
@@ -42,7 +133,7 @@ impl ThreadLocalParams {
42133 static MAX_NUMBER_OF_TERMS : RefCell <usize > = const { RefCell :: new( 50 ) } ;
43134 }
44135
45- /// Initialize the thread local holding the ExecutionProfile.
136+ /// Store on the current thread [` ExecutionProfile`] .
46137 pub fn init_profile ( profile : & ExecutionProfile ) {
47138 ThreadLocalParams :: MAX_NUMBER_OF_STATES . with ( |cell| {
48139 * cell. borrow_mut ( ) = profile. max_number_of_states ;
@@ -77,6 +168,7 @@ impl ThreadLocalParams {
77168 ThreadLocalParams :: MAX_NUMBER_OF_TERMS . with ( |cell| * cell. borrow ( ) )
78169 }
79170
171+ /// Return the [`ExecutionProfile`] stored on the current thread.
80172 pub fn get_execution_profile ( ) -> ExecutionProfile {
81173 ExecutionProfile {
82174 max_number_of_states : Self :: get_max_number_of_states ( ) ,
0 commit comments