trackler 2.2.1.135 → 2.2.1.136
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/pov/canonical-data.json +33 -1
- data/tracks/c/exercises/acronym/test/test_acronym.c +25 -17
- data/tracks/csharp/exercises/binary-search-tree/BinarySearchTreeTest.cs +37 -28
- data/tracks/csharp/generators/Exercises/BinarySearchTree.cs +69 -0
- data/tracks/haskell/config.json +1 -0
- data/tracks/haskell/exercises/accumulate/package.yaml +1 -1
- data/tracks/haskell/exercises/acronym/package.yaml +1 -1
- data/tracks/haskell/exercises/all-your-base/package.yaml +1 -1
- data/tracks/haskell/exercises/allergies/package.yaml +1 -1
- data/tracks/haskell/exercises/alphametics/package.yaml +1 -1
- data/tracks/haskell/exercises/anagram/package.yaml +1 -1
- data/tracks/haskell/exercises/atbash-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/bank-account/package.yaml +1 -1
- data/tracks/haskell/exercises/beer-song/package.yaml +1 -1
- data/tracks/haskell/exercises/binary-search-tree/package.yaml +1 -1
- data/tracks/haskell/exercises/binary/package.yaml +1 -1
- data/tracks/haskell/exercises/bob/package.yaml +1 -1
- data/tracks/haskell/exercises/bowling/package.yaml +1 -1
- data/tracks/haskell/exercises/bracket-push/package.yaml +1 -1
- data/tracks/haskell/exercises/change/package.yaml +1 -1
- data/tracks/haskell/exercises/clock/package.yaml +1 -1
- data/tracks/haskell/exercises/collatz-conjecture/package.yaml +1 -1
- data/tracks/haskell/exercises/complex-numbers/package.yaml +1 -1
- data/tracks/haskell/exercises/connect/package.yaml +1 -1
- data/tracks/haskell/exercises/crypto-square/package.yaml +1 -1
- data/tracks/haskell/exercises/custom-set/package.yaml +1 -1
- data/tracks/haskell/exercises/diamond/package.yaml +1 -1
- data/tracks/haskell/exercises/difference-of-squares/package.yaml +1 -1
- data/tracks/haskell/exercises/dominoes/package.yaml +1 -1
- data/tracks/haskell/exercises/etl/package.yaml +1 -1
- data/tracks/haskell/exercises/food-chain/package.yaml +1 -1
- data/tracks/haskell/exercises/forth/package.yaml +1 -1
- data/tracks/haskell/exercises/gigasecond/package.yaml +1 -1
- data/tracks/haskell/exercises/go-counting/package.yaml +1 -1
- data/tracks/haskell/exercises/grade-school/package.yaml +1 -1
- data/tracks/haskell/exercises/grains/package.yaml +1 -1
- data/tracks/haskell/exercises/hamming/package.yaml +1 -1
- data/tracks/haskell/exercises/hello-world/package.yaml +1 -1
- data/tracks/haskell/exercises/hexadecimal/package.yaml +1 -1
- data/tracks/haskell/exercises/house/package.yaml +1 -1
- data/tracks/haskell/exercises/isbn-verifier/package.yaml +1 -1
- data/tracks/haskell/exercises/isogram/package.yaml +1 -1
- data/tracks/haskell/exercises/kindergarten-garden/examples/success-standard/src/Garden.hs +1 -10
- data/tracks/haskell/exercises/kindergarten-garden/package.yaml +2 -3
- data/tracks/haskell/exercises/kindergarten-garden/src/Garden.hs +3 -7
- data/tracks/haskell/exercises/kindergarten-garden/test/Tests.hs +10 -16
- data/tracks/haskell/exercises/largest-series-product/package.yaml +1 -1
- data/tracks/haskell/exercises/leap/package.yaml +1 -1
- data/tracks/haskell/exercises/lens-person/examples/success-standard/package.yaml +0 -1
- data/tracks/haskell/exercises/lens-person/package.yaml +1 -1
- data/tracks/haskell/exercises/linked-list/package.yaml +1 -1
- data/tracks/haskell/exercises/list-ops/package.yaml +1 -1
- data/tracks/haskell/exercises/luhn/package.yaml +1 -1
- data/tracks/haskell/exercises/matrix/package.yaml +1 -1
- data/tracks/haskell/exercises/meetup/package.yaml +1 -1
- data/tracks/haskell/exercises/minesweeper/package.yaml +1 -1
- data/tracks/haskell/exercises/nth-prime/package.yaml +1 -1
- data/tracks/haskell/exercises/nucleotide-count/package.yaml +1 -1
- data/tracks/haskell/exercises/ocr-numbers/package.yaml +1 -1
- data/tracks/haskell/exercises/octal/package.yaml +1 -1
- data/tracks/haskell/exercises/palindrome-products/package.yaml +1 -1
- data/tracks/haskell/exercises/pangram/package.yaml +1 -1
- data/tracks/haskell/exercises/parallel-letter-frequency/package.yaml +1 -1
- data/tracks/haskell/exercises/pascals-triangle/package.yaml +1 -1
- data/tracks/haskell/exercises/perfect-numbers/package.yaml +1 -1
- data/tracks/haskell/exercises/phone-number/package.yaml +1 -1
- data/tracks/haskell/exercises/pig-latin/package.yaml +1 -1
- data/tracks/haskell/exercises/poker/package.yaml +1 -1
- data/tracks/haskell/exercises/pov/package.yaml +2 -2
- data/tracks/haskell/exercises/pov/test/Tests.hs +15 -0
- data/tracks/haskell/exercises/prime-factors/package.yaml +1 -1
- data/tracks/haskell/exercises/protein-translation/package.yaml +1 -1
- data/tracks/haskell/exercises/pythagorean-triplet/package.yaml +1 -1
- data/tracks/haskell/exercises/queen-attack/package.yaml +1 -1
- data/tracks/haskell/exercises/rail-fence-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/raindrops/package.yaml +1 -1
- data/tracks/haskell/exercises/rna-transcription/package.yaml +1 -1
- data/tracks/haskell/exercises/robot-name/package.yaml +1 -1
- data/tracks/haskell/exercises/robot-simulator/package.yaml +1 -1
- data/tracks/haskell/exercises/roman-numerals/package.yaml +1 -1
- data/tracks/haskell/exercises/rotational-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/run-length-encoding/package.yaml +1 -1
- data/tracks/haskell/exercises/saddle-points/package.yaml +1 -1
- data/tracks/haskell/exercises/say/package.yaml +1 -1
- data/tracks/haskell/exercises/scrabble-score/package.yaml +1 -1
- data/tracks/haskell/exercises/secret-handshake/package.yaml +1 -1
- data/tracks/haskell/exercises/series/package.yaml +1 -1
- data/tracks/haskell/exercises/sgf-parsing/package.yaml +1 -1
- data/tracks/haskell/exercises/sieve/package.yaml +1 -1
- data/tracks/haskell/exercises/simple-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/simple-linked-list/package.yaml +1 -1
- data/tracks/haskell/exercises/space-age/package.yaml +1 -1
- data/tracks/haskell/exercises/spiral-matrix/package.yaml +1 -1
- data/tracks/haskell/exercises/strain/package.yaml +1 -1
- data/tracks/haskell/exercises/sublist/package.yaml +1 -1
- data/tracks/haskell/exercises/sum-of-multiples/package.yaml +1 -1
- data/tracks/haskell/exercises/transpose/package.yaml +1 -1
- data/tracks/haskell/exercises/triangle/package.yaml +1 -1
- data/tracks/haskell/exercises/trinary/package.yaml +1 -1
- data/tracks/haskell/exercises/twelve-days/package.yaml +1 -1
- data/tracks/haskell/exercises/word-count/package.yaml +1 -1
- data/tracks/haskell/exercises/wordy/package.yaml +1 -1
- data/tracks/haskell/exercises/zebra-puzzle/package.yaml +1 -1
- data/tracks/haskell/exercises/zipper/package.yaml +1 -1
- data/tracks/java/CONTRIBUTING.md +39 -3
- data/tracks/java/POLICIES.md +68 -3
- data/tracks/java/exercises/crypto-square/README.md +4 -5
- data/tracks/java/exercises/error-handling/README.md +38 -0
- data/tracks/java/exercises/series/README.md +6 -6
- data/tracks/java/exercises/sieve/README.md +5 -3
- data/tracks/java/scripts/canonical_data_check.sh +1 -1
- data/tracks/python/exercises/react/example.py +54 -63
- data/tracks/python/exercises/react/react.py +10 -10
- data/tracks/python/exercises/react/react_test.py +197 -131
- data/tracks/python/exercises/sieve/README.md +5 -3
- data/tracks/rust/exercises/react/example.rs +103 -64
- data/tracks/rust/exercises/react/src/lib.rs +31 -17
- data/tracks/rust/exercises/react/tests/react.rs +52 -61
- data/tracks/swift/config.json +11 -0
- data/tracks/swift/exercises/circular-buffer/Sources/CircularBufferExample.swift +12 -12
- data/tracks/swift/exercises/circular-buffer/Tests/CircularBufferTests/CircularBufferTests.swift +1 -1
- data/tracks/swift/exercises/proverb/Package.swift +5 -0
- data/tracks/swift/exercises/proverb/README.md +25 -0
- data/tracks/swift/exercises/proverb/Sources/Proverb.swift +1 -0
- data/tracks/swift/exercises/proverb/Sources/ProverbExample.swift +28 -0
- data/tracks/swift/exercises/proverb/Tests/LinuxMain.swift +6 -0
- data/tracks/swift/exercises/proverb/Tests/ProverbTests/ProverbTests.swift +61 -0
- data/tracks/typescript/config.json +14 -0
- data/tracks/typescript/exercises/palindrome-products/README.md +65 -0
- data/tracks/typescript/exercises/palindrome-products/package.json +36 -0
- data/tracks/typescript/exercises/palindrome-products/palindrome-products.example.ts +38 -0
- data/tracks/typescript/exercises/palindrome-products/palindrome-products.test.ts +69 -0
- data/tracks/typescript/exercises/palindrome-products/palindrome-products.ts +0 -0
- data/tracks/typescript/exercises/palindrome-products/tsconfig.json +22 -0
- data/tracks/typescript/exercises/palindrome-products/tslint.json +127 -0
- data/tracks/typescript/exercises/palindrome-products/yarn.lock +2624 -0
- metadata +17 -2
|
@@ -1,12 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
pub
|
|
4
|
-
|
|
1
|
+
/// `InputCellID` is a unique identifier for an input cell.
|
|
2
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
3
|
+
pub struct InputCellID();
|
|
4
|
+
/// `ComputeCellID` is a unique identifier for a compute cell.
|
|
5
|
+
/// Values of type `InputCellID` and `ComputeCellID` should not be mutually assignable,
|
|
6
|
+
/// demonstrated by the following tests:
|
|
7
|
+
///
|
|
8
|
+
/// ```compile_fail
|
|
9
|
+
/// let mut r = react::Reactor::new();
|
|
10
|
+
/// let input: react::ComputeCellID = r.create_input(111);
|
|
11
|
+
/// ```
|
|
12
|
+
///
|
|
13
|
+
/// ```compile_fail
|
|
14
|
+
/// let mut r = react::Reactor::new();
|
|
15
|
+
/// let input = r.create_input(111);
|
|
16
|
+
/// let compute: react::InputCellID = r.create_compute(&[react::CellID::Input(input)], |_| 222).unwrap();
|
|
17
|
+
/// ```
|
|
18
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
19
|
+
pub struct ComputeCellID();
|
|
20
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
21
|
+
pub struct CallbackID();
|
|
5
22
|
|
|
6
|
-
#[derive(Debug, PartialEq)]
|
|
7
|
-
pub enum
|
|
8
|
-
|
|
9
|
-
|
|
23
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
24
|
+
pub enum CellID {
|
|
25
|
+
Input(InputCellID),
|
|
26
|
+
Compute(ComputeCellID),
|
|
10
27
|
}
|
|
11
28
|
|
|
12
29
|
#[derive(Debug, PartialEq)]
|
|
@@ -28,7 +45,7 @@ impl <T: Copy + PartialEq> Reactor<T> {
|
|
|
28
45
|
}
|
|
29
46
|
|
|
30
47
|
// Creates an input cell with the specified initial value, returning its ID.
|
|
31
|
-
pub fn create_input(&mut self, _initial: T) ->
|
|
48
|
+
pub fn create_input(&mut self, _initial: T) -> InputCellID {
|
|
32
49
|
unimplemented!()
|
|
33
50
|
}
|
|
34
51
|
|
|
@@ -45,7 +62,7 @@ impl <T: Copy + PartialEq> Reactor<T> {
|
|
|
45
62
|
// Notice that there is no way to *remove* a cell.
|
|
46
63
|
// This means that you may assume, without checking, that if the dependencies exist at creation
|
|
47
64
|
// time they will continue to exist as long as the Reactor exists.
|
|
48
|
-
pub fn create_compute<F: Fn(&[T]) -> T>(&mut self, _dependencies: &[CellID], _compute_func: F) -> Result<
|
|
65
|
+
pub fn create_compute<F: Fn(&[T]) -> T>(&mut self, _dependencies: &[CellID], _compute_func: F) -> Result<ComputeCellID, CellID> {
|
|
49
66
|
unimplemented!()
|
|
50
67
|
}
|
|
51
68
|
|
|
@@ -62,16 +79,13 @@ impl <T: Copy + PartialEq> Reactor<T> {
|
|
|
62
79
|
|
|
63
80
|
// Sets the value of the specified input cell.
|
|
64
81
|
//
|
|
65
|
-
// Returns
|
|
66
|
-
// * the cell does not exist
|
|
67
|
-
// * the specified cell is a compute cell, since compute cells cannot have their values
|
|
68
|
-
// directly set.
|
|
82
|
+
// Returns false if the cell does not exist.
|
|
69
83
|
//
|
|
70
84
|
// Similarly, you may wonder about `get_mut(&mut self, id: CellID) -> Option<&mut Cell>`, with
|
|
71
85
|
// a `set_value(&mut self, new_value: T)` method on `Cell`.
|
|
72
86
|
//
|
|
73
87
|
// As before, that turned out to add too much extra complexity.
|
|
74
|
-
pub fn set_value(&mut self, _id:
|
|
88
|
+
pub fn set_value(&mut self, _id: InputCellID, _new_value: T) -> bool {
|
|
75
89
|
unimplemented!()
|
|
76
90
|
}
|
|
77
91
|
|
|
@@ -87,7 +101,7 @@ impl <T: Copy + PartialEq> Reactor<T> {
|
|
|
87
101
|
// * Exactly once if the compute cell's value changed as a result of the set_value call.
|
|
88
102
|
// The value passed to the callback should be the final value of the compute cell after the
|
|
89
103
|
// set_value call.
|
|
90
|
-
pub fn add_callback<F: FnMut(T) -> ()>(&mut self, _id:
|
|
104
|
+
pub fn add_callback<F: FnMut(T) -> ()>(&mut self, _id: ComputeCellID, _callback: F) -> Option<CallbackID> {
|
|
91
105
|
unimplemented!()
|
|
92
106
|
}
|
|
93
107
|
|
|
@@ -96,7 +110,7 @@ impl <T: Copy + PartialEq> Reactor<T> {
|
|
|
96
110
|
// Returns an Err if either the cell or callback does not exist.
|
|
97
111
|
//
|
|
98
112
|
// A removed callback should no longer be called.
|
|
99
|
-
pub fn remove_callback(&mut self, cell:
|
|
113
|
+
pub fn remove_callback(&mut self, cell: ComputeCellID, callback: CallbackID) -> Result<(), RemoveCallbackError> {
|
|
100
114
|
unimplemented!(
|
|
101
115
|
"Remove the callback identified by the CallbackID {:?} from the cell {:?}",
|
|
102
116
|
callback,
|
|
@@ -6,7 +6,7 @@ use react::*;
|
|
|
6
6
|
fn input_cells_have_a_value() {
|
|
7
7
|
let mut reactor = Reactor::new();
|
|
8
8
|
let input = reactor.create_input(10);
|
|
9
|
-
assert_eq!(reactor.value(input), Some(10));
|
|
9
|
+
assert_eq!(reactor.value(CellID::Input(input)), Some(10));
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
#[test]
|
|
@@ -14,8 +14,8 @@ fn input_cells_have_a_value() {
|
|
|
14
14
|
fn an_input_cells_value_can_be_set() {
|
|
15
15
|
let mut reactor = Reactor::new();
|
|
16
16
|
let input = reactor.create_input(4);
|
|
17
|
-
assert!(reactor.set_value(input, 20)
|
|
18
|
-
assert_eq!(reactor.value(input), Some(20));
|
|
17
|
+
assert!(reactor.set_value(input, 20));
|
|
18
|
+
assert_eq!(reactor.value(CellID::Input(input)), Some(20));
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
#[test]
|
|
@@ -23,7 +23,7 @@ fn an_input_cells_value_can_be_set() {
|
|
|
23
23
|
fn error_setting_a_nonexistent_input_cell() {
|
|
24
24
|
let mut dummy_reactor = Reactor::new();
|
|
25
25
|
let input = dummy_reactor.create_input(1);
|
|
26
|
-
|
|
26
|
+
assert!(!Reactor::new().set_value(input, 0));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
#[test]
|
|
@@ -31,8 +31,8 @@ fn error_setting_a_nonexistent_input_cell() {
|
|
|
31
31
|
fn compute_cells_calculate_initial_value() {
|
|
32
32
|
let mut reactor = Reactor::new();
|
|
33
33
|
let input = reactor.create_input(1);
|
|
34
|
-
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
|
|
35
|
-
assert_eq!(reactor.value(output), Some(2));
|
|
34
|
+
let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap();
|
|
35
|
+
assert_eq!(reactor.value(CellID::Compute(output)), Some(2));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
#[test]
|
|
@@ -41,8 +41,8 @@ fn compute_cells_take_inputs_in_the_right_order() {
|
|
|
41
41
|
let mut reactor = Reactor::new();
|
|
42
42
|
let one = reactor.create_input(1);
|
|
43
43
|
let two = reactor.create_input(2);
|
|
44
|
-
let output = reactor.create_compute(&[one, two], |v| v[0] + v[1] * 10).unwrap();
|
|
45
|
-
assert_eq!(reactor.value(output), Some(21));
|
|
44
|
+
let output = reactor.create_compute(&[CellID::Input(one), CellID::Input(two)], |v| v[0] + v[1] * 10).unwrap();
|
|
45
|
+
assert_eq!(reactor.value(CellID::Compute(output)), Some(21));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
#[test]
|
|
@@ -50,7 +50,7 @@ fn compute_cells_take_inputs_in_the_right_order() {
|
|
|
50
50
|
fn error_creating_compute_cell_if_input_doesnt_exist() {
|
|
51
51
|
let mut dummy_reactor = Reactor::new();
|
|
52
52
|
let input = dummy_reactor.create_input(1);
|
|
53
|
-
assert_eq!(Reactor::new().create_compute(&[input], |_| 0), Err(input));
|
|
53
|
+
assert_eq!(Reactor::new().create_compute(&[CellID::Input(input)], |_| 0), Err(CellID::Input(input)));
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
#[test]
|
|
@@ -61,9 +61,9 @@ fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() {
|
|
|
61
61
|
let dummy_cell = dummy_reactor.create_input(2);
|
|
62
62
|
let mut reactor = Reactor::new();
|
|
63
63
|
let input = reactor.create_input(1);
|
|
64
|
-
assert_eq!(reactor.create_compute(&[input, dummy_cell], |_| 0), Err(dummy_cell));
|
|
65
|
-
assert!(reactor.set_value(input, 5)
|
|
66
|
-
assert_eq!(reactor.value(input), Some(5));
|
|
64
|
+
assert_eq!(reactor.create_compute(&[CellID::Input(input), CellID::Input(dummy_cell)], |_| 0), Err(CellID::Input(dummy_cell)));
|
|
65
|
+
assert!(reactor.set_value(input, 5));
|
|
66
|
+
assert_eq!(reactor.value(CellID::Input(input)), Some(5));
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
#[test]
|
|
@@ -71,10 +71,10 @@ fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() {
|
|
|
71
71
|
fn compute_cells_update_value_when_dependencies_are_changed() {
|
|
72
72
|
let mut reactor = Reactor::new();
|
|
73
73
|
let input = reactor.create_input(1);
|
|
74
|
-
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
|
|
75
|
-
assert_eq!(reactor.value(output), Some(2));
|
|
76
|
-
assert!(reactor.set_value(input, 3)
|
|
77
|
-
assert_eq!(reactor.value(output), Some(4));
|
|
74
|
+
let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap();
|
|
75
|
+
assert_eq!(reactor.value(CellID::Compute(output)), Some(2));
|
|
76
|
+
assert!(reactor.set_value(input, 3));
|
|
77
|
+
assert_eq!(reactor.value(CellID::Compute(output)), Some(4));
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
#[test]
|
|
@@ -82,21 +82,12 @@ fn compute_cells_update_value_when_dependencies_are_changed() {
|
|
|
82
82
|
fn compute_cells_can_depend_on_other_compute_cells() {
|
|
83
83
|
let mut reactor = Reactor::new();
|
|
84
84
|
let input = reactor.create_input(1);
|
|
85
|
-
let times_two = reactor.create_compute(&[input], |v| v[0] * 2).unwrap();
|
|
86
|
-
let times_thirty = reactor.create_compute(&[input], |v| v[0] * 30).unwrap();
|
|
87
|
-
let output = reactor.create_compute(&[times_two, times_thirty], |v| v[0] + v[1]).unwrap();
|
|
88
|
-
assert_eq!(reactor.value(output), Some(32));
|
|
89
|
-
assert!(reactor.set_value(input, 3)
|
|
90
|
-
assert_eq!(reactor.value(output), Some(96));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
#[test]
|
|
94
|
-
#[ignore]
|
|
95
|
-
fn error_setting_a_compute_cell() {
|
|
96
|
-
let mut reactor = Reactor::new();
|
|
97
|
-
let input = reactor.create_input(1);
|
|
98
|
-
let output = reactor.create_compute(&[input], |_| 0).unwrap();
|
|
99
|
-
assert_eq!(reactor.set_value(output, 3), Err(SetValueError::ComputeCell));
|
|
85
|
+
let times_two = reactor.create_compute(&[CellID::Input(input)], |v| v[0] * 2).unwrap();
|
|
86
|
+
let times_thirty = reactor.create_compute(&[CellID::Input(input)], |v| v[0] * 30).unwrap();
|
|
87
|
+
let output = reactor.create_compute(&[CellID::Compute(times_two), CellID::Compute(times_thirty)], |v| v[0] + v[1]).unwrap();
|
|
88
|
+
assert_eq!(reactor.value(CellID::Compute(output)), Some(32));
|
|
89
|
+
assert!(reactor.set_value(input, 3));
|
|
90
|
+
assert_eq!(reactor.value(CellID::Compute(output)), Some(96));
|
|
100
91
|
}
|
|
101
92
|
|
|
102
93
|
/// A CallbackRecorder helps tests whether callbacks get called correctly.
|
|
@@ -138,9 +129,9 @@ fn compute_cells_fire_callbacks() {
|
|
|
138
129
|
let cb = CallbackRecorder::new();
|
|
139
130
|
let mut reactor = Reactor::new();
|
|
140
131
|
let input = reactor.create_input(1);
|
|
141
|
-
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
|
|
132
|
+
let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap();
|
|
142
133
|
assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_some());
|
|
143
|
-
assert!(reactor.set_value(input, 3)
|
|
134
|
+
assert!(reactor.set_value(input, 3));
|
|
144
135
|
cb.expect_to_have_been_called_with(4);
|
|
145
136
|
}
|
|
146
137
|
|
|
@@ -149,7 +140,7 @@ fn compute_cells_fire_callbacks() {
|
|
|
149
140
|
fn error_adding_callback_to_nonexistent_cell() {
|
|
150
141
|
let mut dummy_reactor = Reactor::new();
|
|
151
142
|
let input = dummy_reactor.create_input(1);
|
|
152
|
-
let output = dummy_reactor.create_compute(&[input], |_| 0).unwrap();
|
|
143
|
+
let output = dummy_reactor.create_compute(&[CellID::Input(input)], |_| 0).unwrap();
|
|
153
144
|
assert_eq!(Reactor::new().add_callback(output, |_: usize| println!("hi")), None);
|
|
154
145
|
}
|
|
155
146
|
|
|
@@ -159,12 +150,12 @@ fn callbacks_only_fire_on_change() {
|
|
|
159
150
|
let cb = CallbackRecorder::new();
|
|
160
151
|
let mut reactor = Reactor::new();
|
|
161
152
|
let input = reactor.create_input(1);
|
|
162
|
-
let output = reactor.create_compute(&[input], |v| if v[0] < 3 { 111 } else { 222 }).unwrap();
|
|
153
|
+
let output = reactor.create_compute(&[CellID::Input(input)], |v| if v[0] < 3 { 111 } else { 222 }).unwrap();
|
|
163
154
|
assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_some());
|
|
164
155
|
|
|
165
|
-
assert!(reactor.set_value(input, 2)
|
|
156
|
+
assert!(reactor.set_value(input, 2));
|
|
166
157
|
cb.expect_not_to_have_been_called();
|
|
167
|
-
assert!(reactor.set_value(input, 4)
|
|
158
|
+
assert!(reactor.set_value(input, 4));
|
|
168
159
|
cb.expect_to_have_been_called_with(222);
|
|
169
160
|
}
|
|
170
161
|
|
|
@@ -177,19 +168,19 @@ fn callbacks_can_be_added_and_removed() {
|
|
|
177
168
|
|
|
178
169
|
let mut reactor = Reactor::new();
|
|
179
170
|
let input = reactor.create_input(11);
|
|
180
|
-
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
|
|
171
|
+
let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap();
|
|
181
172
|
|
|
182
173
|
let callback = reactor.add_callback(output, |v| cb1.callback_called(v)).unwrap();
|
|
183
174
|
assert!(reactor.add_callback(output, |v| cb2.callback_called(v)).is_some());
|
|
184
175
|
|
|
185
|
-
assert!(reactor.set_value(input, 31)
|
|
176
|
+
assert!(reactor.set_value(input, 31));
|
|
186
177
|
cb1.expect_to_have_been_called_with(32);
|
|
187
178
|
cb2.expect_to_have_been_called_with(32);
|
|
188
179
|
|
|
189
180
|
assert!(reactor.remove_callback(output, callback).is_ok());
|
|
190
181
|
assert!(reactor.add_callback(output, |v| cb3.callback_called(v)).is_some());
|
|
191
182
|
|
|
192
|
-
assert!(reactor.set_value(input, 41)
|
|
183
|
+
assert!(reactor.set_value(input, 41));
|
|
193
184
|
cb1.expect_not_to_have_been_called();
|
|
194
185
|
cb2.expect_to_have_been_called_with(42);
|
|
195
186
|
cb3.expect_to_have_been_called_with(42);
|
|
@@ -203,7 +194,7 @@ fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() {
|
|
|
203
194
|
|
|
204
195
|
let mut reactor = Reactor::new();
|
|
205
196
|
let input = reactor.create_input(1);
|
|
206
|
-
let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
|
|
197
|
+
let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap();
|
|
207
198
|
let callback = reactor.add_callback(output, |v| cb1.callback_called(v)).unwrap();
|
|
208
199
|
assert!(reactor.add_callback(output, |v| cb2.callback_called(v)).is_some());
|
|
209
200
|
// We want the first remove to be Ok, but the others should be errors.
|
|
@@ -212,7 +203,7 @@ fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() {
|
|
|
212
203
|
assert_eq!(reactor.remove_callback(output, callback), Err(RemoveCallbackError::NonexistentCallback));
|
|
213
204
|
}
|
|
214
205
|
|
|
215
|
-
assert!(reactor.set_value(input, 2)
|
|
206
|
+
assert!(reactor.set_value(input, 2));
|
|
216
207
|
cb1.expect_not_to_have_been_called();
|
|
217
208
|
cb2.expect_to_have_been_called_with(3);
|
|
218
209
|
}
|
|
@@ -223,12 +214,12 @@ fn callbacks_should_only_be_called_once_even_if_multiple_dependencies_change() {
|
|
|
223
214
|
let cb = CallbackRecorder::new();
|
|
224
215
|
let mut reactor = Reactor::new();
|
|
225
216
|
let input = reactor.create_input(1);
|
|
226
|
-
let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
|
|
227
|
-
let minus_one1 = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
|
|
228
|
-
let minus_one2 = reactor.create_compute(&[minus_one1], |v| v[0] - 1).unwrap();
|
|
229
|
-
let output = reactor.create_compute(&[plus_one, minus_one2], |v| v[0] * v[1]).unwrap();
|
|
217
|
+
let plus_one = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap();
|
|
218
|
+
let minus_one1 = reactor.create_compute(&[CellID::Input(input)], |v| v[0] - 1).unwrap();
|
|
219
|
+
let minus_one2 = reactor.create_compute(&[CellID::Compute(minus_one1)], |v| v[0] - 1).unwrap();
|
|
220
|
+
let output = reactor.create_compute(&[CellID::Compute(plus_one), CellID::Compute(minus_one2)], |v| v[0] * v[1]).unwrap();
|
|
230
221
|
assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_some());
|
|
231
|
-
assert!(reactor.set_value(input, 4)
|
|
222
|
+
assert!(reactor.set_value(input, 4));
|
|
232
223
|
cb.expect_to_have_been_called_with(10);
|
|
233
224
|
}
|
|
234
225
|
|
|
@@ -238,12 +229,12 @@ fn callbacks_should_not_be_called_if_dependencies_change_but_output_value_doesnt
|
|
|
238
229
|
let cb = CallbackRecorder::new();
|
|
239
230
|
let mut reactor = Reactor::new();
|
|
240
231
|
let input = reactor.create_input(1);
|
|
241
|
-
let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap();
|
|
242
|
-
let minus_one = reactor.create_compute(&[input], |v| v[0] - 1).unwrap();
|
|
243
|
-
let always_two = reactor.create_compute(&[plus_one, minus_one], |v| v[0] - v[1]).unwrap();
|
|
232
|
+
let plus_one = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap();
|
|
233
|
+
let minus_one = reactor.create_compute(&[CellID::Input(input)], |v| v[0] - 1).unwrap();
|
|
234
|
+
let always_two = reactor.create_compute(&[CellID::Compute(plus_one), CellID::Compute(minus_one)], |v| v[0] - v[1]).unwrap();
|
|
244
235
|
assert!(reactor.add_callback(always_two, |v| cb.callback_called(v)).is_some());
|
|
245
236
|
for i in 2..5 {
|
|
246
|
-
assert!(reactor.set_value(input, i)
|
|
237
|
+
assert!(reactor.set_value(input, i));
|
|
247
238
|
cb.expect_not_to_have_been_called();
|
|
248
239
|
}
|
|
249
240
|
}
|
|
@@ -258,12 +249,12 @@ fn test_adder_with_boolean_values() {
|
|
|
258
249
|
let b = reactor.create_input(false);
|
|
259
250
|
let carry_in = reactor.create_input(false);
|
|
260
251
|
|
|
261
|
-
let a_xor_b = reactor.create_compute(&[a, b], |v| v[0] ^ v[1]).unwrap();
|
|
262
|
-
let sum = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] ^ v[1]).unwrap();
|
|
252
|
+
let a_xor_b = reactor.create_compute(&[CellID::Input(a), CellID::Input(b)], |v| v[0] ^ v[1]).unwrap();
|
|
253
|
+
let sum = reactor.create_compute(&[CellID::Compute(a_xor_b), CellID::Input(carry_in)], |v| v[0] ^ v[1]).unwrap();
|
|
263
254
|
|
|
264
|
-
let a_xor_b_and_cin = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] && v[1]).unwrap();
|
|
265
|
-
let a_and_b = reactor.create_compute(&[a, b], |v| v[0] && v[1]).unwrap();
|
|
266
|
-
let carry_out = reactor.create_compute(&[a_xor_b_and_cin, a_and_b], |v| v[0] || v[1]).unwrap();
|
|
255
|
+
let a_xor_b_and_cin = reactor.create_compute(&[CellID::Compute(a_xor_b), CellID::Input(carry_in)], |v| v[0] && v[1]).unwrap();
|
|
256
|
+
let a_and_b = reactor.create_compute(&[CellID::Input(a), CellID::Input(b)], |v| v[0] && v[1]).unwrap();
|
|
257
|
+
let carry_out = reactor.create_compute(&[CellID::Compute(a_xor_b_and_cin), CellID::Compute(a_and_b)], |v| v[0] || v[1]).unwrap();
|
|
267
258
|
|
|
268
259
|
let tests = &[
|
|
269
260
|
(false, false, false, false, false),
|
|
@@ -277,11 +268,11 @@ fn test_adder_with_boolean_values() {
|
|
|
277
268
|
];
|
|
278
269
|
|
|
279
270
|
for &(aval, bval, cinval, expected_cout, expected_sum) in tests {
|
|
280
|
-
assert!(reactor.set_value(a, aval)
|
|
281
|
-
assert!(reactor.set_value(b, bval)
|
|
282
|
-
assert!(reactor.set_value(carry_in, cinval)
|
|
271
|
+
assert!(reactor.set_value(a, aval));
|
|
272
|
+
assert!(reactor.set_value(b, bval));
|
|
273
|
+
assert!(reactor.set_value(carry_in, cinval));
|
|
283
274
|
|
|
284
|
-
assert_eq!(reactor.value(sum), Some(expected_sum));
|
|
285
|
-
assert_eq!(reactor.value(carry_out), Some(expected_cout));
|
|
275
|
+
assert_eq!(reactor.value(CellID::Compute(sum)), Some(expected_sum));
|
|
276
|
+
assert_eq!(reactor.value(CellID::Compute(carry_out)), Some(expected_cout));
|
|
286
277
|
}
|
|
287
278
|
}
|
data/tracks/swift/config.json
CHANGED
|
@@ -438,6 +438,17 @@
|
|
|
438
438
|
"loops"
|
|
439
439
|
]
|
|
440
440
|
},
|
|
441
|
+
{
|
|
442
|
+
"core": false,
|
|
443
|
+
"difficulty": 3,
|
|
444
|
+
"slug": "proverb",
|
|
445
|
+
"topics": [
|
|
446
|
+
"algorithms",
|
|
447
|
+
"strings"
|
|
448
|
+
],
|
|
449
|
+
"unlocked_by": null,
|
|
450
|
+
"uuid": "9604f1ef-4925-4c28-9c59-b986c1a42c7e"
|
|
451
|
+
},
|
|
441
452
|
{
|
|
442
453
|
"core": false,
|
|
443
454
|
"difficulty": 4,
|
|
@@ -10,29 +10,29 @@ struct CircularBuffer<T: Equatable> {
|
|
|
10
10
|
let capacity: Int
|
|
11
11
|
var writePoint = 0
|
|
12
12
|
var readPoint = 0
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
private var isFull: Bool {
|
|
15
15
|
return buffer.flatMap { $0 }.count >= capacity
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
private var isEmpty: Bool {
|
|
19
19
|
return buffer.flatMap { $0 }.isEmpty
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
init(capacity: Int) {
|
|
23
23
|
self.capacity = capacity
|
|
24
24
|
buffer = [T?](repeating: nil, count: capacity)
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
mutating func write(_ data: T) throws {
|
|
28
28
|
guard !isFull else {
|
|
29
29
|
throw CircularBufferError.bufferFull
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
buffer[writePoint] = data
|
|
33
33
|
updateWritePoint()
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
mutating func overwrite(_ data: T) {
|
|
37
37
|
buffer[writePoint] = data
|
|
38
38
|
if isFull && writePoint == readPoint {
|
|
@@ -40,26 +40,26 @@ struct CircularBuffer<T: Equatable> {
|
|
|
40
40
|
}
|
|
41
41
|
updateWritePoint()
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
mutating func read() throws -> T {
|
|
45
45
|
guard let data = buffer[readPoint] else {
|
|
46
46
|
throw CircularBufferError.bufferEmpty
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
buffer[readPoint] = nil
|
|
50
50
|
updateReadPoint()
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
return data
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
mutating func clear() {
|
|
56
56
|
buffer = [T?](repeating: nil, count: capacity)
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
private mutating func updateWritePoint() {
|
|
60
60
|
writePoint = (writePoint + 1) % capacity
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
private mutating func updateReadPoint() {
|
|
64
64
|
readPoint = (readPoint + 1) % capacity
|
|
65
65
|
}
|