Skip to content

Commit e5047b8

Browse files
committed
Properly sort routes
1 parent acbb42a commit e5047b8

File tree

2 files changed

+108
-32
lines changed

2 files changed

+108
-32
lines changed

src/lib.rs

+70-5
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,46 @@ pub enum Handler {
77
StringHandler(~str)
88
}
99

10-
struct Router {
11-
nfa: NFA,
10+
struct Metadata {
11+
statics: uint,
12+
dynamics: uint,
13+
stars: uint
14+
}
15+
16+
impl Metadata {
17+
pub fn new() -> Metadata {
18+
Metadata{ statics: 0, dynamics: 0, stars: 0 }
19+
}
20+
}
21+
22+
impl TotalOrd for Metadata {
23+
fn cmp(&self, other: &Metadata) -> Ordering {
24+
if self.stars > other.stars {
25+
Less
26+
} else if self.stars < other.stars {
27+
Greater
28+
} else if self.dynamics > other.dynamics {
29+
Less
30+
} else if self.dynamics < other.dynamics {
31+
Greater
32+
} else if self.statics > other.statics {
33+
Less
34+
} else if self.statics < other.statics {
35+
Greater
36+
} else {
37+
Equal
38+
}
39+
}
40+
}
41+
42+
impl TotalEq for Metadata {
43+
fn equals(&self, other: &Metadata) -> bool {
44+
self.statics == other.statics && self.dynamics == other.dynamics && self.stars == other.stars
45+
}
46+
}
47+
48+
pub struct Router {
49+
nfa: NFA<Metadata>,
1250
handlers: HashMap<uint, Handler>
1351
}
1452

@@ -24,18 +62,22 @@ impl Router {
2462

2563
let nfa = &mut self.nfa;
2664
let mut state = 0;
65+
let mut metadata = Metadata::new();
2766

2867
for (i, segment) in route.split('/').enumerate() {
2968
if i > 0 { state = nfa.put(state, CharacterClass::valid_char('/')); }
3069

3170
if segment.char_at(0) == ':' {
3271
state = process_dynamic_segment(nfa, state);
72+
metadata.dynamics += 1;
3373
} else {
3474
state = process_static_segment(segment, nfa, state);
75+
metadata.statics += 1;
3576
}
3677
}
3778

3879
nfa.acceptance(state);
80+
nfa.metadata(state, metadata);
3981
self.handlers.insert(state, dest);
4082
}
4183

@@ -48,20 +90,23 @@ impl Router {
4890

4991
match states {
5092
Err(str) => Err(str),
51-
Ok(states) => Ok(self.handlers.get(&states[0]))
93+
Ok(mut states) => {
94+
states.sort_by(|a, b| a.metadata.get_ref().cmp(b.metadata.get_ref()));
95+
Ok(self.handlers.get(&states.last().index))
96+
}
5297
}
5398
}
5499
}
55100

