typestate_automata/
lib.rs

1use std::{
2    collections::{HashMap, HashSet, VecDeque},
3    hash::Hash,
4};
5
6/// Type alias for the transition "minigraph".
7type Deltas<State, Transition> = HashMap<State, HashMap<Transition, HashSet<State>>>;
8
9/// Delta kind enumeration.
10/// Distinguishes between `Delta` (forward transitions) and
11/// `IDelta` (backward transitions) which are the inverse of `Delta`.
12enum Delta {
13    Delta,
14    IDelta,
15}
16
17/// Type alias for [`DeterministicFiniteAutomata`].
18pub type Dfa<State, Transition> = DeterministicFiniteAutomata<State, Transition>;
19
20/// A representation for a deterministic finite automata.
21#[derive(Debug, Clone)]
22pub struct DeterministicFiniteAutomata<State, Transition>
23where
24    State: Eq + Hash + Clone,
25    Transition: Eq + Hash + Clone,
26{
27    /// Deterministic finite automata states.
28    pub states: HashSet<State>,
29    /// Deterministic finite automata transition symbols.
30    sigma: HashSet<Transition>,
31    /// Deterministic finite automata initial state-indexes.
32    pub initial_states: HashMap<State, HashSet<Transition>>,
33    /// Deterministic finite automata final state-indexes.
34    pub final_states: HashMap<State, HashSet<Transition>>,
35    /// Deterministic finite automata transition functions.
36    /// Map of state indexes to map of transitions to state indexes.
37    delta: HashMap<State, HashMap<Transition, State>>,
38    /// The inverse paths of delta.
39    /// This structure helps algorithms requiring interation in the "inverse" order.
40    idelta: HashMap<State, HashMap<Transition, State>>,
41}
42
43impl<State, Transition> DeterministicFiniteAutomata<State, Transition>
44where
45    State: Eq + Hash + Clone,
46    Transition: Eq + Hash + Clone,
47{
48    /// Construct a new deterministic finite automata.
49    #[must_use]
50    pub fn new() -> Self {
51        Self {
52            states: HashSet::new(),
53            sigma: HashSet::new(),
54            initial_states: HashMap::new(),
55            final_states: HashMap::new(),
56            delta: HashMap::new(),
57            idelta: HashMap::new(),
58        }
59    }
60
61    /// Add a state to the automata.
62    pub fn add_state(&mut self, state: State) {
63        self.states.insert(state);
64    }
65
66    /// Add an initial state to the automata.
67    pub fn add_initial(&mut self, state: State, symbol: Transition) {
68        self.states.insert(state.clone());
69        if let Some(symbols) = self.initial_states.get_mut(&state) {
70            symbols.insert(symbol);
71        } else {
72            let mut symbols = HashSet::new();
73            symbols.insert(symbol);
74            self.initial_states.insert(state, symbols);
75        }
76    }
77
78    /// Add a final state to the automata.
79    pub fn add_final(&mut self, state: State, symbol: Transition) {
80        self.states.insert(state.clone());
81        if let Some(symbols) = self.final_states.get_mut(&state) {
82            symbols.insert(symbol);
83        } else {
84            let mut symbols = HashSet::new();
85            symbols.insert(symbol);
86            self.final_states.insert(state, symbols);
87        }
88    }
89
90    /// Add a new symbol to the automata alphabet.
91    pub fn add_sigma(&mut self, sigma: Transition) {
92        self.sigma.insert(sigma);
93    }
94
95    fn add_delta(&mut self, source: State, symbol: Transition, destination: State, delta: &Delta) {
96        let delta = match delta {
97            Delta::Delta => &mut self.delta,
98            Delta::IDelta => &mut self.idelta,
99        };
100        if let Some(transitions) = delta.get_mut(&source) {
101            if transitions.get_mut(&symbol).is_some() {
102                // TODO duplicate: return error or replace?
103            } else {
104                transitions.insert(symbol, destination);
105            }
106        } else {
107            let mut transitions = HashMap::new();
108            transitions.insert(symbol, destination);
109            delta.insert(source, transitions);
110        }
111    }
112
113    // Add a transition from `source` to `destination`, consuming `symbol`.
114    pub fn add_transition(&mut self, source: State, symbol: Transition, destination: State) {
115        // TODO check for state existence or add regardless
116        self.add_sigma(symbol.clone());
117        self.add_delta(
118            source.clone(),
119            symbol.clone(),
120            destination.clone(),
121            &Delta::Delta,
122        );
123        self.add_delta(destination, symbol, source, &Delta::IDelta);
124    }
125
126    /// Compute the automata productive states.
127    #[must_use]
128    pub fn productive_states(&self) -> HashSet<State> {
129        let mut stack: VecDeque<_> = self.final_states.keys().collect();
130        // productive == visited
131        let mut productive = HashSet::new();
132        while let Some(state) = stack.pop_back() {
133            if productive.insert(state.clone()) {
134                if let Some(states) = self
135                    .idelta
136                    .get(state)
137                    .map(std::collections::HashMap::values)
138                {
139                    stack.extend(states)
140                }
141            }
142        }
143        productive
144    }
145
146    /// Compute the automata non-productive states.
147    ///
148    /// This is done by calling [`DeterministicFiniteAutomata::productive_states`] and performing a diference against the full state set.
149    #[must_use]
150    pub fn non_productive_states(&self) -> HashSet<State> {
151        // TODO check if the clone should be here or if we can return `HashSet<&State>`
152        self.states
153            .difference(&self.productive_states())
154            .cloned()
155            .collect()
156    }
157
158    /// Compute the automata useful states.
159    #[must_use]
160    pub fn useful_states(&self) -> HashSet<State> {
161        // TODO this could benefit from some "caching" of results on productive
162        let productive = self.productive_states();
163        let mut stack: VecDeque<_> = self.initial_states.keys().collect();
164        // productive == visited
165        let mut reachable = HashSet::new();
166        while let Some(state) = stack.pop_back() {
167            if reachable.insert(state.clone()) {
168                if let Some(states) = self.delta.get(state).map(std::collections::HashMap::values) {
169                    stack.extend(states)
170                }
171            }
172        }
173        productive.intersection(&reachable).cloned().collect()
174    }
175
176    /// Compute the automata non-useful states.
177    ///
178    /// This is done by calling [`DeterministicFiniteAutomata::useful_states`] and performing a diference against the full state set.
179    #[must_use]
180    pub fn non_useful_states(&self) -> HashSet<State> {
181        // TODO check if the clone should be here or if we can return `HashSet<&State>`
182        self.states
183            .difference(&self.useful_states())
184            .cloned()
185            .collect()
186    }
187}
188
189/// Implementation of the [`Default`] trait for a [`DeterministicFiniteAutomata`].
190impl<State, Transition> Default for DeterministicFiniteAutomata<State, Transition>
191where
192    State: Eq + Hash + Clone,
193    Transition: Eq + Hash + Clone,
194{
195    /// This function is equivalent to [`DeterministicFiniteAutomata::new`].
196    fn default() -> Self {
197        Self::new()
198    }
199}
200
201/// Tests for [DeterministicFiniteAutomata].
202#[cfg(test)]
203mod dfa_tests {
204    use super::test_traits::*;
205    use super::*;
206
207    fn setup_automata() -> Dfa<i32, usize> {
208        let mut dfa = Dfa::new();
209        let state_list = [1, 2, 3, 4, 5, 6, 7];
210        for &state in state_list.iter() {
211            dfa.add_state(state);
212        }
213        dfa.add_initial(1, 0);
214        dfa.add_final(7, 0);
215        let transition_list = [
216            (1, 2),
217            (1, 3),
218            (2, 6),
219            (3, 4),
220            (3, 5),
221            (3, 6),
222            (4, 5),
223            (5, 7),
224            (6, 7),
225        ];
226        for (idx, &(src, dst)) in transition_list.iter().enumerate() {
227            dfa.add_transition(src, idx + 1, dst);
228        }
229        dfa
230    }
231
232    fn setup_automata_loop() -> Dfa<i32, ()> {
233        let mut dfa = Dfa::new();
234        dfa.add_initial(1, ());
235        dfa.add_final(2, ());
236        dfa.add_transition(1, (), 2);
237        dfa.add_transition(2, (), 1);
238        dfa
239    }
240
241    #[test]
242    fn test_add_state() {
243        let dfa = setup_automata();
244        let expected_states = vec![1, 2, 3, 4, 5, 6, 7].into_hash_set();
245        let result_states = dfa.states;
246        assert_eq!(expected_states, result_states);
247    }
248
249    #[test]
250    fn test_add_initial_state() {
251        let dfa = setup_automata();
252        let expected_states = vec![1].into_hash_set();
253        let result_states: HashSet<i32> = dfa.initial_states.keys().map(|i| *i).collect();
254        assert_eq!(expected_states, result_states);
255    }
256
257    #[test]
258    fn test_add_final_state() {
259        let dfa = setup_automata();
260        let expected_states = vec![7].into_hash_set();
261        let result_states: HashSet<i32> = dfa.final_states.keys().map(|i| *i).collect();
262        assert_eq!(expected_states, result_states);
263    }
264
265    #[test]
266    fn test_add_transition() {
267        let dfa = setup_automata();
268        let expected_deltas = [
269            (1, 2),
270            (1, 3),
271            (2, 6),
272            (3, 4),
273            (3, 5),
274            (3, 6),
275            (4, 5),
276            (5, 7),
277            (6, 7),
278        ]
279        .iter()
280        .map(|t| t.to_owned())
281        .collect::<HashSet<_>>();
282        let expected_ideltas = expected_deltas
283            .iter()
284            .map(|(fst, snd)| (*snd, *fst))
285            .map(|t| t.to_owned())
286            .collect::<HashSet<_>>();
287        let mut result_deltas = HashSet::new();
288        for (src, transitions) in dfa.delta {
289            for &dst in transitions.values() {
290                result_deltas.insert((src, dst));
291            }
292        }
293        let mut result_ideltas = HashSet::new();
294        for (src, transitions) in dfa.idelta {
295            for &dst in transitions.values() {
296                result_ideltas.insert((src, dst));
297            }
298        }
299        assert_eq!(expected_deltas, result_deltas);
300        assert_eq!(expected_ideltas, result_ideltas);
301    }
302
303    #[test]
304    fn test_productive() {
305        let dfa = setup_automata();
306        let result = dfa.productive_states();
307        let expected = [1, 2, 3, 4, 5, 6, 7]
308            .iter()
309            .map(|i| i.to_owned())
310            .collect::<HashSet<i32>>();
311        assert_eq!(expected, result);
312    }
313
314    #[test]
315    fn test_productive_loop() {
316        let dfa = setup_automata_loop();
317        let result = dfa.productive_states();
318        let expected = [1, 2]
319            .iter()
320            .map(|i| i.to_owned())
321            .collect::<HashSet<i32>>();
322        assert_eq!(expected, result);
323    }
324
325    #[test]
326    fn test_useful() {
327        let dfa = setup_automata();
328        let result = dfa.useful_states();
329        let expected = [1, 2, 3, 4, 5, 6, 7]
330            .iter()
331            .map(|i| i.to_owned())
332            .collect::<HashSet<i32>>();
333        assert_eq!(expected, result);
334    }
335}
336
337/// Type alias for [`NonDeterministicFiniteAutomata`].
338pub type Nfa<State, Transition> = NonDeterministicFiniteAutomata<State, Transition>;
339
340/// A representation for non-deterministic finite automata.
341#[derive(Debug, Clone)]
342pub struct NonDeterministicFiniteAutomata<State, Transition>
343where
344    State: Eq + Hash + Clone,
345    Transition: Eq + Hash + Clone,
346{
347    /// Deterministic finite automata states.
348    pub states: HashSet<State>,
349    /// Deterministic finite automata transition symbols.
350    sigma: HashSet<Transition>,
351    /// Deterministic finite automata initial state-indexes.
352    pub initial_states: HashMap<State, HashSet<Transition>>,
353    /// Deterministic finite automata final state-indexes.
354    pub final_states: HashMap<State, HashSet<Transition>>,
355    /// Deterministic finite automata transition functions.
356    /// Map of state indexes to map of transitions to state indexes.
357    delta: Deltas<State, Transition>,
358    /// The inverse paths of delta.
359    /// This structure helps algorithms requiring interation in the "inverse" order.
360    idelta: Deltas<State, Transition>,
361}
362
363impl<State, Transition> NonDeterministicFiniteAutomata<State, Transition>
364where
365    State: Eq + Hash + Clone,
366    Transition: Eq + Hash + Clone,
367{
368    /// Construct a new non-deterministic finite automata.
369    #[must_use]
370    pub fn new() -> Self {
371        Self {
372            states: HashSet::new(),
373            sigma: HashSet::new(),
374            initial_states: HashMap::new(),
375            final_states: HashMap::new(),
376            delta: HashMap::new(),
377            idelta: HashMap::new(),
378        }
379    }
380
381    /// Add a state to the automata.
382    pub fn add_state(&mut self, state: State) {
383        self.states.insert(state);
384    }
385
386    /// Add an initial state to the automata.
387    pub fn add_initial(&mut self, state: State, symbol: Transition) {
388        self.states.insert(state.clone());
389        if let Some(symbols) = self.initial_states.get_mut(&state) {
390            symbols.insert(symbol);
391        } else {
392            let mut symbols = HashSet::new();
393            symbols.insert(symbol);
394            self.initial_states.insert(state, symbols);
395        }
396    }
397
398    /// Add a final state to the automata.
399    pub fn add_final(&mut self, state: State, symbol: Transition) {
400        self.states.insert(state.clone());
401        if let Some(symbols) = self.final_states.get_mut(&state) {
402            symbols.insert(symbol);
403        } else {
404            let mut symbols = HashSet::new();
405            symbols.insert(symbol);
406            self.final_states.insert(state, symbols);
407        }
408    }
409
410    /// Add a new symbol to the automata alphabet.
411    pub fn add_sigma(&mut self, sigma: Transition) {
412        self.sigma.insert(sigma);
413    }
414
415    fn add_delta(&mut self, source: State, symbol: Transition, destination: State, delta: &Delta) {
416        let delta = match delta {
417            Delta::Delta => &mut self.delta,
418            Delta::IDelta => &mut self.idelta,
419        };
420        if let Some(transitions) = delta.get_mut(&source) {
421            if let Some(destinations) = transitions.get_mut(&symbol) {
422                destinations.insert(destination);
423            } else {
424                let mut destinations = HashSet::new();
425                destinations.insert(destination);
426                transitions.insert(symbol, destinations);
427            }
428        } else {
429            let mut transitions = HashMap::new();
430            let mut destinations = HashSet::new();
431            destinations.insert(destination);
432            transitions.insert(symbol, destinations);
433            delta.insert(source, transitions);
434        }
435    }
436
437    // Add a transition from `source` to `destination`, consuming `symbol`.
438    pub fn add_transition(&mut self, source: State, symbol: Transition, destination: State) {
439        // TODO check for state existence or add regardless
440        self.add_sigma(symbol.clone());
441        self.add_delta(
442            source.clone(),
443            symbol.clone(),
444            destination.clone(),
445            &Delta::Delta,
446        );
447        self.add_delta(destination, symbol, source, &Delta::IDelta);
448    }
449
450    // Add a transition from `source` to `destinations`, consuming `symbol`.
451    pub fn add_non_deterministic_transitions(
452        &mut self,
453        source: &State,
454        symbol: &Transition,
455        destinations: impl Iterator<Item = State>,
456    ) {
457        // TODO check for state existence or add regardless
458        self.add_sigma(symbol.clone());
459        for destination in destinations {
460            self.add_delta(
461                source.clone(),
462                symbol.clone(),
463                destination.clone(),
464                &Delta::Delta,
465            );
466            self.add_delta(
467                destination.clone(),
468                symbol.clone(),
469                source.clone(),
470                &Delta::IDelta,
471            );
472        }
473    }
474
475    /// Compute the automata productive states.
476    #[must_use]
477    pub fn productive_states(&self) -> HashSet<State> {
478        let mut stack: VecDeque<_> = self.final_states.keys().collect();
479        // productive == visited
480        let mut productive = HashSet::new();
481        while let Some(state) = stack.pop_back() {
482            if productive.insert(state.clone()) {
483                if let Some(states) = self.idelta.get(state).map(|transitions| {
484                    transitions
485                        .values()
486                        .flat_map(std::collections::HashSet::iter)
487                }) {
488                    stack.extend(states)
489                }
490            }
491        }
492        productive
493    }
494
495    /// Compute the automata non-productive states.
496    ///
497    /// This is done by calling [`NonDeterministicFiniteAutomata::productive_states`] and performing a diference against the full state set.
498    #[must_use]
499    pub fn non_productive_states(&self) -> HashSet<State> {
500        // TODO check if the clone should be here or if we can return `HashSet<&State>`
501        self.states
502            .difference(&self.productive_states())
503            .cloned()
504            .collect()
505    }
506
507    /// Compute the automata useful states.
508    #[must_use]
509    pub fn useful_states(&self) -> HashSet<State> {
510        // TODO this could benefit from some "caching" of results on productive
511        let productive = self.productive_states();
512        let mut stack: VecDeque<_> = self.initial_states.keys().collect();
513        // productive == visited
514        let mut reachable = HashSet::new();
515        while let Some(state) = stack.pop_back() {
516            if reachable.insert(state.clone()) {
517                if let Some(states) = self.delta.get(state).map(|transitions| {
518                    transitions
519                        .values()
520                        .flat_map(std::collections::HashSet::iter)
521                }) {
522                    stack.extend(states)
523                }
524            }
525        }
526        productive.intersection(&reachable).cloned().collect()
527    }
528
529    /// Compute the automata non-useful states.
530    ///
531    /// This is done by calling [`NonDeterministicFiniteAutomata::useful_states`] and performing a diference against the full state set.
532    #[must_use]
533    pub fn non_useful_states(&self) -> HashSet<State> {
534        // TODO check if the clone should be here or if we can return `HashSet<&State>`
535        self.states
536            .difference(&self.useful_states())
537            .cloned()
538            .collect()
539    }
540}
541
542/// Implementation of the [`Default`] trait for a [`NonDeterministicFiniteAutomata`].
543impl<State, Transition> Default for NonDeterministicFiniteAutomata<State, Transition>
544where
545    State: Eq + Hash + Clone,
546    Transition: Eq + Hash + Clone,
547{
548    /// This function is equivalent to [`NonDeterministicFiniteAutomata::new`].
549    fn default() -> Self {
550        Self::new()
551    }
552}
553
554/// Tests for [`NonDeterministicFiniteAutomata`].
555#[cfg(test)]
556mod nfa_tests {
557    use super::test_traits::*;
558    use super::*;
559
560    fn setup_automata() -> Nfa<i32, ()> {
561        let mut nfa = Nfa::new();
562        let state_list = [1, 2, 3, 4, 5, 6, 7];
563        for &state in state_list.iter() {
564            nfa.add_state(state);
565        }
566        nfa.add_initial(1, ());
567        nfa.add_final(7, ());
568        let transition_list = [
569            (1, 2),
570            (1, 3),
571            (2, 6),
572            (3, 4),
573            (3, 5),
574            (3, 6),
575            (4, 5),
576            (5, 7),
577            (6, 7),
578        ];
579        for &(src, dst) in transition_list.iter() {
580            nfa.add_transition(src, (), dst);
581        }
582        nfa
583    }
584
585    fn setup_automata_loop() -> Nfa<i32, ()> {
586        let mut nfa = Nfa::new();
587        nfa.add_initial(1, ());
588        nfa.add_final(2, ());
589        nfa.add_transition(1, (), 2);
590        nfa.add_transition(2, (), 1);
591        nfa
592    }
593
594    #[test]
595    fn test_add_state() {
596        let nfa = setup_automata();
597        let expected_states = vec![1, 2, 3, 4, 5, 6, 7].into_hash_set();
598        let result_states = nfa.states;
599        assert_eq!(expected_states, result_states);
600    }
601
602    #[test]
603    fn test_add_initial_state() {
604        let nfa = setup_automata();
605        let expected_states = vec![1].into_hash_set();
606        let result_states: HashSet<i32> = nfa.initial_states.keys().map(|i| *i).collect();
607        assert_eq!(expected_states, result_states);
608    }
609
610    #[test]
611    fn test_add_final_state() {
612        let nfa = setup_automata();
613        let expected_states = vec![7].into_hash_set();
614        let result_states: HashSet<i32> = nfa.final_states.keys().map(|i| *i).collect();
615        assert_eq!(expected_states, result_states);
616    }
617
618    #[test]
619    fn test_add_transition() {
620        let nfa = setup_automata();
621        let expected_deltas = [
622            (1, 2),
623            (1, 3),
624            (2, 6),
625            (3, 4),
626            (3, 5),
627            (3, 6),
628            (4, 5),
629            (5, 7),
630            (6, 7),
631        ]
632        .iter()
633        .map(|t| t.to_owned())
634        .collect::<HashSet<_>>();
635        let expected_ideltas = expected_deltas
636            .iter()
637            .map(|(fst, snd)| (*snd, *fst))
638            .map(|t| t.to_owned())
639            .collect::<HashSet<_>>();
640        let mut result_deltas = HashSet::new();
641        for (src, transitions) in nfa.delta {
642            for destinations in transitions.values() {
643                for &dst in destinations {
644                    result_deltas.insert((src, dst));
645                }
646            }
647        }
648        let mut result_ideltas = HashSet::new();
649        for (src, transitions) in nfa.idelta {
650            for destinations in transitions.values() {
651                for &dst in destinations {
652                    result_ideltas.insert((src, dst));
653                }
654            }
655        }
656        assert_eq!(expected_deltas, result_deltas);
657        assert_eq!(expected_ideltas, result_ideltas);
658    }
659
660    #[test]
661    fn test_add_non_deterministic_transition() {
662        let mut nfa = Nfa::new();
663        [1, 2, 3, 4, 5, 6, 7]
664            .iter()
665            .map(|i| *i)
666            .for_each(|i| nfa.add_state(i));
667        nfa.add_initial(1, ());
668        nfa.add_final(7, ());
669        let non_deterministic_transitions = vec![
670            (1, vec![2, 3]),
671            (2, vec![6]),
672            (3, vec![4, 5, 6]),
673            (4, vec![5]),
674            (5, vec![7]),
675            (6, vec![7]),
676        ];
677        for (source, destinations) in non_deterministic_transitions {
678            nfa.add_non_deterministic_transitions(&source, &(), destinations.into_iter());
679        }
680        let expected_deltas = [
681            (1, 2),
682            (1, 3),
683            (2, 6),
684            (3, 4),
685            (3, 5),
686            (3, 6),
687            (4, 5),
688            (5, 7),
689            (6, 7),
690        ]
691        .iter()
692        .map(|t| t.to_owned())
693        .collect::<HashSet<_>>();
694        let expected_ideltas = expected_deltas
695            .iter()
696            .map(|(fst, snd)| (*snd, *fst))
697            .map(|t| t.to_owned())
698            .collect::<HashSet<_>>();
699        let mut result_deltas = HashSet::new();
700        for (src, transitions) in nfa.delta {
701            for destinations in transitions.values() {
702                for &dst in destinations {
703                    result_deltas.insert((src, dst));
704                }
705            }
706        }
707        let mut result_ideltas = HashSet::new();
708        for (src, transitions) in nfa.idelta {
709            for destinations in transitions.values() {
710                for &dst in destinations {
711                    result_ideltas.insert((src, dst));
712                }
713            }
714        }
715        assert_eq!(expected_deltas, result_deltas);
716        assert_eq!(expected_ideltas, result_ideltas);
717    }
718
719    #[test]
720    fn test_productive() {
721        let nfa = setup_automata();
722        let result = nfa.productive_states();
723        let expected = [1, 2, 3, 4, 5, 6, 7]
724            .iter()
725            .map(|i| i.to_owned())
726            .collect::<HashSet<i32>>();
727        assert_eq!(expected, result);
728    }
729
730    #[test]
731    fn test_productive_loop() {
732        let nfa = setup_automata_loop();
733        let result = nfa.productive_states();
734        let expected = [1, 2]
735            .iter()
736            .map(|i| i.to_owned())
737            .collect::<HashSet<i32>>();
738        assert_eq!(expected, result);
739    }
740
741    #[test]
742    fn test_useful() {
743        let nfa = setup_automata();
744        let result = nfa.useful_states();
745        let expected = [1, 2, 3, 4, 5, 6, 7]
746            .iter()
747            .map(|i| i.to_owned())
748            .collect::<HashSet<i32>>();
749        assert_eq!(expected, result);
750    }
751}
752
753/// Module containing useful traits for tests.
754#[cfg(test)] // should only be available for tests
755mod test_traits {
756    use std::{collections::HashSet, hash::Hash, rc::Rc};
757
758    /// A conversion to HashSet<T> trait.
759    pub(crate) trait IntoHashSet<T>
760    where
761        T: Eq + Hash,
762    {
763        fn into_hash_set(self) -> HashSet<T>;
764    }
765
766    /// Implementation of [IntoHashSet<T>] for a `Vec<i32>`.
767    impl IntoHashSet<i32> for Vec<i32> {
768        fn into_hash_set(self) -> HashSet<i32> {
769            self.iter().map(|t| t.to_owned()).collect()
770        }
771    }
772
773    /// Implementation of [IntoHashSet<T>] for an `HashSet<Rc<i32>>`.
774    impl IntoHashSet<i32> for HashSet<Rc<i32>> {
775        fn into_hash_set(self) -> HashSet<i32> {
776            self.iter().map(|i| *i.to_owned()).collect()
777        }
778    }
779}