56-
fn process_static_segment(segment: &str, nfa: &mut NFA, mut state: uint) -> uint {
101+
fn process_static_segment<T>(segment: &str, nfa: &mut NFA<T>, mut state: uint) -> uint {
57102
for char in segment.chars() {
58103
state = nfa.put(state, CharacterClass::valid_char(char));
59104
}
60105

61106
state
62107
}
63108

64-
fn process_dynamic_segment(nfa: &mut NFA, mut state: uint) -> uint {
109+
fn process_dynamic_segment<T>(nfa: &mut NFA<T>, mut state: uint) -> uint {
65110
state = nfa.put(state, CharacterClass::invalid_char('/'));
66111
nfa.put_state(state, state);
67112

@@ -91,4 +136,24 @@ fn ambiguous_router() {
91136
match *router.recognize("/posts/1").unwrap() {
92137
StringHandler(ref str) => assert!(str == &~"id", "/posts/1 matched")
93138
}
139+
140+
match *router.recognize("/posts/new").unwrap() {
141+
StringHandler(ref str) => assert!(str == &~"new", "/posts/new matched")
142+
}
143+
}
144+
145+
#[test]
146+
fn ambiguous_router_b() {
147+
let mut router = Router::new();
148+
149+
router.add("/posts/:id", StringHandler(~"id"));
150+
router.add("/posts/new", StringHandler(~"new"));
151+
152+
match *router.recognize("/posts/1").unwrap() {
153+
StringHandler(ref str) => assert!(str == &~"id", "/posts/1 matched")
154+
}
155+
156+
match *router.recognize("/posts/new").unwrap() {
157+
StringHandler(ref str) => assert!(str == &~"new", "/posts/new matched")
158+
}
94159
}

src/nfa.rs

+38-27
Original file line numberDiff line numberDiff line change
@@ -38,30 +38,37 @@ impl CharacterClass {
3838
}
3939
}
4040

41-
struct State {
41+
struct State<T> {
4242
index: uint,
4343
chars: CharacterClass,
4444
next_states: ~[uint],
45-
acceptance: bool
45+
acceptance: bool,
46+
metadata: Option<T>
4647
}
4748

48-
impl State {
49-
pub fn new(index: uint, chars: CharacterClass) -> State {
50-
State{ index: index, chars: chars, next_states: ~[], acceptance: false }
49+
impl<T> Eq for State<T> {
50+
fn eq(&self, other: &State<T>) -> bool {
51+
self.index == other.index
5152
}
5253
}
5354

54-
pub struct NFA {
55-
states: ~[State]
55+
impl<T> State<T> {
56+
pub fn new(index: uint, chars: CharacterClass) -> State<T> {
57+
State{ index: index, chars: chars, next_states: ~[], acceptance: false, metadata: None }
58+
}
59+
}
60+
61+
pub struct NFA<T> {
62+
states: ~[State<T>]
5663
}
5764

58-
impl NFA {
59-
pub fn new() -> NFA {
65+
impl<T> NFA<T> {
66+
pub fn new() -> NFA<T> {
6067
let root = State::new(0, CharacterClass::valid(""));
6168
NFA{ states: ~[root] }
6269
}
6370

64-
pub fn process<'a>(&'a self, string: &str) -> Result<~[uint], ~str> {
71+
pub fn process<'a>(&'a self, string: &str) -> Result<~[&'a State<T>], ~str> {
6572
let mut current = ~[self.get(0)];
6673

6774
for char in string.chars() {
@@ -75,7 +82,7 @@ impl NFA {
7582
}
7683

7784
let returned = current.iter().filter_map(|&state| {
78-
if state.acceptance { Some(state.index) } else { None }
85+
if state.acceptance { Some(state) } else { None }
7986
}).to_owned_vec();
8087

8188
if returned.is_empty() {
@@ -85,7 +92,7 @@ impl NFA {
8592
}
8693
}
8794

88-
fn process_char<'a>(&'a self, states: ~[&State], char: &char) -> ~[&'a State] {
95+
fn process_char<'a>(&'a self, states: ~[&State<T>], char: &char) -> ~[&'a State<T>] {
8996
let mut returned = ~[];
9097

9198
for state in states.iter() {
@@ -101,11 +108,11 @@ impl NFA {
101108
returned
102109
}
103110

104-
pub fn get<'a>(&'a self, state: uint) -> &'a State {
111+
pub fn get<'a>(&'a self, state: uint) -> &'a State<T> {
105112
&self.states[state]
106113
}
107114

108-
pub fn get_mut<'a>(&'a mut self, state: uint) -> &'a mut State {
115+
pub fn get_mut<'a>(&'a mut self, state: uint) -> &'a mut State<T> {
109116
&mut self.states[state]
110117
}
111118

@@ -134,6 +141,10 @@ impl NFA {
134141
self.get_mut(index).acceptance = true;
135142
}
136143

144+
pub fn metadata(&mut self, index: uint, metadata: T) {
145+
self.get_mut(index).metadata = Some(metadata);
146+
}
147+
137148
fn new_state(&mut self, chars: CharacterClass) -> uint {
138149
let index = self.states.len();
139150
let state = State::new(index, chars);
@@ -144,7 +155,7 @@ impl NFA {
144155

145156
#[test]
146157
fn basic_test() {
147-
let mut nfa = NFA::new();
158+
let mut nfa = NFA::<()>::new();
148159
let a = nfa.put(0, CharacterClass::valid("h"));
149160
let b = nfa.put(a, CharacterClass::valid("e"));
150161
let c = nfa.put(b, CharacterClass::valid("l"));
@@ -154,12 +165,12 @@ fn basic_test() {
154165

155166
let states = nfa.process("hello");
156167

157-
assert!(states.unwrap() == ~[e], "You didn't get the right final state");
168+
assert!(states.unwrap() == ~[nfa.get(e)], "You didn't get the right final state");
158169
}
159170

160171
#[test]
161172
fn multiple_solutions() {
162-
let mut nfa = NFA::new();
173+
let mut nfa = NFA::<()>::new();
163174
let a1 = nfa.put(0, CharacterClass::valid("n"));
164175
let b1 = nfa.put(a1, CharacterClass::valid("e"));
165176
let c1 = nfa.put(b1, CharacterClass::valid("w"));
@@ -172,12 +183,12 @@ fn multiple_solutions() {
172183

173184
let states = nfa.process("new");
174185

175-
assert!(states.unwrap() == ~[c1, c2], "The two states were not found");
186+
assert!(states.unwrap() == ~[nfa.get(c1), nfa.get(c2)], "The two states were not found");
176187
}
177188

178189
#[test]
179190
fn multiple_paths() {
180-
let mut nfa = NFA::new();
191+
let mut nfa = NFA::<()>::new();
181192
let a = nfa.put(0, CharacterClass::valid("t")); // t
182193
let b1 = nfa.put(a, CharacterClass::valid("h")); // th
183194
let c1 = nfa.put(b1, CharacterClass::valid("o")); // tho
@@ -196,15 +207,15 @@ fn multiple_paths() {
196207
let thom = nfa.process("thom");
197208
let nope = nfa.process("nope");
198209

199-
assert!(thomas.unwrap() == ~[f1], "thomas was parsed correctly");
200-
assert!(tom.unwrap() == ~[c2], "tom was parsed correctly");
210+
assert!(thomas.unwrap() == ~[nfa.get(f1)], "thomas was parsed correctly");
211+
assert!(tom.unwrap() == ~[nfa.get(c2)], "tom was parsed correctly");
201212
assert!(thom.is_err(), "thom didn't reach an acceptance state");
202213
assert!(nope.is_err(), "nope wasn't parsed");
203214
}
204215

205216
#[test]
206217
fn repetitions() {
207-
let mut nfa = NFA::new();
218+
let mut nfa = NFA::<()>::new();
208219
let a = nfa.put(0, CharacterClass::valid("p")); // p
209220
let b = nfa.put(a, CharacterClass::valid("o")); // po
210221
let c = nfa.put(b, CharacterClass::valid("s")); // pos
@@ -220,14 +231,14 @@ fn repetitions() {
220231
let new_post = nfa.process("posts/new");
221232
let invalid = nfa.process("posts/");
222233

223-
assert!(post.unwrap() == ~[g], "posts/1 was parsed");
224-
assert!(new_post.unwrap() == ~[g], "posts/new was parsed");
234+
assert!(post.unwrap() == ~[nfa.get(g)], "posts/1 was parsed");
235+
assert!(new_post.unwrap() == ~[nfa.get(g)], "posts/new was parsed");
225236
assert!(invalid.is_err(), "posts/ was invalid");
226237
}
227238

228239
#[test]
229240
fn repetitions_with_ambiguous() {
230-
let mut nfa = NFA::new();
241+
let mut nfa = NFA::<()>::new();
231242
let a = nfa.put(0, CharacterClass::valid("p")); // p
232243
let b = nfa.put(a, CharacterClass::valid("o")); // po
233244
let c = nfa.put(b, CharacterClass::valid("s")); // pos
@@ -248,7 +259,7 @@ fn repetitions_with_ambiguous() {
248259
let ambiguous = nfa.process("posts/new");
249260
let invalid = nfa.process("posts/");
250261

251-
assert!(post.unwrap() == ~[g1], "posts/1 was parsed");
252-
assert!(ambiguous.unwrap() == ~[g1, i2], "posts/new was ambiguous");
262+
assert!(post.unwrap() == ~[nfa.get(g1)], "posts/1 was parsed");
263+
assert!(ambiguous.unwrap() == ~[nfa.get(g1), nfa.get(i2)], "posts/new was ambiguous");
253264
assert!(invalid.is_err(), "posts/ was invalid");
254265
}

0 commit comments

Comments
 (0)