mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
490 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba087ce64a | ||
|
|
3b03865a62 | ||
|
|
33fa274bbf | ||
|
|
23f700dc23 | ||
|
|
d876649616 | ||
|
|
e4c14ac76e | ||
|
|
b438049c39 | ||
|
|
b017579577 | ||
|
|
c8e4b357a3 | ||
|
|
8774e47dc3 | ||
|
|
e422ab1507 | ||
|
|
cdd8e19716 | ||
|
|
91d86a1de9 | ||
|
|
6a10f900b4 | ||
|
|
9b9a89c79a | ||
|
|
123e6426d1 | ||
|
|
427ec6b2e4 | ||
|
|
03dcb582e6 | ||
|
|
1043a06124 | ||
|
|
d20e413a68 | ||
|
|
9bf4c5e8df | ||
|
|
633303d4b8 | ||
|
|
a4a1098766 | ||
|
|
0bd459dcac | ||
|
|
3b4514b686 | ||
|
|
2e05606edc | ||
|
|
c8c1b87a01 | ||
|
|
34ea029df8 | ||
|
|
3a4433d5a2 | ||
|
|
de6c45ad24 | ||
|
|
fadade8592 | ||
|
|
d91044f3a2 | ||
|
|
a3ea37b76e | ||
|
|
ec63cadadb | ||
|
|
84d8305730 | ||
|
|
73777980f1 | ||
|
|
75788b1148 | ||
|
|
dd9b2ddc89 | ||
|
|
b7ddd09fab | ||
|
|
48ffcbd2c4 | ||
|
|
68d3ac567c | ||
|
|
50ab289da6 | ||
|
|
4e079fdd08 | ||
|
|
91fc9e3118 | ||
|
|
a2f0401c4c | ||
|
|
1b85828548 | ||
|
|
4c46e5e1a3 | ||
|
|
4da9e7ee29 | ||
|
|
72e615aa7a | ||
|
|
cd02abc481 | ||
|
|
399ab328d8 | ||
|
|
809ec2ce01 | ||
|
|
11d2cf0d60 | ||
|
|
dbb2624403 | ||
|
|
4d4fa77459 | ||
|
|
3145794084 | ||
|
|
d9b69bd1a0 | ||
|
|
7cd635fa84 | ||
|
|
ce40e201f0 | ||
|
|
404f3ef465 | ||
|
|
e1be594fdd | ||
|
|
9569c9a9e7 | ||
|
|
91530f5716 | ||
|
|
650b1dee54 | ||
|
|
6b6dc9dd48 | ||
|
|
3a9ec4192d | ||
|
|
4f7dbbd2c3 | ||
|
|
8c37db1a23 | ||
|
|
c6b7ad8878 | ||
|
|
84461c20cb | ||
|
|
3cddda56fc | ||
|
|
37f3069a67 | ||
|
|
2b2fbe918e | ||
|
|
cf42ddc449 | ||
|
|
eefa656232 | ||
|
|
249ad44cc0 | ||
|
|
54804e344d | ||
|
|
1c334de6fd | ||
|
|
f253103a31 | ||
|
|
1120db57a6 | ||
|
|
afa661cff4 | ||
|
|
347f30bd86 | ||
|
|
127773f3f5 | ||
|
|
8d0490bd70 | ||
|
|
293dfb35d5 | ||
|
|
81be404487 | ||
|
|
6177b6e126 | ||
|
|
79cc657917 | ||
|
|
7928122fce | ||
|
|
9c88ea9126 | ||
|
|
2b766ef9f9 | ||
|
|
bd3d9ac9d5 | ||
|
|
aa0db8379c | ||
|
|
eadd41a9ec | ||
|
|
fab2eb9833 | ||
|
|
6bd791f2f4 | ||
|
|
ec5f80dce1 | ||
|
|
65cdc856ae | ||
|
|
472f61485e | ||
|
|
b4de659438 | ||
|
|
a37a8818c8 | ||
|
|
bdf01aa174 | ||
|
|
a941c69f09 | ||
|
|
72aaa15e6a | ||
|
|
3a06de71a8 | ||
|
|
5e2b39a5c1 | ||
|
|
63c942233e | ||
|
|
2612edc133 | ||
|
|
e2ce9f42b5 | ||
|
|
1c6f7e4b7b | ||
|
|
e2c41903ad | ||
|
|
bd48544e25 | ||
|
|
c0e3daacaf | ||
|
|
f2ad3a6a0b | ||
|
|
caf921a01f | ||
|
|
b790bafc02 | ||
|
|
ad3cd54cce | ||
|
|
1a6a725f88 | ||
|
|
1ad20d94ff | ||
|
|
995c6f0fb1 | ||
|
|
c3e7b83178 | ||
|
|
2e93a588e0 | ||
|
|
9aeca3f97e | ||
|
|
2193fff4bb | ||
|
|
aec2c65c63 | ||
|
|
a6509cc4d5 | ||
|
|
a02b279750 | ||
|
|
ece841f5ce | ||
|
|
2a6e4dc8a6 | ||
|
|
c163011cc0 | ||
|
|
b350945a16 | ||
|
|
1ef368a69d | ||
|
|
8dc587b01a | ||
|
|
550c4293ed | ||
|
|
3df094713f | ||
|
|
01e7f27aa6 | ||
|
|
8d62a99637 | ||
|
|
ab9995e76e | ||
|
|
bef39b1259 | ||
|
|
0d894e6ff7 | ||
|
|
be9510539e | ||
|
|
3bce2ef8d6 | ||
|
|
aa9a943ddf | ||
|
|
ebdb66c7bf | ||
|
|
9f3e8c2dde | ||
|
|
96c56ab08a | ||
|
|
04dbf03ace | ||
|
|
05a753fe63 | ||
|
|
815edb7003 | ||
|
|
5157f56875 | ||
|
|
3f5abca215 | ||
|
|
833df0b8b3 | ||
|
|
6742860ea5 | ||
|
|
797e6d45c0 | ||
|
|
320de0d921 | ||
|
|
5eed505d74 | ||
|
|
91ee27f22b | ||
|
|
5f7c89f85d | ||
|
|
c6712dfccd | ||
|
|
baf4ba175b | ||
|
|
b29ea17ea9 | ||
|
|
ab57c26cf9 | ||
|
|
98e5e8835e | ||
|
|
f5158ece1a | ||
|
|
d65b4a9a93 | ||
|
|
8404947bc0 | ||
|
|
2e84f34cf3 | ||
|
|
726805f064 | ||
|
|
b4a4138559 | ||
|
|
f1d2b3a39a | ||
|
|
1f9d006858 | ||
|
|
cc266d7d80 | ||
|
|
fff72afe2e | ||
|
|
c1abd13b5c | ||
|
|
75802c14b2 | ||
|
|
cddc1e86e7 | ||
|
|
24ea42ce61 | ||
|
|
6102e612fa | ||
|
|
52bde71166 | ||
|
|
15a79cfe9c | ||
|
|
15e71535f3 | ||
|
|
9f988bfe29 | ||
|
|
e8d1baa4b5 | ||
|
|
8bbe4ff138 | ||
|
|
0b9220c1fc | ||
|
|
0d65753fdb | ||
|
|
4f1374a6e7 | ||
|
|
5a0521e92c | ||
|
|
fea86c29d6 | ||
|
|
9c4614f7e6 | ||
|
|
c24a78ae94 | ||
|
|
621816fb56 | ||
|
|
cfae54d361 | ||
|
|
7857b0a689 | ||
|
|
10965920fb | ||
|
|
d2e7ecabd8 | ||
|
|
5772589dc3 | ||
|
|
6df08b411b | ||
|
|
c355ac6593 | ||
|
|
e9b42bbc2a | ||
|
|
1283aa3bd8 | ||
|
|
ff6cba7205 | ||
|
|
d0107f7921 | ||
|
|
644c49f1e0 | ||
|
|
a303d508cf | ||
|
|
44d39112ff | ||
|
|
28020d0c54 | ||
|
|
0ef95947cc | ||
|
|
4ac70a99ae | ||
|
|
bcf14cf677 | ||
|
|
1dae782cd4 | ||
|
|
90cfb6ff28 | ||
|
|
26110da7ca | ||
|
|
30644c9a06 | ||
|
|
033bf1198f | ||
|
|
cdc7d92e57 | ||
|
|
af0e3b8f17 | ||
|
|
04f1d079aa | ||
|
|
9b6c629397 | ||
|
|
5aa467bef2 | ||
|
|
af7ad27f89 | ||
|
|
d6d57bfbb8 | ||
|
|
4f4cfcf3c3 | ||
|
|
fa9f522b7f | ||
|
|
838f9f3008 | ||
|
|
96347df9df | ||
|
|
9334783da3 | ||
|
|
964b2a331d | ||
|
|
95ccd92616 | ||
|
|
197d3a3d89 | ||
|
|
a7ddd747ca | ||
|
|
d61b4e5a13 | ||
|
|
68e646f8aa | ||
|
|
21bfb2d477 | ||
|
|
a9dae71188 | ||
|
|
dd84cc5fd4 | ||
|
|
51631f4c2e | ||
|
|
535a8c8243 | ||
|
|
7abfbd23d0 | ||
|
|
633c00cf80 | ||
|
|
0c12fa31c5 | ||
|
|
5643ef05bc | ||
|
|
f38f42f17d | ||
|
|
472d8592d6 | ||
|
|
4fb230daf1 | ||
|
|
e6bde22f9c | ||
|
|
cc5b9b772a | ||
|
|
ded1474bbb | ||
|
|
2b1fb2b739 | ||
|
|
18e0bfef1d | ||
|
|
3be760dc38 | ||
|
|
29dd0b1e41 | ||
|
|
e1fdfbb062 | ||
|
|
89c07b5e43 | ||
|
|
9b5350eab1 | ||
|
|
5382cd696a | ||
|
|
69fc9ce10e | ||
|
|
13ac6f38dc | ||
|
|
2ec0bdfd99 | ||
|
|
c03e1e6c6c | ||
|
|
2a682abeef | ||
|
|
9f38b54a2d | ||
|
|
2933f51949 | ||
|
|
a75300b8c7 | ||
|
|
01f4bb86c3 | ||
|
|
79c3ada49b | ||
|
|
ac276d06fa | ||
|
|
c7eabe61bb | ||
|
|
8f28bcf704 | ||
|
|
be3b289a10 | ||
|
|
19a0c1f3cb | ||
|
|
dc94fcc6e8 | ||
|
|
183237c858 | ||
|
|
599a44f90f | ||
|
|
08e9c7aa2f | ||
|
|
a893d04e81 | ||
|
|
5996bd57ea | ||
|
|
909b297ae3 | ||
|
|
abdc3b2211 | ||
|
|
e66d2085b7 | ||
|
|
4a5e48e88f | ||
|
|
3a586a0c19 | ||
|
|
144dec3fd3 | ||
|
|
448d116a89 | ||
|
|
8493e5d09f | ||
|
|
83e7365fd8 | ||
|
|
b6040e6061 | ||
|
|
858b9a5119 | ||
|
|
00fbcd14f7 | ||
|
|
062f18d353 | ||
|
|
58760bce54 | ||
|
|
ca4f026074 | ||
|
|
f285ac2281 | ||
|
|
0f3db4dbb9 | ||
|
|
18b2d451cd | ||
|
|
b6dd1af7d2 | ||
|
|
303c8ee7cd | ||
|
|
98d6b15fc0 | ||
|
|
77f407dd5f | ||
|
|
a12a3ef08b | ||
|
|
6480fcaf7c | ||
|
|
f5cb439fe6 | ||
|
|
15c9e85690 | ||
|
|
8f8a85303b | ||
|
|
114cc2db21 | ||
|
|
bec97b6c76 | ||
|
|
114b54cbdb | ||
|
|
0f16463794 | ||
|
|
8ff5fde88e | ||
|
|
3286c5ec19 | ||
|
|
ee7cdc66b3 | ||
|
|
9699da4968 | ||
|
|
6bb0b48b10 | ||
|
|
70da09eae2 | ||
|
|
101072ab9f | ||
|
|
47f7672c03 | ||
|
|
dd54ccf677 | ||
|
|
66ec916b3d | ||
|
|
b4062ef699 | ||
|
|
2d3816341e | ||
|
|
d1054cd596 | ||
|
|
81f8c2f83c | ||
|
|
3144d3ae63 | ||
|
|
9642f5a3f6 | ||
|
|
c4853ee6bb | ||
|
|
1cc40bc9ce | ||
|
|
38a615f407 | ||
|
|
4f2468e14f | ||
|
|
8f7b5bd00e | ||
|
|
4821a8be94 | ||
|
|
523d18b873 | ||
|
|
c52be7dfcb | ||
|
|
c2bfcf1c54 | ||
|
|
bb5f404e35 | ||
|
|
106dbbc341 | ||
|
|
4b6540c71a | ||
|
|
816b1f5e85 | ||
|
|
9f61db5dbe | ||
|
|
e823bef970 | ||
|
|
f9ccc6a289 | ||
|
|
b32a666541 | ||
|
|
b636825de3 | ||
|
|
ddd98ad75d | ||
|
|
d355927024 | ||
|
|
75c0053bb1 | ||
|
|
55a9284665 | ||
|
|
113cdae2d4 | ||
|
|
c6295ade33 | ||
|
|
e1e453075f | ||
|
|
9ca08b8f2b | ||
|
|
f47d3f422d | ||
|
|
e6bd8021d9 | ||
|
|
307252e9ae | ||
|
|
bb2ca25110 | ||
|
|
9e4fb1009f | ||
|
|
8ad5f9bf53 | ||
|
|
02a2fe4871 | ||
|
|
40741c5b0b | ||
|
|
0dd1c6ca6b | ||
|
|
5563adbb89 | ||
|
|
524e17df10 | ||
|
|
73e848e96f | ||
|
|
5f0806967c | ||
|
|
173bb14140 | ||
|
|
918f310674 | ||
|
|
a75fdbd8ad | ||
|
|
9d3f189b0e | ||
|
|
7e79c51222 | ||
|
|
a180d831a1 | ||
|
|
e81adc2752 | ||
|
|
500422d594 | ||
|
|
0311c03735 | ||
|
|
df81141d6f | ||
|
|
cce6a44277 | ||
|
|
7479a4737b | ||
|
|
06ef4cc654 | ||
|
|
c7c3130507 | ||
|
|
010a045692 | ||
|
|
51666609f1 | ||
|
|
10967bce57 | ||
|
|
763aa6e378 | ||
|
|
d6c0a688e6 | ||
|
|
9f75554f2a | ||
|
|
2b20c8a0f5 | ||
|
|
1b4590b42b | ||
|
|
09e89bbcd3 | ||
|
|
7c4b1f910c | ||
|
|
3ceabe91f8 | ||
|
|
a39ffb2fb8 | ||
|
|
41f989135d | ||
|
|
f6cffc7e48 | ||
|
|
1da84b5f7c | ||
|
|
ebfe76cdb6 | ||
|
|
c301814d68 | ||
|
|
09478571df | ||
|
|
a901499ede | ||
|
|
de65026db0 | ||
|
|
071b51d588 | ||
|
|
80390d8a03 | ||
|
|
9590082848 | ||
|
|
9cfb617d5b | ||
|
|
b66e2e0962 | ||
|
|
32721bbc83 | ||
|
|
19fb1c240c | ||
|
|
630ff0e00b | ||
|
|
964c974a02 | ||
|
|
c9e4f2cfb4 | ||
|
|
a3a554aeed | ||
|
|
6c3cc2caf5 | ||
|
|
5999acd24a | ||
|
|
59f56b24d9 | ||
|
|
abd0ec379c | ||
|
|
cfb98a5617 | ||
|
|
fafcffed25 | ||
|
|
3f1209ce19 | ||
|
|
b217961254 | ||
|
|
cd06b39a42 | ||
|
|
84e1f85be2 | ||
|
|
f060f099d4 | ||
|
|
e093af4c05 | ||
|
|
eface5ef45 | ||
|
|
5b72f478a7 | ||
|
|
5f5a0465cb | ||
|
|
f509e479a1 | ||
|
|
ad00c2cf51 | ||
|
|
a20f80623e | ||
|
|
f26dca6d8e | ||
|
|
9ea089a5d9 | ||
|
|
f07d1c9488 | ||
|
|
0d0c79a5cb | ||
|
|
9bb5aa583f | ||
|
|
f26ed591f3 | ||
|
|
0b4576a028 | ||
|
|
d7bb220ba3 | ||
|
|
f907c710b2 | ||
|
|
c6bcb319f8 | ||
|
|
443600194c | ||
|
|
7b6f14c25a | ||
|
|
887d919323 | ||
|
|
74d32f0cca | ||
|
|
3f479be7e7 | ||
|
|
95d02a23d0 | ||
|
|
8b59b9852f | ||
|
|
53bda94f77 | ||
|
|
52580cfd0d | ||
|
|
cf3d5b44e6 | ||
|
|
491dc2e5ca | ||
|
|
b89cdef120 | ||
|
|
348fe339b9 | ||
|
|
e79d7ea981 | ||
|
|
e7841ba2ed | ||
|
|
37687e9323 | ||
|
|
b749314944 | ||
|
|
3eb0fb5aa6 | ||
|
|
44a4cf3b27 | ||
|
|
9a8762ba6e | ||
|
|
2e1bd5ef4e | ||
|
|
a9dc101701 | ||
|
|
e2835de137 | ||
|
|
535e7a6a28 | ||
|
|
fe96de2e2d | ||
|
|
9fd881443f | ||
|
|
2ff3f7ae13 | ||
|
|
2b80f6ed41 | ||
|
|
3ab084a421 | ||
|
|
495174ff7c | ||
|
|
b049fa2c84 | ||
|
|
052f0aa7d4 | ||
|
|
60393999b8 | ||
|
|
b3a3351e8e | ||
|
|
86b5c08b9b | ||
|
|
dab90f7b91 | ||
|
|
71d31256a6 | ||
|
|
3b6d5c3aaa | ||
|
|
7ce42941ea | ||
|
|
3f8171475c | ||
|
|
b135b589e0 | ||
|
|
05ca3d77f7 | ||
|
|
6deee7e3e9 | ||
|
|
9dc404077a | ||
|
|
30e6af6069 | ||
|
|
9788496a85 | ||
|
|
6d3a412d47 | ||
|
|
700b236f4d | ||
|
|
bc22ec382f | ||
|
|
135e5d47a7 | ||
|
|
0f8001ea44 | ||
|
|
5b6e23c323 | ||
|
|
29b30ec946 | ||
|
|
76be5e4e99 |
940
.all-contributorsrc
Normal file
940
.all-contributorsrc
Normal file
@@ -0,0 +1,940 @@
|
||||
{
|
||||
"files": [
|
||||
"README.md"
|
||||
],
|
||||
"imageSize": 100,
|
||||
"commit": false,
|
||||
"contributors": [
|
||||
{
|
||||
"login": "carols10cents",
|
||||
"name": "Carol (Nichols || Goulding)",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/193874?v=4",
|
||||
"profile": "http://carol-nichols.com",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "QuietMisdreavus",
|
||||
"name": "QuietMisdreavus",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/5217170?v=4",
|
||||
"profile": "https://twitter.com/QuietMisdreavus",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "robertlugg",
|
||||
"name": "Robert M Lugg",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/6054540?v=4",
|
||||
"profile": "https://github.com/robertlugg",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hynek",
|
||||
"name": "Hynek Schlawack",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/41240?v=4",
|
||||
"profile": "https://hynek.me/about/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "spacekookie",
|
||||
"name": "Katharina Fey",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/7669898?v=4",
|
||||
"profile": "https://spacekookie.de",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lukabavdaz",
|
||||
"name": "lukabavdaz",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/9624558?v=4",
|
||||
"profile": "https://github.com/lukabavdaz",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "evestera",
|
||||
"name": "Erik Vesteraas",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/4187449?v=4",
|
||||
"profile": "http://vestera.as",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Delet0r",
|
||||
"name": "delet0r",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/23195618?v=4",
|
||||
"profile": "https://github.com/Delet0r",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "shaunbennett",
|
||||
"name": "Shaun Bennett",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/10522375?v=4",
|
||||
"profile": "http://phinary.ca",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "abagshaw",
|
||||
"name": "Andrew Bagshaw",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/8594541?v=4",
|
||||
"profile": "https://github.com/abagshaw",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kisom",
|
||||
"name": "Kyle Isom",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/175578?v=4",
|
||||
"profile": "https://ai6ua.net/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ColinPitrat",
|
||||
"name": "Colin Pitrat",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/1541863?v=4",
|
||||
"profile": "https://github.com/ColinPitrat",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "zacanger",
|
||||
"name": "Zac Anger",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/12520493?v=4",
|
||||
"profile": "https://zacanger.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "mgeier",
|
||||
"name": "Matthias Geier",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/705404?v=4",
|
||||
"profile": "https://github.com/mgeier",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cjpearce",
|
||||
"name": "Chris Pearce",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/3453268?v=4",
|
||||
"profile": "https://github.com/cjpearce",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "yvan-sraka",
|
||||
"name": "Yvan Sraka",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/705213?v=4",
|
||||
"profile": "https://yvan-sraka.github.io",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dendi239",
|
||||
"name": "Denys Smirnov",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/16478650?v=4",
|
||||
"profile": "https://github.com/dendi239",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "eddyp",
|
||||
"name": "eddyp",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/123772?v=4",
|
||||
"profile": "https://github.com/eddyp",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "briankung",
|
||||
"name": "Brian Kung",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/2836167?v=4",
|
||||
"profile": "http://about.me/BrianKung",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "miller-time",
|
||||
"name": "Russell",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/281039?v=4",
|
||||
"profile": "https://rcousineau.gitlab.io",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "danwilhelm",
|
||||
"name": "Dan Wilhelm",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/6137185?v=4",
|
||||
"profile": "http://danwilhelm.com",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Jesse-Cameron",
|
||||
"name": "Jesse",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/3723654?v=4",
|
||||
"profile": "https://github.com/Jesse-Cameron",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "MrFroop",
|
||||
"name": "Fredrik Jambrén",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/196700?v=4",
|
||||
"profile": "https://github.com/MrFroop",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "petemcfarlane",
|
||||
"name": "Pete McFarlane",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/3472717?v=4",
|
||||
"profile": "https://github.com/petemcfarlane",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nkanderson",
|
||||
"name": "nkanderson",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/4128825?v=4",
|
||||
"profile": "https://github.com/nkanderson",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ajaxm",
|
||||
"name": "Ajax M",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/13360138?v=4",
|
||||
"profile": "https://github.com/ajaxm",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Dylnuge",
|
||||
"name": "Dylan Nugent",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/118624?v=4",
|
||||
"profile": "https://dylnuge.com",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "vyaslav",
|
||||
"name": "vyaslav",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/1385427?v=4",
|
||||
"profile": "https://github.com/vyaslav",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "gdoenlen",
|
||||
"name": "George",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/17297466?v=4",
|
||||
"profile": "https://join.sfxd.org",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nyxtom",
|
||||
"name": "Thomas Holloway",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/222763?v=4",
|
||||
"profile": "https://github.com/nyxtom",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "workingjubilee",
|
||||
"name": "Jubilee",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/46493976?v=4",
|
||||
"profile": "https://github.com/workingjubilee",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "WofWca",
|
||||
"name": "WofWca",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/39462442?v=4",
|
||||
"profile": "https://github.com/WofWca",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jrvidal",
|
||||
"name": "Roberto Vidal",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/1636604?v=4",
|
||||
"profile": "https://github.com/jrvidal",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc",
|
||||
"ideas",
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jensim",
|
||||
"name": "Jens",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/3663856?v=4",
|
||||
"profile": "https://github.com/jensim",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "rahatarmanahmed",
|
||||
"name": "Rahat Ahmed",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/3174006?v=4",
|
||||
"profile": "http://rahatah.me/d",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AbdouSeck",
|
||||
"name": "Abdou Seck",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/6490055?v=4",
|
||||
"profile": "https://github.com/AbdouSeck",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "codehearts",
|
||||
"name": "Katie",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/2885412?v=4",
|
||||
"profile": "https://codehearts.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Socratides",
|
||||
"name": "Socrates",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/27732983?v=4",
|
||||
"profile": "https://github.com/Socratides",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "gnodarse",
|
||||
"name": "gnodarse",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/46761795?v=4",
|
||||
"profile": "https://github.com/gnodarse",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "harrisonmetz",
|
||||
"name": "Harrison Metzger",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/7883408?v=4",
|
||||
"profile": "https://github.com/harrisonmetz",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "TorbenJ",
|
||||
"name": "Torben Jonas",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/9077102?v=4",
|
||||
"profile": "https://github.com/TorbenJ",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "pbx",
|
||||
"name": "Paul Bissex",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/641?v=4",
|
||||
"profile": "http://paulbissex.com/",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sjmann",
|
||||
"name": "Steven Mann",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/6589896?v=4",
|
||||
"profile": "https://github.com/sjmann",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Tarnadas",
|
||||
"name": "Mario Reder",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/5855071?v=4",
|
||||
"profile": "https://smmdb.net/",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sl4m",
|
||||
"name": "skim",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/47347?v=4",
|
||||
"profile": "https://keybase.io/skim",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sanjaykdragon",
|
||||
"name": "Sanjay K",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/10261698?v=4",
|
||||
"profile": "https://github.com/sanjaykdragon",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "crodjer",
|
||||
"name": "Rohan Jain",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/343499?v=4",
|
||||
"profile": "http://www.rohanjain.in",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "saidaspen",
|
||||
"name": "Said Aspen",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/7727687?v=4",
|
||||
"profile": "https://www.saidaspen.se",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "uce",
|
||||
"name": "Ufuk Celebi",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/1756620?v=4",
|
||||
"profile": "https://github.com/uce",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lebedevsergey",
|
||||
"name": "lebedevsergey",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/7325764?v=4",
|
||||
"profile": "https://github.com/lebedevsergey",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "avrong",
|
||||
"name": "Aleksei Trifonov",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/6342851?v=4",
|
||||
"profile": "https://github.com/avrong",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Darrenmeehan",
|
||||
"name": "Darren Meehan",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/411136?v=4",
|
||||
"profile": "https://drn.ie",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jihchi",
|
||||
"name": "Jihchi Lee",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/87983?v=4",
|
||||
"profile": "https://github.com/jihchi",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "bertonha",
|
||||
"name": "Christofer Bertonha",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/1225902?v=4",
|
||||
"profile": "https://github.com/bertonha",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "apatniv",
|
||||
"name": "Vivek Bharath Akupatni",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/22565917?v=4",
|
||||
"profile": "https://github.com/apatniv",
|
||||
"contributions": [
|
||||
"code",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "DiD92",
|
||||
"name": "Dídac Sementé Fernández",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/6002416?v=4",
|
||||
"profile": "https://github.com/DiD92",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "wrobstory",
|
||||
"name": "Rob Story",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/2601457?v=4",
|
||||
"profile": "https://github.com/wrobstory",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "siobhanjacobson",
|
||||
"name": "Siobhan Jacobson",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/28983835?v=4",
|
||||
"profile": "https://github.com/siobhanjacobson",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "EvanCarroll",
|
||||
"name": "Evan Carroll",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/19922?v=4",
|
||||
"profile": "https://www.linkedin.com/in/evancarroll/",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jmahmood",
|
||||
"name": "Jawaad Mahmood",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/95606?v=4",
|
||||
"profile": "http://www.jawaadmahmood.com",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "GaurangTandon",
|
||||
"name": "Gaurang Tandon",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/6308683?v=4",
|
||||
"profile": "https://github.com/GaurangTandon",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dev-cyprium",
|
||||
"name": "Stefan Kupresak",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/6002628?v=4",
|
||||
"profile": "https://github.com/dev-cyprium",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "greg-el",
|
||||
"name": "Greg Leonard",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/45019882?v=4",
|
||||
"profile": "https://github.com/greg-el",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ryanpcmcquen",
|
||||
"name": "Ryan McQuen",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/772937?v=4",
|
||||
"profile": "https://ryanpcmcquen.org",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "AnnikaCodes",
|
||||
"name": "Annika",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/56906084?v=4",
|
||||
"profile": "https://github.com/AnnikaCodes",
|
||||
"contributions": [
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "darnuria",
|
||||
"name": "Axel Viala",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/2827553?v=4",
|
||||
"profile": "https://darnuria.eu",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sazid",
|
||||
"name": "Mohammed Sazid Al Rashid",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/2370167?v=4",
|
||||
"profile": "https://sazid.github.io",
|
||||
"contributions": [
|
||||
"content",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "seeplusplus",
|
||||
"name": "Caleb Webber",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/17479099?v=4",
|
||||
"profile": "https://codingthemsoftly.com",
|
||||
"contributions": [
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "pcn",
|
||||
"name": "Peter N",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1056756?v=4",
|
||||
"profile": "https://github.com/pcn",
|
||||
"contributions": [
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "seancad",
|
||||
"name": "seancad",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/47405611?v=4",
|
||||
"profile": "https://github.com/seancad",
|
||||
"contributions": [
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "wsh",
|
||||
"name": "Will Hayworth",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/181174?v=4",
|
||||
"profile": "http://willhayworth.com",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "chrizel",
|
||||
"name": "Christian Zeller",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/20802?v=4",
|
||||
"profile": "https://github.com/chrizel",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jfchevrette",
|
||||
"name": "Jean-Francois Chevrette",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3001?v=4",
|
||||
"profile": "https://github.com/jfchevrette",
|
||||
"contributions": [
|
||||
"content",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jbaber",
|
||||
"name": "John Baber-Lucero",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1908117?v=4",
|
||||
"profile": "https://github.com/jbaber",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "tal-zvon",
|
||||
"name": "Tal",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3195851?v=4",
|
||||
"profile": "https://github.com/tal-zvon",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "apogeeoak",
|
||||
"name": "apogeeoak",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/59737221?v=4",
|
||||
"profile": "https://github.com/apogeeoak",
|
||||
"contributions": [
|
||||
"content",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Crell",
|
||||
"name": "Larry Garfield",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/254863?v=4",
|
||||
"profile": "http://www.garfieldtech.com/",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "circumspect",
|
||||
"name": "circumspect",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/40770208?v=4",
|
||||
"profile": "https://github.com/circumspect",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cjwyett",
|
||||
"name": "Cyrus Wyett",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/34195737?v=4",
|
||||
"profile": "https://github.com/cjwyett",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cadolphs",
|
||||
"name": "cadolphs",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/13894820?v=4",
|
||||
"profile": "https://github.com/cadolphs",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hpwxf",
|
||||
"name": "Pascal H.",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/26146722?v=4",
|
||||
"profile": "https://www.haveneer.com",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "chapeupreto",
|
||||
"name": "Rod Elias",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/834048?v=4",
|
||||
"profile": "https://twitter.com/chapeupreto",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "blerchy",
|
||||
"name": "Matt Lebl",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/2555355?v=4",
|
||||
"profile": "https://github.com/blerchy",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "flakolefluk",
|
||||
"name": "Ignacio Le Fluk",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/11986564?v=4",
|
||||
"profile": "http://flakolefluk.dev",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "tlyu",
|
||||
"name": "Taylor Yu",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/431873?v=4",
|
||||
"profile": "https://github.com/tlyu",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Zerotask",
|
||||
"name": "Patrick Hintermayer",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/20150243?v=4",
|
||||
"profile": "https://zerotask.github.io",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "arthas168",
|
||||
"name": "Pete Pavlovski",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/32264020?v=4",
|
||||
"profile": "https://petkopavlovski.com/",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "k12ish",
|
||||
"name": "k12ish",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/45272873?v=4",
|
||||
"profile": "https://github.com/k12ish",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hongshaoyang",
|
||||
"name": "Shao Yang Hong",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19281800?v=4",
|
||||
"profile": "https://github.com/hongshaoyang",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "bmacer",
|
||||
"name": "Brandon Macer",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/13931806?v=4",
|
||||
"profile": "https://github.com/bmacer",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "stoiandan",
|
||||
"name": "Stoian Dan",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10388612?v=4",
|
||||
"profile": "https://github.com/stoiandan",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "PiDelport",
|
||||
"name": "Pi Delport",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/630271?v=4",
|
||||
"profile": "https://about.me/pjdelport",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sateeshkumarb",
|
||||
"name": "Sateesh ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/429263?v=4",
|
||||
"profile": "https://github.com/sateeshkumarb",
|
||||
"contributions": [
|
||||
"code",
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kayuapi",
|
||||
"name": "ZC",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10304328?v=4",
|
||||
"profile": "https://github.com/kayuapi",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hyperparabolic",
|
||||
"name": "hyperparabolic",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/12348474?v=4",
|
||||
"profile": "https://github.com/hyperparabolic",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kolbma",
|
||||
"name": "arlecchino",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5228369?v=4",
|
||||
"profile": "https://www.net4visions.at",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jazzplato",
|
||||
"name": "Richthofen",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/7576730?v=4",
|
||||
"profile": "https://richthofen.io/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cseltol",
|
||||
"name": "Ivan Nerazumov",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/64264529?v=4",
|
||||
"profile": "https://github.com/cseltol",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lauralindzey",
|
||||
"name": "lauralindzey",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/65185744?v=4",
|
||||
"profile": "https://github.com/lauralindzey",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sinharaksh1t",
|
||||
"name": "Rakshit Sinha",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/28585848?v=4",
|
||||
"profile": "https://github.com/sinharaksh1t",
|
||||
"contributions": [
|
||||
"content"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 8,
|
||||
"projectName": "rustlings",
|
||||
"projectOwner": "rust-lang",
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"skipCi": true
|
||||
}
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,3 +5,5 @@ target/
|
||||
*.pdb
|
||||
exercises/clippy/Cargo.toml
|
||||
exercises/clippy/Cargo.lock
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
7
.gitpod.yml
Normal file
7
.gitpod.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
tasks:
|
||||
- init: /workspace/rustlings/install.sh
|
||||
command: /workspace/.cargo/bin/rustlings watch
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- rust-lang.rust@0.7.8:CvNqMTgDdt3UXt+6BCDTVg==
|
||||
2
.replit
Normal file
2
.replit
Normal file
@@ -0,0 +1,2 @@
|
||||
language = "rust"
|
||||
run = "[ -x ~/.cargo/bin/rustlings ] && ~/.cargo/bin/rustlings watch || ./install.sh"
|
||||
11
.travis.yml
11
.travis.yml
@@ -1,11 +0,0 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
script: cargo test --verbose
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
fast_finish: true
|
||||
cache: cargo
|
||||
205
CHANGELOG.md
205
CHANGELOG.md
@@ -1,3 +1,204 @@
|
||||
<a name="4.5.0"></a>
|
||||
## 4.5.0 (2021-07-07)
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* Add move_semantics5 exercise. (#746) ([399ab328](https://github.com/rust-lang/rustlings/commit/399ab328d8d407265c09563aa4ef4534b2503ff2))
|
||||
* **cli:** Add "next" to run the next unsolved exercise. (#785) ([d20e413a](https://github.com/rust-lang/rustlings/commit/d20e413a68772cd493561f2651cf244e822b7ca5))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* rename result1 to errors4 ([50ab289d](https://github.com/rust-lang/rustlings/commit/50ab289da6b9eb19a7486c341b00048c516b88c0))
|
||||
* move_semantics5 hints ([1b858285](https://github.com/rust-lang/rustlings/commit/1b85828548f46f58b622b5e0c00f8c989f928807))
|
||||
* remove trailing whitespaces from iterators1 ([4d4fa774](https://github.com/rust-lang/rustlings/commit/4d4fa77459392acd3581c6068aa8be9a02de12fc))
|
||||
* add hints to generics1 and generics2 exercises ([31457940](https://github.com/rust-lang/rustlings/commit/31457940846b3844d78d4a4d2b074bc8d6aaf1eb))
|
||||
* remove trailing whitespace ([d9b69bd1](https://github.com/rust-lang/rustlings/commit/d9b69bd1a0a7a99f2c0d80933ad2eea44c8c71b2))
|
||||
* **installation:** first PowerShell command ([aa9a943d](https://github.com/rust-lang/rustlings/commit/aa9a943ddf3ae260782e73c26bcc9db60e5894b6))
|
||||
* **iterators5:** derive Clone, Copy ([91fc9e31](https://github.com/rust-lang/rustlings/commit/91fc9e3118f4af603c9911698cc2a234725cb032))
|
||||
* **quiz1:** Updated question description (#794) ([d8766496](https://github.com/rust-lang/rustlings/commit/d876649616cc8a8dd5f539f8bc1a5434b960b1e9))
|
||||
* **try_from_into, from_str:** hints for dyn Error ([11d2cf0d](https://github.com/rust-lang/rustlings/commit/11d2cf0d604dee3f5023c17802d69438e69fa50e))
|
||||
* **variables5:** confine the answer further ([48ffcbd2](https://github.com/rust-lang/rustlings/commit/48ffcbd2c4cc4d936c2c7480019190f179813cc5))
|
||||
|
||||
|
||||
|
||||
<a name="4.4.0"></a>
|
||||
## 4.4.0 (2021-04-24)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Fix spelling error in main.rs ([91ee27f2](https://github.com/rust-lang/rustlings/commit/91ee27f22bd3797a9db57e5fd430801c170c5db8))
|
||||
* typo in default out text ([644c49f1](https://github.com/rust-lang/rustlings/commit/644c49f1e04cbb24e95872b3a52b07d692ae3bc8))
|
||||
* **collections:** Naming exercises for vectors and hashmap ([bef39b12](https://github.com/rust-lang/rustlings/commit/bef39b125961310b34b34871e480a82e82af4678))
|
||||
* **from_str:**
|
||||
* Correct typos ([5f7c89f8](https://github.com/rust-lang/rustlings/commit/5f7c89f85db1f33da01911eaa479c3a2d4721678))
|
||||
* test for error instead of unwrap/should_panic ([15e71535](https://github.com/rust-lang/rustlings/commit/15e71535f37cfaed36e22eb778728d186e2104ab))
|
||||
* use trait objects for from_str ([c3e7b831](https://github.com/rust-lang/rustlings/commit/c3e7b831786c9172ed8bd5d150f3c432f242fba9))
|
||||
* **functions3:** improve function argument type (#687) ([a6509cc4](https://github.com/rust-lang/rustlings/commit/a6509cc4d545d8825f01ddf7ee37823b372154dd))
|
||||
* **hashmap2:** Update incorrect assertion (#660) ([72aaa15e](https://github.com/rust-lang/rustlings/commit/72aaa15e6ab4b72b3422f1c6356396e20a2a2bb8))
|
||||
* **info:** Fix typo (#635) ([cddc1e86](https://github.com/rust-lang/rustlings/commit/cddc1e86e7ec744ee644cc774a4887b1a0ded3e8))
|
||||
* **iterators2:** Moved errors out of tests. ([baf4ba17](https://github.com/rust-lang/rustlings/commit/baf4ba175ba6eb92989e3dd54ecbec4bedc9a863), closes [#359](https://github.com/rust-lang/rustlings/issues/359))
|
||||
* **iterators3:** Enabled iterators3.rs to run without commented out tests. ([c6712dfc](https://github.com/rust-lang/rustlings/commit/c6712dfccd1a093e590ad22bbc4f49edc417dac0))
|
||||
* **main:** Let find_exercise work with borrows ([347f30bd](https://github.com/rust-lang/rustlings/commit/347f30bd867343c5ace1097e085a1f7e356553f7))
|
||||
* **move_semantics4:**
|
||||
* Remove redundant "instead" (#640) ([cc266d7d](https://github.com/rust-lang/rustlings/commit/cc266d7d80b91e79df3f61984f231b7f1587218e))
|
||||
* Small readbility improvement (#617) ([10965920](https://github.com/rust-lang/rustlings/commit/10965920fbdf8a1efc85bed869e55a1787006404))
|
||||
* **option2:** Rename uninformative variables (#675) ([b4de6594](https://github.com/rust-lang/rustlings/commit/b4de6594380636817d13c2677ec6f472a964cf43))
|
||||
* **quiz3:** Force an answer to Q2 (#672) ([0d894e6f](https://github.com/rust-lang/rustlings/commit/0d894e6ff739943901e1ae8c904582e5c2f843bd))
|
||||
* **structs:** Add 5.3 to structs/README (#652) ([6bd791f2](https://github.com/rust-lang/rustlings/commit/6bd791f2f44aa7f0ad926df767f6b1fa8f12a9a9))
|
||||
* **structs2:** correct grammar in hint (#663) ([ebdb66c7](https://github.com/rust-lang/rustlings/commit/ebdb66c7bfb6d687a14cc511a559a222e6fc5de4))
|
||||
* **structs3:**
|
||||
* reword heading comment (#664) ([9f3e8c2d](https://github.com/rust-lang/rustlings/commit/9f3e8c2dde645e5264c2d2200e68842b5f47bfa3))
|
||||
* add check to prevent naive implementation of is_international ([05a753fe](https://github.com/rust-lang/rustlings/commit/05a753fe6333d36dbee5f68c21dec04eacdc75df))
|
||||
* **threads1:** line number correction ([7857b0a6](https://github.com/rust-lang/rustlings/commit/7857b0a689b0847f48d8c14cbd1865e3b812d5ca))
|
||||
* **try_from_into:** use trait objects ([2e93a588](https://github.com/rust-lang/rustlings/commit/2e93a588e0abe8badb7eafafb9e7d073c2be5df8))
|
||||
|
||||
#### Features
|
||||
|
||||
* Replace clap with argh ([7928122f](https://github.com/rust-lang/rustlings/commit/7928122fcef9ca7834d988b1ec8ca0687478beeb))
|
||||
* Replace emojis when NO_EMOJI env variable present ([8d62a996](https://github.com/rust-lang/rustlings/commit/8d62a9963708dbecd9312e8bcc4b47049c72d155))
|
||||
* Added iterators5.rs exercise. ([b29ea17e](https://github.com/rust-lang/rustlings/commit/b29ea17ea94d1862114af2cf5ced0e09c197dc35))
|
||||
* **arc1:** Add more details to description and hint (#710) ([81be4044](https://github.com/rust-lang/rustlings/commit/81be40448777fa338ebced3b0bfc1b32d6370313))
|
||||
* **cli:** Improve the list command with options, and then some ([8bbe4ff1](https://github.com/rust-lang/rustlings/commit/8bbe4ff1385c5c169c90cd3ff9253f9a91daaf8e))
|
||||
* **list:**
|
||||
* updated progress percentage ([1c6f7e4b](https://github.com/rust-lang/rustlings/commit/1c6f7e4b7b9b3bd36f4da2bb2b69c549cc8bd913))
|
||||
* added progress info ([c0e3daac](https://github.com/rust-lang/rustlings/commit/c0e3daacaf6850811df5bc57fa43e0f249d5cfa4))
|
||||
|
||||
|
||||
|
||||
<a name="4.3.0"></a>
|
||||
## 4.3.0 (2020-12-29)
|
||||
|
||||
#### Features
|
||||
|
||||
* Rewrite default out text ([44d39112](https://github.com/rust-lang/rustlings/commit/44d39112ff122b29c9793fe52e605df1612c6490))
|
||||
* match exercise order to book chapters (#541) ([033bf119](https://github.com/rust-lang/rustlings/commit/033bf1198fc8bfce1b570e49da7cde010aa552e3))
|
||||
* Crab? (#586) ([fa9f522b](https://github.com/rust-lang/rustlings/commit/fa9f522b7f043d7ef73a39f003a9272dfe72c4f4))
|
||||
* add "rustlings list" command ([838f9f30](https://github.com/rust-lang/rustlings/commit/838f9f30083d0b23fd67503dcf0fbeca498e6647))
|
||||
* **try_from_into:** remove duplicate annotation ([04f1d079](https://github.com/rust-lang/rustlings/commit/04f1d079aa42a2f49af694bc92c67d731d31a53f))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* update structs README ([bcf14cf6](https://github.com/rust-lang/rustlings/commit/bcf14cf677adb3a38a3ac3ca53f3c69f61153025))
|
||||
* added missing exercises to info.toml ([90cfb6ff](https://github.com/rust-lang/rustlings/commit/90cfb6ff28377531bfc34acb70547bdb13374f6b))
|
||||
* gives a bit more context to magic number ([30644c9a](https://github.com/rust-lang/rustlings/commit/30644c9a062b825c0ea89435dc59f0cad86b110e))
|
||||
* **functions2:** Change signature to trigger precise error message: (#605) ([0ef95947](https://github.com/rust-lang/rustlings/commit/0ef95947cc30482e63a7045be6cc2fb6f6dcb4cc))
|
||||
* **structs1:** Adjust wording (#573) ([9334783d](https://github.com/rust-lang/rustlings/commit/9334783da31d821cc59174fbe8320df95828926c))
|
||||
* **try_from_into:**
|
||||
* type error ([4f4cfcf3](https://github.com/rust-lang/rustlings/commit/4f4cfcf3c36c8718c7c170c9c3a6935e6ef0618c))
|
||||
* Update description (#584) ([96347df9](https://github.com/rust-lang/rustlings/commit/96347df9df294f01153b29d9ad4ba361f665c755))
|
||||
* **vec1:** Have test compare every element in a and v ([9b6c6293](https://github.com/rust-lang/rustlings/commit/9b6c629397b24b944f484f5b2bbd8144266b5695))
|
||||
|
||||
<a name="4.2.0"></a>
|
||||
## 4.2.0 (2020-11-07)
|
||||
|
||||
#### Features
|
||||
|
||||
* Add HashMap exercises ([633c00cf](https://github.com/rust-lang/rustlings/commit/633c00cf8071e1e82959a3010452a32f34f29fc9))
|
||||
* Add Vec exercises ([0c12fa31](https://github.com/rust-lang/rustlings/commit/0c12fa31c57c03c6287458a0a8aca7afd057baf6))
|
||||
* **primitive_types6:** Add a test (#548) ([2b1fb2b7](https://github.com/rust-lang/rustlings/commit/2b1fb2b739bf9ad8d6b7b12af25fee173011bfc4))
|
||||
* **try_from_into:** Add tests (#571) ([95ccd926](https://github.com/rust-lang/rustlings/commit/95ccd92616ae79ba287cce221101e0bbe4f68cdc))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* log error output when inotify limit is exceeded ([d61b4e5a](https://github.com/rust-lang/rustlings/commit/d61b4e5a13b44d72d004082f523fa1b6b24c1aca))
|
||||
* more unique temp_file ([5643ef05](https://github.com/rust-lang/rustlings/commit/5643ef05bc81e4a840e9456f4406a769abbe1392))
|
||||
* **installation:** Update the MinRustVersion ([21bfb2d4](https://github.com/rust-lang/rustlings/commit/21bfb2d4777429c87d8d3b5fbf0ce66006dcd034))
|
||||
* **iterators2:** Update description (#578) ([197d3a3d](https://github.com/rust-lang/rustlings/commit/197d3a3d8961b2465579218a6749b2b2cefa8ddd))
|
||||
* **primitive_types6:**
|
||||
* remove 'unused doc comment' warning ([472d8592](https://github.com/rust-lang/rustlings/commit/472d8592d65c8275332a20dfc269e7ac0d41bc88))
|
||||
* missing comma in test ([4fb230da](https://github.com/rust-lang/rustlings/commit/4fb230daf1251444fcf29e085cee222a91f8a37e))
|
||||
* **quiz3:** Second test is for odd numbers, not even. (#553) ([18e0bfef](https://github.com/rust-lang/rustlings/commit/18e0bfef1de53071e353ba1ec5837002ff7290e6))
|
||||
|
||||
<a name="4.1.0"></a>
|
||||
## 4.1.0 (2020-10-05)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Update rustlings version in Cargo.lock ([1cc40bc9](https://github.com/rust-lang/rustlings/commit/1cc40bc9ce95c23d56f6d91fa1c4deb646231fef))
|
||||
* **arc1:** index mod should equal thread count ([b4062ef6](https://github.com/rust-lang/rustlings/commit/b4062ef6993e80dac107c4093ea85166ad3ee0fa))
|
||||
* **enums3:** Update Message::ChangeColor to take a tuple. (#457) ([4b6540c7](https://github.com/rust-lang/rustlings/commit/4b6540c71adabad647de8a09e57295e7c7c7d794))
|
||||
* **exercises:** adding question mark to quiz2 ([101072ab](https://github.com/rust-lang/rustlings/commit/101072ab9f8c80b40b8b88cb06cbe38aca2481c5))
|
||||
* **generics3:** clarify grade change ([47f7672c](https://github.com/rust-lang/rustlings/commit/47f7672c0307732056e7426e81d351f0dd7e22e5))
|
||||
* **structs3:** Small adjustment of variable name ([114b54cb](https://github.com/rust-lang/rustlings/commit/114b54cbdb977234b39e5f180d937c14c78bb8b2))
|
||||
* **using_as:** Add test so that proper type is returned. (#512) ([3286c5ec](https://github.com/rust-lang/rustlings/commit/3286c5ec19ea5fb7ded81d047da5f8594108a490))
|
||||
|
||||
#### Features
|
||||
|
||||
* Added iterators1.rs exercise ([9642f5a3](https://github.com/rust-lang/rustlings/commit/9642f5a3f686270a4f8f6ba969919ddbbc4f7fdd))
|
||||
* Add ability to run rustlings on repl.it (#471) ([8f7b5bd0](https://github.com/rust-lang/rustlings/commit/8f7b5bd00eb83542b959830ef55192d2d76db90a))
|
||||
* Add gitpod support (#473) ([4821a8be](https://github.com/rust-lang/rustlings/commit/4821a8be94af4f669042a06ab917934cfacd032f))
|
||||
* Remind the user of the hint option (#425) ([816b1f5e](https://github.com/rust-lang/rustlings/commit/816b1f5e85d6cc6e72673813a85d0ada2a8f84af))
|
||||
* Remind the user of the hint option (#425) ([9f61db5d](https://github.com/rust-lang/rustlings/commit/9f61db5dbe38538cf06571fcdd5f806e7901e83a))
|
||||
* **cli:** Added 'cls' command to 'watch' mode (#474) ([4f2468e1](https://github.com/rust-lang/rustlings/commit/4f2468e14f574a93a2e9b688367b5752ed96ae7b))
|
||||
* **try_from_into:** Add insufficient length test (#469) ([523d18b8](https://github.com/rust-lang/rustlings/commit/523d18b873a319f7c09262f44bd40e2fab1830e5))
|
||||
|
||||
<a name="4.0.0"></a>
|
||||
## 4.0.0 (2020-07-08)
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* Add a --nocapture option to display test harnesses' outputs ([8ad5f9bf](https://github.com/rust-lang/rustlings/commit/8ad5f9bf531a4848b1104b7b389a20171624c82f))
|
||||
* Rename test to quiz, fixes #244 ([010a0456](https://github.com/rust-lang/rustlings/commit/010a04569282149cea7f7a76fc4d7f4c9f0f08dd))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add traits README ([173bb141](https://github.com/rust-lang/rustlings/commit/173bb14140c5530cbdb59e53ace3991a99d804af))
|
||||
* Add box1.rs exercise ([7479a473](https://github.com/rust-lang/rustlings/commit/7479a4737bdcac347322ad0883ca528c8675e720))
|
||||
* Rewrite try_from_into (#393) ([763aa6e3](https://github.com/rust-lang/rustlings/commit/763aa6e378a586caae2d8d63755a85eeba227933))
|
||||
* Add if2 exercise ([1da84b5f](https://github.com/rust-lang/rustlings/commit/1da84b5f7c489f65bd683c244f13c7d1ee812df0))
|
||||
* Added exercise structs3.rs ([b66e2e09](https://github.com/rust-lang/rustlings/commit/b66e2e09622243e086a0f1258dd27e1a2d61c891))
|
||||
* Add exercise variables6 covering const (#352) ([5999acd2](https://github.com/rust-lang/rustlings/commit/5999acd24a4f203292be36e0fd18d385887ec481))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Change then to than ([ddd98ad7](https://github.com/rust-lang/rustlings/commit/ddd98ad75d3668fbb10eff74374148aa5ed2344d))
|
||||
* rename quiz1 to tests1 in info (#420) ([0dd1c6ca](https://github.com/rust-lang/rustlings/commit/0dd1c6ca6b389789e0972aa955fe17aa15c95f29))
|
||||
* fix quiz naming inconsistency (#421) ([5563adbb](https://github.com/rust-lang/rustlings/commit/5563adbb890587fc48fbbc9c4028642687f1e85b))
|
||||
* confine the user further in variable exercises ([06ef4cc6](https://github.com/rust-lang/rustlings/commit/06ef4cc654e75d22a526812919ee49b8956280bf))
|
||||
* update iterator and macro text for typos and clarity ([95900828](https://github.com/rust-lang/rustlings/commit/959008284834bece0196a01e17ac69a7e3590116))
|
||||
* update generics2 closes #362 ([964c974a](https://github.com/rust-lang/rustlings/commit/964c974a0274199d755073b917c2bc5da0c9b4f1))
|
||||
* confusing comment in conversions/try_from_into.rs ([c9e4f2cf](https://github.com/rust-lang/rustlings/commit/c9e4f2cfb4c48d0b7451263cfb43b9426438122d))
|
||||
* **arc1:** Passively introduce attributes (#429) ([113cdae2](https://github.com/rust-lang/rustlings/commit/113cdae2d4e4c55905e8056ad326ede7fd7de356))
|
||||
* **box1:** fix comment typo (#426) ([bb2ca251](https://github.com/rust-lang/rustlings/commit/bb2ca251106b27a7272d9a30872904dd1376654c))
|
||||
* **errorsn:** Try harder to confine the user. (#388) ([2b20c8a0](https://github.com/rust-lang/rustlings/commit/2b20c8a0f5774d07c58d110d75879f33fc6273b5))
|
||||
* **from_into.rs:** typo ([a901499e](https://github.com/rust-lang/rustlings/commit/a901499ededd3ce1995164700514fe4e9a0373ea))
|
||||
* **generics2:** Guide students to the answer (#430) ([e6bd8021](https://github.com/rust-lang/rustlings/commit/e6bd8021d9a7dd06feebc30c9d5f953901d7b419))
|
||||
* **installation:**
|
||||
* Provide a backup git reference when tag can't be curl ([9e4fb100](https://github.com/rust-lang/rustlings/commit/9e4fb1009f1c9e3433915c03e22c2af422e5c5fe))
|
||||
* Check if python is available while checking for git,rustc and cargo ([9cfb617d](https://github.com/rust-lang/rustlings/commit/9cfb617d5b0451b4b51644a1298965390cda9884))
|
||||
* **option1:**
|
||||
* Don't add only zeros to the numbers array ([cce6a442](https://github.com/rust-lang/rustlings/commit/cce6a4427718724a9096800754cd3abeca6a1580))
|
||||
* Add cast to usize, as it is confusing in the context of an exercise about Option ([f6cffc7e](https://github.com/rust-lang/rustlings/commit/f6cffc7e487b42f15a6f958e49704c93a8d4465b))
|
||||
* **option2:** Add TODO to comments (#400) ([10967bce](https://github.com/rust-lang/rustlings/commit/10967bce57682812dc0891a9f9757da1a9d87404))
|
||||
* **options1:** Add hint about Array Initialization (#389) ([9f75554f](https://github.com/rust-lang/rustlings/commit/9f75554f2a30295996f03f0160b98c0458305502))
|
||||
* **test2:** name of type String and &str (#394) ([d6c0a688](https://github.com/rust-lang/rustlings/commit/d6c0a688e6a96f93ad60d540d4b326f342fc0d45))
|
||||
* **variables6:** minor typo (#419) ([524e17df](https://github.com/rust-lang/rustlings/commit/524e17df10db95f7b90a0f75cc8997182a8a4094))
|
||||
|
||||
<a name="3.0.0"></a>
|
||||
## 3.0.0 (2020-04-11)
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* make "compile" exercises print output (#278) ([3b6d5c](https://github.com/fmoko/rustlings/commit/3b6d5c3aaa27a242a832799eb66e96897d26fde3))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **primitive_types:** revert primitive_types4 (#296) ([b3a3351e](https://github.com/rust-lang/rustlings/commit/b3a3351e8e6a0bdee07077d7b0382953821649ae))
|
||||
* **run:** compile clippy exercise files (#295) ([3ab084a4](https://github.com/rust-lang/rustlings/commit/3ab084a421c0f140ae83bf1fc3f47b39342e7373))
|
||||
* **conversions:**
|
||||
* add additional test to meet exercise rules (#284) ([bc22ec3](https://github.com/fmoko/rustlings/commit/bc22ec382f843347333ef1301fc1bad773657f38))
|
||||
* remove duplicate not done comment (#292) ([dab90f](https://github.com/fmoko/rustlings/commit/dab90f7b91a6000fe874e3d664f244048e5fa342))
|
||||
* don't hardcode documentation version for traits (#288) ([30e6af](https://github.com/fmoko/rustlings/commit/30e6af60690c326fb5d3a9b7335f35c69c09137d))
|
||||
|
||||
#### Features
|
||||
|
||||
* add Option2 exercise (#290) ([86b5c08b](https://github.com/rust-lang/rustlings/commit/86b5c08b9bea1576127a7c5f599f5752072c087d))
|
||||
* add excercise for option (#282) ([135e5d47](https://github.com/rust-lang/rustlings/commit/135e5d47a7c395aece6f6022117fb20c82f2d3d4))
|
||||
* add new exercises for generics (#280) ([76be5e4e](https://github.com/rust-lang/rustlings/commit/76be5e4e991160f5fd9093f03ee2ba260e8f7229))
|
||||
* **ci:** add buildkite config ([b049fa2c](https://github.com/rust-lang/rustlings/commit/b049fa2c84dba0f0c8906ac44e28fd45fba51a71))
|
||||
|
||||
<a name="2.2.1"></a>
|
||||
### 2.2.1 (2020-02-27)
|
||||
|
||||
@@ -18,14 +219,14 @@
|
||||
* Update deps to version compatable with aarch64-pc-windows (#263) ([19a93428](https://github.com/rust-lang/rustlings/commit/19a93428b3c73d994292671f829bdc8e5b7b3401))
|
||||
* **docs:**
|
||||
* Added a necessary step to Windows installation process (#242) ([3906efcd](https://github.com/rust-lang/rustlings/commit/3906efcd52a004047b460ed548037093de3f523f))
|
||||
* Fixed mangled sentence from book; edited for clarity (#266) ([ade52ff](https://github.com/rust-lang/rustlings/commit/ade52ffb739987287ddd5705944c8777705faed9))
|
||||
* Fixed mangled sentence from book; edited for clarity (#266) ([ade52ff](https://github.com/rust-lang/rustlings/commit/ade52ffb739987287ddd5705944c8777705faed9))
|
||||
* Updated iterators readme to account for iterators4 exercise (#273) ([bec8e3a](https://github.com/rust-lang/rustlings/commit/bec8e3a644cbd88db1c73ea5f1d8a364f4a34016))
|
||||
* **installation:** make fatal errors more obvious (#272) ([17d0951e](https://github.com/rust-lang/rustlings/commit/17d0951e66fda8e11b204d5c4c41a0d5e22e78f7))
|
||||
* **iterators2:**
|
||||
* Remove reference to missing iterators2.rs (#245) ([419f7797](https://github.com/rust-lang/rustlings/commit/419f7797f294e4ce6a2b883199731b5bde77d262))
|
||||
* **as_ref_mut:** Enable a test and improve per clippy's suggestion (#256) ([dfdf809](https://github.com/rust-lang/rustlings/commit/dfdf8093ebbd4145864995627b812780de52f902))
|
||||
* **tests1:**
|
||||
* Change test command ([fe10e06c](https://github.com/rust-lang/rustlings/commit/fe10e06c3733ddb4a21e90d09bf79bfe618e97ce)
|
||||
* Change test command ([fe10e06c](https://github.com/rust-lang/rustlings/commit/fe10e06c3733ddb4a21e90d09bf79bfe618e97ce)
|
||||
* Correct test command in tests1.rs comment (#263) ([39fa7ae](https://github.com/rust-lang/rustlings/commit/39fa7ae8b70ad468da49b06f11b2383135a63bcf))
|
||||
|
||||
#### Features
|
||||
|
||||
@@ -26,12 +26,12 @@ isn't really that complicated since the bulk of the work is done by `rustc`.
|
||||
<a name="addex"></a>
|
||||
### Adding an exercise
|
||||
|
||||
First step is to add the exercise! Call it `exercises/yourTopic/yourTopicN.rs`, make sure to
|
||||
The first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure to
|
||||
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
|
||||
|
||||
Next you want to make sure it runs when using `rustlings`. All exercises are stored in `info.toml`, under the `exercises` array. They're ordered by the order they're ran when using `rustlings verify`.
|
||||
Next make sure it runs with `rustlings`. The exercise metadata is stored in `info.toml`, under the `exercises` array. The order of the `exercises` array determines the order the exercises are run by `rustlings verify`.
|
||||
|
||||
You want to make sure where in the file you add your exercise. If you're not sure, add it at the bottom and ask in your pull request. To add an exercise, edit the file like this:
|
||||
Add the metadata for your exercise in the correct order in the `exercises` array. If you are unsure of the correct ordering, add it at the bottom and ask in your pull request. The exercise metadata should contain the following:
|
||||
```diff
|
||||
...
|
||||
+ [[exercises]]
|
||||
|
||||
835
Cargo.lock
generated
835
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "2.2.1"
|
||||
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
|
||||
version = "4.5.0"
|
||||
authors = ["anastasie <ana@ana.st>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.32.0"
|
||||
argh = "0.1.4"
|
||||
indicatif = "0.10.3"
|
||||
console = "0.7.7"
|
||||
notify = "4.0.15"
|
||||
|
||||
217
README.md
217
README.md
@@ -1,4 +1,6 @@
|
||||

|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
# rustlings 🦀❤️
|
||||
|
||||
@@ -6,7 +8,7 @@ Greetings and welcome to `rustlings`. This project contains small exercises to g
|
||||
|
||||
_...looking for the old, web-based version of Rustlings? Try [here](https://github.com/rust-lang/rustlings/tree/rustlings-1)_
|
||||
|
||||
Alternatively, for a first-time Rust learner, there's several other resources:
|
||||
Alternatively, for a first-time Rust learner, there are several other resources:
|
||||
|
||||
- [The Book](https://doc.rust-lang.org/book/index.html) - The most comprehensive resource for learning Rust, but a bit theoretical sometimes. You will be using this along with Rustlings!
|
||||
- [Rust By Example](https://doc.rust-lang.org/rust-by-example/index.html) - Learn Rust by solving little exercises! It's almost like `rustlings`, but online
|
||||
@@ -15,8 +17,6 @@ Alternatively, for a first-time Rust learner, there's several other resources:
|
||||
|
||||
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._
|
||||
|
||||
_Note: If you have Xcode 10+ installed, you also need to install the package file found at `/Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg`._
|
||||
|
||||
You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
|
||||
|
||||
## MacOS/Linux
|
||||
@@ -24,37 +24,45 @@ You will need to have Rust installed. You can get it by visiting https://rustup.
|
||||
Just run:
|
||||
|
||||
```bash
|
||||
curl -L https://git.io/rustlings | bash
|
||||
curl -L https://git.io/install-rustlings | bash
|
||||
# Or if you want it to be installed to a different path:
|
||||
curl -L https://git.io/rustlings | bash -s mypath/
|
||||
curl -L https://git.io/install-rustlings | bash -s mypath/
|
||||
```
|
||||
|
||||
This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
|
||||
|
||||
## Windows
|
||||
|
||||
First, set `ExecutionPolicy` to `RemoteSigned`:
|
||||
In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`:
|
||||
|
||||
```ps
|
||||
Set-ExecutionPolicy RemoteSigned
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
```
|
||||
|
||||
Then, you can run:
|
||||
|
||||
```ps
|
||||
Invoke-WebRequest https://git.io/rustlings-win | Select-Object -ExpandProperty Content | Out-File $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1
|
||||
Start-BitsTransfer -Source https://git.io/JTL5v -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1
|
||||
```
|
||||
|
||||
To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it.
|
||||
|
||||
When you get a permission denied message then you have to exclude the directory where you placed the rustlings in your virus-scanner
|
||||
|
||||
## Browser:
|
||||
|
||||
[Run on Repl.it](https://repl.it/github/rust-lang/rustlings)
|
||||
|
||||
[Open in Gitpod](https://gitpod.io/#https://github.com/rust-lang/rustlings)
|
||||
|
||||
## Manually
|
||||
|
||||
Basically: Clone the repository, checkout to the latest tag, run `cargo install`.
|
||||
Basically: Clone the repository at the latest tag, run `cargo install`.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings
|
||||
# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 4.5.0)
|
||||
git clone -b 4.5.0 --depth 1 https://github.com/rust-lang/rustlings
|
||||
cd rustlings
|
||||
git checkout tags/2.2.1 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
cargo install --force --path .
|
||||
```
|
||||
|
||||
@@ -69,7 +77,7 @@ Then, same as above, run `rustlings` to get started.
|
||||
|
||||
The exercises are sorted by topic and can be found in the subdirectory `rustlings/exercises/<topic>`. For every topic there is an additional README file with some resources to get you started on the topic. We really recommend that you have a look at them before you start.
|
||||
|
||||
The task is simple. Most exercises contain an error that keep it from compiling, and it's up to you to fix it! Some exercises are also run as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute:
|
||||
The task is simple. Most exercises contain an error that keeps them from compiling, and it's up to you to fix it! Some exercises are also run as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute:
|
||||
|
||||
```bash
|
||||
rustlings watch
|
||||
@@ -89,6 +97,12 @@ In case you want to go by your own order, or want to only verify a single exerci
|
||||
rustlings run myExercise1
|
||||
```
|
||||
|
||||
Or simply use the following command to run the next unsolved exercise in the course:
|
||||
|
||||
```bash
|
||||
rustlings run next
|
||||
```
|
||||
|
||||
In case you get stuck, you can run the following command to get a hint for your
|
||||
exercise:
|
||||
|
||||
@@ -96,9 +110,42 @@ exercise:
|
||||
rustlings hint myExercise1
|
||||
```
|
||||
|
||||
You can also get the hint for the next unsolved exercise with the following command:
|
||||
|
||||
``` bash
|
||||
rustlings hint next
|
||||
```
|
||||
|
||||
To check your progress, you can run the following command:
|
||||
```bash
|
||||
rustlings list
|
||||
```
|
||||
|
||||
## Testing yourself
|
||||
|
||||
After every couple of sections, there will be a test that'll test your knowledge on a bunch of sections at once. These tests are found in `exercises/testN.rs`.
|
||||
After every couple of sections, there will be a quiz that'll test your knowledge on a bunch of sections at once. These quizzes are found in `exercises/quizN.rs`.
|
||||
|
||||
## Continuing On
|
||||
|
||||
Once you've completed Rustlings, put your new knowledge to good use! Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to.
|
||||
|
||||
## Uninstalling Rustlings
|
||||
|
||||
If you want to remove Rustlings from your system, there's two steps. First, you'll need to remove the exercises folder that the install script created
|
||||
for you:
|
||||
|
||||
``` bash
|
||||
rm -rf rustlings # or your custom folder name, if you chose and or renamed it
|
||||
```
|
||||
|
||||
Second, since Rustlings got installed via `cargo install`, it's only reasonable to assume that you can also remove it using Cargo, and
|
||||
exactly that is the case. Run `cargo uninstall` to remove the `rustlings` binary:
|
||||
|
||||
``` bash
|
||||
cargo uninstall rustlings
|
||||
```
|
||||
|
||||
Now you should be done!
|
||||
|
||||
## Completion
|
||||
|
||||
@@ -122,7 +169,145 @@ If you are interested in improving or adding new ones, please feel free to contr
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
## Credits
|
||||
## Contributors ✨
|
||||
|
||||
`rustlings` was originally written by [Carol](https://github.com/carols10cents)!
|
||||
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="http://carol-nichols.com"><img src="https://avatars2.githubusercontent.com/u/193874?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Carol (Nichols || Goulding)</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=carols10cents" title="Code">💻</a> <a href="#content-carols10cents" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://twitter.com/QuietMisdreavus"><img src="https://avatars2.githubusercontent.com/u/5217170?v=4?s=100" width="100px;" alt=""/><br /><sub><b>QuietMisdreavus</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=QuietMisdreavus" title="Code">💻</a> <a href="#content-QuietMisdreavus" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/robertlugg"><img src="https://avatars0.githubusercontent.com/u/6054540?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert M Lugg</b></sub></a><br /><a href="#content-robertlugg" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://hynek.me/about/"><img src="https://avatars3.githubusercontent.com/u/41240?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hynek Schlawack</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=hynek" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://spacekookie.de"><img src="https://avatars0.githubusercontent.com/u/7669898?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Katharina Fey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=spacekookie" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/lukabavdaz"><img src="https://avatars0.githubusercontent.com/u/9624558?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lukabavdaz</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lukabavdaz" title="Code">💻</a> <a href="#content-lukabavdaz" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="http://vestera.as"><img src="https://avatars2.githubusercontent.com/u/4187449?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Erik Vesteraas</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=evestera" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Delet0r"><img src="https://avatars1.githubusercontent.com/u/23195618?v=4?s=100" width="100px;" alt=""/><br /><sub><b>delet0r</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Delet0r" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://phinary.ca"><img src="https://avatars1.githubusercontent.com/u/10522375?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shaun Bennett</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=shaunbennett" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/abagshaw"><img src="https://avatars2.githubusercontent.com/u/8594541?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Bagshaw</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=abagshaw" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://ai6ua.net/"><img src="https://avatars2.githubusercontent.com/u/175578?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kyle Isom</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=kisom" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ColinPitrat"><img src="https://avatars3.githubusercontent.com/u/1541863?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Colin Pitrat</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ColinPitrat" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://zacanger.com"><img src="https://avatars3.githubusercontent.com/u/12520493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zac Anger</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=zacanger" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mgeier"><img src="https://avatars1.githubusercontent.com/u/705404?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matthias Geier</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=mgeier" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/cjpearce"><img src="https://avatars1.githubusercontent.com/u/3453268?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Pearce</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cjpearce" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://yvan-sraka.github.io"><img src="https://avatars2.githubusercontent.com/u/705213?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yvan Sraka</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=yvan-sraka" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/dendi239"><img src="https://avatars3.githubusercontent.com/u/16478650?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Denys Smirnov</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=dendi239" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/eddyp"><img src="https://avatars2.githubusercontent.com/u/123772?v=4?s=100" width="100px;" alt=""/><br /><sub><b>eddyp</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=eddyp" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://about.me/BrianKung"><img src="https://avatars1.githubusercontent.com/u/2836167?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brian Kung</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=briankung" title="Code">💻</a> <a href="#content-briankung" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://rcousineau.gitlab.io"><img src="https://avatars3.githubusercontent.com/u/281039?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Russell</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=miller-time" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://danwilhelm.com"><img src="https://avatars3.githubusercontent.com/u/6137185?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dan Wilhelm</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=danwilhelm" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/Jesse-Cameron"><img src="https://avatars3.githubusercontent.com/u/3723654?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jesse</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Jesse-Cameron" title="Code">💻</a> <a href="#content-Jesse-Cameron" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/MrFroop"><img src="https://avatars3.githubusercontent.com/u/196700?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fredrik Jambrén</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=MrFroop" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/petemcfarlane"><img src="https://avatars3.githubusercontent.com/u/3472717?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pete McFarlane</b></sub></a><br /><a href="#content-petemcfarlane" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nkanderson"><img src="https://avatars0.githubusercontent.com/u/4128825?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nkanderson</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nkanderson" title="Code">💻</a> <a href="#content-nkanderson" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/ajaxm"><img src="https://avatars0.githubusercontent.com/u/13360138?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ajax M</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ajaxm" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://dylnuge.com"><img src="https://avatars2.githubusercontent.com/u/118624?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dylan Nugent</b></sub></a><br /><a href="#content-Dylnuge" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/vyaslav"><img src="https://avatars0.githubusercontent.com/u/1385427?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vyaslav</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=vyaslav" title="Code">💻</a> <a href="#content-vyaslav" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://join.sfxd.org"><img src="https://avatars1.githubusercontent.com/u/17297466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=gdoenlen" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/nyxtom"><img src="https://avatars2.githubusercontent.com/u/222763?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Thomas Holloway</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=nyxtom" title="Code">💻</a> <a href="#content-nyxtom" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/workingjubilee"><img src="https://avatars1.githubusercontent.com/u/46493976?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jubilee</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=workingjubilee" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/WofWca"><img src="https://avatars1.githubusercontent.com/u/39462442?v=4?s=100" width="100px;" alt=""/><br /><sub><b>WofWca</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=WofWca" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/jrvidal"><img src="https://avatars0.githubusercontent.com/u/1636604?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Roberto Vidal</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jrvidal" title="Code">💻</a> <a href="https://github.com/rust-lang/rustlings/commits?author=jrvidal" title="Documentation">📖</a> <a href="#ideas-jrvidal" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-jrvidal" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://github.com/jensim"><img src="https://avatars0.githubusercontent.com/u/3663856?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jens</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jensim" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://rahatah.me/d"><img src="https://avatars3.githubusercontent.com/u/3174006?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rahat Ahmed</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=rahatarmanahmed" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/AbdouSeck"><img src="https://avatars2.githubusercontent.com/u/6490055?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Abdou Seck</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=AbdouSeck" title="Code">💻</a> <a href="#content-AbdouSeck" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/pulls?q=is%3Apr+reviewed-by%3AAbdouSeck" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://codehearts.com"><img src="https://avatars0.githubusercontent.com/u/2885412?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Katie</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=codehearts" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Socratides"><img src="https://avatars3.githubusercontent.com/u/27732983?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Socrates</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Socratides" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/gnodarse"><img src="https://avatars3.githubusercontent.com/u/46761795?v=4?s=100" width="100px;" alt=""/><br /><sub><b>gnodarse</b></sub></a><br /><a href="#content-gnodarse" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/harrisonmetz"><img src="https://avatars1.githubusercontent.com/u/7883408?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Harrison Metzger</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=harrisonmetz" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/TorbenJ"><img src="https://avatars2.githubusercontent.com/u/9077102?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Torben Jonas</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=TorbenJ" title="Code">💻</a> <a href="#content-TorbenJ" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="http://paulbissex.com/"><img src="https://avatars0.githubusercontent.com/u/641?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul Bissex</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=pbx" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/sjmann"><img src="https://avatars0.githubusercontent.com/u/6589896?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Steven Mann</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sjmann" title="Code">💻</a> <a href="#content-sjmann" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://smmdb.net/"><img src="https://avatars2.githubusercontent.com/u/5855071?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mario Reder</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Tarnadas" title="Code">💻</a> <a href="#content-Tarnadas" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://keybase.io/skim"><img src="https://avatars0.githubusercontent.com/u/47347?v=4?s=100" width="100px;" alt=""/><br /><sub><b>skim</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sl4m" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/sanjaykdragon"><img src="https://avatars1.githubusercontent.com/u/10261698?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sanjay K</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sanjaykdragon" title="Code">💻</a> <a href="#content-sanjaykdragon" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="http://www.rohanjain.in"><img src="https://avatars1.githubusercontent.com/u/343499?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rohan Jain</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=crodjer" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.saidaspen.se"><img src="https://avatars1.githubusercontent.com/u/7727687?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Said Aspen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=saidaspen" title="Code">💻</a> <a href="#content-saidaspen" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/uce"><img src="https://avatars3.githubusercontent.com/u/1756620?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ufuk Celebi</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=uce" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/lebedevsergey"><img src="https://avatars2.githubusercontent.com/u/7325764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lebedevsergey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lebedevsergey" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/avrong"><img src="https://avatars2.githubusercontent.com/u/6342851?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksei Trifonov</b></sub></a><br /><a href="#content-avrong" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://drn.ie"><img src="https://avatars2.githubusercontent.com/u/411136?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Darren Meehan</b></sub></a><br /><a href="#content-Darrenmeehan" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/jihchi"><img src="https://avatars1.githubusercontent.com/u/87983?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jihchi Lee</b></sub></a><br /><a href="#content-jihchi" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/bertonha"><img src="https://avatars3.githubusercontent.com/u/1225902?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christofer Bertonha</b></sub></a><br /><a href="#content-bertonha" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/apatniv"><img src="https://avatars2.githubusercontent.com/u/22565917?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vivek Bharath Akupatni</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=apatniv" title="Code">💻</a> <a href="https://github.com/rust-lang/rustlings/commits?author=apatniv" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/DiD92"><img src="https://avatars3.githubusercontent.com/u/6002416?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dídac Sementé Fernández</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=DiD92" title="Code">💻</a> <a href="#content-DiD92" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/wrobstory"><img src="https://avatars3.githubusercontent.com/u/2601457?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rob Story</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=wrobstory" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/siobhanjacobson"><img src="https://avatars2.githubusercontent.com/u/28983835?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Siobhan Jacobson</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=siobhanjacobson" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/evancarroll/"><img src="https://avatars2.githubusercontent.com/u/19922?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Evan Carroll</b></sub></a><br /><a href="#content-EvanCarroll" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="http://www.jawaadmahmood.com"><img src="https://avatars3.githubusercontent.com/u/95606?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jawaad Mahmood</b></sub></a><br /><a href="#content-jmahmood" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/GaurangTandon"><img src="https://avatars1.githubusercontent.com/u/6308683?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gaurang Tandon</b></sub></a><br /><a href="#content-GaurangTandon" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/dev-cyprium"><img src="https://avatars1.githubusercontent.com/u/6002628?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stefan Kupresak</b></sub></a><br /><a href="#content-dev-cyprium" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/greg-el"><img src="https://avatars3.githubusercontent.com/u/45019882?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Greg Leonard</b></sub></a><br /><a href="#content-greg-el" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://ryanpcmcquen.org"><img src="https://avatars3.githubusercontent.com/u/772937?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ryan McQuen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=ryanpcmcquen" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/AnnikaCodes"><img src="https://avatars3.githubusercontent.com/u/56906084?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Annika</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/pulls?q=is%3Apr+reviewed-by%3AAnnikaCodes" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://darnuria.eu"><img src="https://avatars1.githubusercontent.com/u/2827553?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Axel Viala</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=darnuria" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://sazid.github.io"><img src="https://avatars1.githubusercontent.com/u/2370167?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mohammed Sazid Al Rashid</b></sub></a><br /><a href="#content-sazid" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=sazid" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://codingthemsoftly.com"><img src="https://avatars1.githubusercontent.com/u/17479099?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Caleb Webber</b></sub></a><br /><a href="#maintenance-seeplusplus" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://github.com/pcn"><img src="https://avatars2.githubusercontent.com/u/1056756?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Peter N</b></sub></a><br /><a href="#maintenance-pcn" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://github.com/seancad"><img src="https://avatars1.githubusercontent.com/u/47405611?v=4?s=100" width="100px;" alt=""/><br /><sub><b>seancad</b></sub></a><br /><a href="#maintenance-seancad" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="http://willhayworth.com"><img src="https://avatars3.githubusercontent.com/u/181174?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Will Hayworth</b></sub></a><br /><a href="#content-wsh" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/chrizel"><img src="https://avatars3.githubusercontent.com/u/20802?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Zeller</b></sub></a><br /><a href="#content-chrizel" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/jfchevrette"><img src="https://avatars.githubusercontent.com/u/3001?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jean-Francois Chevrette</b></sub></a><br /><a href="#content-jfchevrette" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=jfchevrette" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jbaber"><img src="https://avatars.githubusercontent.com/u/1908117?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Baber-Lucero</b></sub></a><br /><a href="#content-jbaber" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/tal-zvon"><img src="https://avatars.githubusercontent.com/u/3195851?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tal</b></sub></a><br /><a href="#content-tal-zvon" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/apogeeoak"><img src="https://avatars.githubusercontent.com/u/59737221?v=4?s=100" width="100px;" alt=""/><br /><sub><b>apogeeoak</b></sub></a><br /><a href="#content-apogeeoak" title="Content">🖋</a> <a href="https://github.com/rust-lang/rustlings/commits?author=apogeeoak" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.garfieldtech.com/"><img src="https://avatars.githubusercontent.com/u/254863?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Larry Garfield</b></sub></a><br /><a href="#content-Crell" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/circumspect"><img src="https://avatars.githubusercontent.com/u/40770208?v=4?s=100" width="100px;" alt=""/><br /><sub><b>circumspect</b></sub></a><br /><a href="#content-circumspect" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/cjwyett"><img src="https://avatars.githubusercontent.com/u/34195737?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cyrus Wyett</b></sub></a><br /><a href="#content-cjwyett" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/cadolphs"><img src="https://avatars.githubusercontent.com/u/13894820?v=4?s=100" width="100px;" alt=""/><br /><sub><b>cadolphs</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cadolphs" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.haveneer.com"><img src="https://avatars.githubusercontent.com/u/26146722?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pascal H.</b></sub></a><br /><a href="#content-hpwxf" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://twitter.com/chapeupreto"><img src="https://avatars.githubusercontent.com/u/834048?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rod Elias</b></sub></a><br /><a href="#content-chapeupreto" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/blerchy"><img src="https://avatars.githubusercontent.com/u/2555355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Lebl</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=blerchy" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://flakolefluk.dev"><img src="https://avatars.githubusercontent.com/u/11986564?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ignacio Le Fluk</b></sub></a><br /><a href="#content-flakolefluk" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/tlyu"><img src="https://avatars.githubusercontent.com/u/431873?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Taylor Yu</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=tlyu" title="Code">💻</a> <a href="#content-tlyu" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://zerotask.github.io"><img src="https://avatars.githubusercontent.com/u/20150243?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Patrick Hintermayer</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=Zerotask" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://petkopavlovski.com/"><img src="https://avatars.githubusercontent.com/u/32264020?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pete Pavlovski</b></sub></a><br /><a href="#content-arthas168" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/k12ish"><img src="https://avatars.githubusercontent.com/u/45272873?v=4?s=100" width="100px;" alt=""/><br /><sub><b>k12ish</b></sub></a><br /><a href="#content-k12ish" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/hongshaoyang"><img src="https://avatars.githubusercontent.com/u/19281800?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shao Yang Hong</b></sub></a><br /><a href="#content-hongshaoyang" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/bmacer"><img src="https://avatars.githubusercontent.com/u/13931806?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brandon Macer</b></sub></a><br /><a href="#content-bmacer" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/stoiandan"><img src="https://avatars.githubusercontent.com/u/10388612?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stoian Dan</b></sub></a><br /><a href="#content-stoiandan" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://about.me/pjdelport"><img src="https://avatars.githubusercontent.com/u/630271?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pi Delport</b></sub></a><br /><a href="#content-PiDelport" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/sateeshkumarb"><img src="https://avatars.githubusercontent.com/u/429263?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sateesh </b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=sateeshkumarb" title="Code">💻</a> <a href="#content-sateeshkumarb" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/kayuapi"><img src="https://avatars.githubusercontent.com/u/10304328?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ZC</b></sub></a><br /><a href="#content-kayuapi" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://github.com/hyperparabolic"><img src="https://avatars.githubusercontent.com/u/12348474?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hyperparabolic</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=hyperparabolic" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.net4visions.at"><img src="https://avatars.githubusercontent.com/u/5228369?v=4?s=100" width="100px;" alt=""/><br /><sub><b>arlecchino</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=kolbma" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://richthofen.io/"><img src="https://avatars.githubusercontent.com/u/7576730?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Richthofen</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=jazzplato" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/cseltol"><img src="https://avatars.githubusercontent.com/u/64264529?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ivan Nerazumov</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=cseltol" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/lauralindzey"><img src="https://avatars.githubusercontent.com/u/65185744?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lauralindzey</b></sub></a><br /><a href="https://github.com/rust-lang/rustlings/commits?author=lauralindzey" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/sinharaksh1t"><img src="https://avatars.githubusercontent.com/u/28585848?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rakshit Sinha</b></sub></a><br /><a href="#content-sinharaksh1t" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
Thanks for installing Rustlings!
|
||||
|
||||
Is this your first time?
|
||||
Is this your first time? Don't worry, Rustlings was made for beginners! We are
|
||||
going to teach you a lot of things about Rust, but before we can get
|
||||
started, here's a couple of notes about how Rustlings operates:
|
||||
|
||||
Let's make sure you're up to speed:
|
||||
- You have Rust installed, preferably via `rustup`
|
||||
- You have `~/.cargo/bin` added to your PATH variable
|
||||
- You have cloned this repository (https://github.com/rust-lang/rustlings)
|
||||
- You have installed Rust language support for your editor
|
||||
- You have locally installed the `rustlings` command by running an
|
||||
installation script or manually executing:
|
||||
1. The central concept behind Rustlings is that you solve exercises. These
|
||||
exercises usually have some sort of syntax error in them, which will cause
|
||||
them to fail compilation or testing. Sometimes there's a logic error instead
|
||||
of a syntax error. No matter what error, it's your job to find it and fix it!
|
||||
You'll know when you fixed it because then, the exercise will compile and
|
||||
Rustlings will be able to move on to the next exercise.
|
||||
2. If you run Rustlings in watch mode (which we recommend), it'll automatically
|
||||
start with the first exercise. Don't get confused by an error message popping
|
||||
up as soon as you run Rustlings! This is part of the exercise that you're
|
||||
supposed to solve, so open the exercise file in an editor and start your
|
||||
detective work!
|
||||
3. If you're stuck on an exercise, there is a helpful hint you can view by typing
|
||||
'hint' (in watch mode), or running `rustlings hint myexercise`.
|
||||
4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
|
||||
(https://github.com/rust-lang/rustlings/issues/new). We look at every issue,
|
||||
and sometimes, other learners do too so you can help each other out!
|
||||
|
||||
cargo install --force --path .
|
||||
|
||||
If you've done all of this (or even most of it), congrats! You're ready
|
||||
to start working with Rust.
|
||||
|
||||
To get started, run `rustlings watch` in order to get the first exercise.
|
||||
Make sure to have your editor open!
|
||||
Got all that? Great! To get started, run `rustlings watch` in order to get the first
|
||||
exercise. Make sure to have your editor open!
|
||||
|
||||
24
exercises/README.md
Normal file
24
exercises/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Exercise to Book Chapter mapping
|
||||
|
||||
| Exercise | Book Chapter |
|
||||
|------------------------|--------------|
|
||||
| variables | §3.1 |
|
||||
| functions | §3.3 |
|
||||
| if | §3.5 |
|
||||
| move_semantics | §4.1 |
|
||||
| primitive_types | §4.3 |
|
||||
| structs | §5.1 |
|
||||
| enums | §6 |
|
||||
| modules | §7.2 |
|
||||
| collections | §8.1, §8.3 |
|
||||
| strings | §8.2 |
|
||||
| error_handling | §9 |
|
||||
| generics | §10 |
|
||||
| option | §10.1 |
|
||||
| traits | §10.2 |
|
||||
| tests | §11.1 |
|
||||
| standard_library_types | §13.2 |
|
||||
| threads | §16.1 |
|
||||
| macros | §19.6 |
|
||||
| clippy | n/a |
|
||||
| conversions | n/a |
|
||||
@@ -1,8 +1,10 @@
|
||||
### Clippy
|
||||
# Clippy
|
||||
|
||||
The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code.
|
||||
|
||||
If you used the installation script for Rustlings, Clippy should be already installed.
|
||||
If not you can install it manually via `rustup component add clippy`.
|
||||
|
||||
For more information about Clippy lints, please see [their documentation page](https://rust-lang.github.io/rust-clippy/master/).
|
||||
## Further information
|
||||
|
||||
- [GitHub Repository](https://github.com/rust-lang/rust-clippy).
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// The Clippy tool is a collection of lints to analyze your code
|
||||
// so you can catch common mistakes and improve your Rust code.
|
||||
//
|
||||
// For these exercises the code will fail to compile when there are clippy warnings
|
||||
// check clippy's suggestions from the output to solve the exercise.
|
||||
// Execute `rustlings hint clippy1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
23
exercises/collections/README.md
Normal file
23
exercises/collections/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Collections
|
||||
|
||||
Rust’s standard library includes a number of very useful data
|
||||
structures called collections. Most other data types represent one
|
||||
specific value, but collections can contain multiple values. Unlike
|
||||
the built-in array and tuple types, the data these collections point
|
||||
to is stored on the heap, which means the amount of data does not need
|
||||
to be known at compile time and can grow or shrink as the program
|
||||
runs.
|
||||
|
||||
This exercise will get you familiar with two fundamental data
|
||||
structures that are used very often in Rust programs:
|
||||
|
||||
* A *vector* allows you to store a variable number of values next to
|
||||
each other.
|
||||
* A *hash map* allows you to associate a value with a particular key.
|
||||
You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
|
||||
[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html)
|
||||
- [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
|
||||
44
exercises/collections/hashmap1.rs
Normal file
44
exercises/collections/hashmap1.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
// hashmap1.rs
|
||||
// A basket of fruits in the form of a hash map needs to be defined.
|
||||
// The key represents the name of the fruit and the value represents
|
||||
// how many of that particular fruit is in the basket. You have to put
|
||||
// at least three different types of fruits (e.g apple, banana, mango)
|
||||
// in the basket and the total count of all the fruits should be at
|
||||
// least five.
|
||||
//
|
||||
// Make me compile and pass the tests!
|
||||
//
|
||||
// Execute the command `rustlings hint hashmap1` if you need
|
||||
// hints.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn fruit_basket() -> HashMap<String, u32> {
|
||||
let mut basket = // TODO: declare your hash map here.
|
||||
|
||||
// Two bananas are already given for you :)
|
||||
basket.insert(String::from("banana"), 2);
|
||||
|
||||
// TODO: Put more fruits in your basket here.
|
||||
|
||||
basket
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn at_least_three_types_of_fruits() {
|
||||
let basket = fruit_basket();
|
||||
assert!(basket.len() >= 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn at_least_five_fruits() {
|
||||
let basket = fruit_basket();
|
||||
assert!(basket.values().sum::<u32>() >= 5);
|
||||
}
|
||||
}
|
||||
81
exercises/collections/hashmap2.rs
Normal file
81
exercises/collections/hashmap2.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
// hashmap2.rs
|
||||
|
||||
// A basket of fruits in the form of a hash map is given. The key
|
||||
// represents the name of the fruit and the value represents how many
|
||||
// of that particular fruit is in the basket. You have to put *MORE
|
||||
// THAN 11* fruits in the basket. Three types of fruits - Apple (4),
|
||||
// Mango (2) and Lychee (5) are already given in the basket. You are
|
||||
// not allowed to insert any more of these fruits!
|
||||
//
|
||||
// Make me pass the tests!
|
||||
//
|
||||
// Execute the command `rustlings hint hashmap2` if you need
|
||||
// hints.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Hash, PartialEq, Eq)]
|
||||
enum Fruit {
|
||||
Apple,
|
||||
Banana,
|
||||
Mango,
|
||||
Lychee,
|
||||
Pineapple,
|
||||
}
|
||||
|
||||
fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
|
||||
let fruit_kinds = vec![
|
||||
Fruit::Apple,
|
||||
Fruit::Banana,
|
||||
Fruit::Mango,
|
||||
Fruit::Lychee,
|
||||
Fruit::Pineapple,
|
||||
];
|
||||
|
||||
for fruit in fruit_kinds {
|
||||
// TODO: Put new fruits if not already present. Note that you
|
||||
// are not allowed to put any type of fruit that's already
|
||||
// present!
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn get_fruit_basket() -> HashMap<Fruit, u32> {
|
||||
let mut basket = HashMap::<Fruit, u32>::new();
|
||||
basket.insert(Fruit::Apple, 4);
|
||||
basket.insert(Fruit::Mango, 2);
|
||||
basket.insert(Fruit::Lychee, 5);
|
||||
|
||||
basket
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_given_fruits_are_not_modified() {
|
||||
let mut basket = get_fruit_basket();
|
||||
fruit_basket(&mut basket);
|
||||
assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
|
||||
assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
|
||||
assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn at_least_five_types_of_fruits() {
|
||||
let mut basket = get_fruit_basket();
|
||||
fruit_basket(&mut basket);
|
||||
let count_fruit_kinds = basket.len();
|
||||
assert!(count_fruit_kinds >= 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than_eleven_fruits() {
|
||||
let mut basket = get_fruit_basket();
|
||||
fruit_basket(&mut basket);
|
||||
let count = basket.values().sum::<u32>();
|
||||
assert!(count > 11);
|
||||
}
|
||||
}
|
||||
25
exercises/collections/vec1.rs
Normal file
25
exercises/collections/vec1.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
// vec1.rs
|
||||
// Your task is to create a `Vec` which holds the exact same elements
|
||||
// as in the array `a`.
|
||||
// Make me compile and pass the test!
|
||||
// Execute the command `rustlings hint vec1` if you need hints.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn array_and_vec() -> ([i32; 4], Vec<i32>) {
|
||||
let a = [10, 20, 30, 40]; // a plain array
|
||||
let v = // TODO: declare your vector here with the macro for vectors
|
||||
|
||||
(a, v)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_array_and_vec_similarity() {
|
||||
let (a, v) = array_and_vec();
|
||||
assert_eq!(a, v[..]);
|
||||
}
|
||||
}
|
||||
33
exercises/collections/vec2.rs
Normal file
33
exercises/collections/vec2.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
// vec2.rs
|
||||
// A Vec of even numbers is given. Your task is to complete the loop
|
||||
// so that each number in the Vec is multiplied by 2.
|
||||
//
|
||||
// Make me pass the test!
|
||||
//
|
||||
// Execute the command `rustlings hint vec2` if you need
|
||||
// hints.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn vec_loop(mut v: Vec<i32>) -> Vec<i32> {
|
||||
for i in v.iter_mut() {
|
||||
// TODO: Fill this up so that each element in the Vec `v` is
|
||||
// multiplied by 2.
|
||||
}
|
||||
|
||||
// At this point, `v` should be equal to [4, 8, 12, 16, 20].
|
||||
v
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_vec_loop() {
|
||||
let v: Vec<i32> = (1..).filter(|x| x % 2 == 0).take(5).collect();
|
||||
let ans = vec_loop(v.clone());
|
||||
|
||||
assert_eq!(ans, v.iter().map(|x| x * 2).collect::<Vec<i32>>());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
### Type conversions
|
||||
|
||||
# Type conversions
|
||||
|
||||
Rust offers a multitude of ways to convert a value of a given type into another type.
|
||||
|
||||
@@ -15,6 +14,8 @@ Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc
|
||||
|
||||
These should be the main ways ***within the standard library*** to convert data into your desired types.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
These are not directly covered in the book, but the standard library has great documentation for [conversions here](https://doc.rust-lang.org/std/convert/index.html). The `FromStr` trait is also covered [here](https://doc.rust-lang.org/std/str/trait.FromStr.html).
|
||||
These are not directly covered in the book, but the standard library has a great documentation for it.
|
||||
- [conversions](https://doc.rust-lang.org/std/convert/index.html)
|
||||
- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html)
|
||||
@@ -3,13 +3,13 @@
|
||||
// and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Obtain the number of bytes (not characters) in the given argument
|
||||
// Add the AsRef trait appropriately as a trait bound
|
||||
fn byte_counter<T>(arg: T) -> usize {
|
||||
arg.as_ref().as_bytes().len()
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
// Obtain the number of characters (not bytes) in the given argument
|
||||
// Add the AsRef trait appropriately as a trait bound
|
||||
fn char_counter<T>(arg: T) -> usize {
|
||||
@@ -37,4 +37,16 @@ mod tests {
|
||||
let s = "Cafe au lait";
|
||||
assert_eq!(char_counter(s), byte_counter(s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn different_counts_using_string() {
|
||||
let s = String::from("Café au lait");
|
||||
assert_ne!(char_counter(s.clone()), byte_counter(s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_counts_using_string() {
|
||||
let s = String::from("Cafe au lait");
|
||||
assert_eq!(char_counter(s.clone()), byte_counter(s));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ impl Default for Person {
|
||||
}
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
// Your task is to complete this implementation
|
||||
// in order for the line `let p = Person::from("Mark,20")` to compile
|
||||
// Please note that you'll need to parse the age component into a `usize`
|
||||
@@ -29,9 +28,13 @@ impl Default for Person {
|
||||
// 1. If the length of the provided string is 0, then return the default of Person
|
||||
// 2. Split the given string on the commas present in it
|
||||
// 3. Extract the first element from the split operation and use it as the name
|
||||
// 4. Extract the other element from the split operation and parse it into a `usize` as the age
|
||||
// 4. If the name is empty, then return the default of Person
|
||||
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
|
||||
// If while parsing the age, something goes wrong, then return the default of Person
|
||||
// Otherwise, then return an instantiated Person onject with the results
|
||||
// Otherwise, then return an instantiated Person object with the results
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
impl From<&str> for Person {
|
||||
fn from(s: &str) -> Person {
|
||||
}
|
||||
@@ -70,4 +73,60 @@ mod tests {
|
||||
assert_eq!(p.name, "Mark");
|
||||
assert_eq!(p.age, 20);
|
||||
}
|
||||
#[test]
|
||||
fn test_bad_age() {
|
||||
// Test that "Mark,twenty" will return the default person due to an error in parsing age
|
||||
let p = Person::from("Mark,twenty");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_comma_and_age() {
|
||||
let p: Person = Person::from("Mark");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_age() {
|
||||
let p: Person = Person::from("Mark,");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_name() {
|
||||
let p: Person = Person::from(",1");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_name_and_age() {
|
||||
let p: Person = Person::from(",");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_name_and_invalid_age() {
|
||||
let p: Person = Person::from(",one");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trailing_comma() {
|
||||
let p: Person = Person::from("Mike,32,");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trailing_comma_and_some_string() {
|
||||
let p: Person = Person::from("Mike,32,man");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Additionally, upon implementing FromStr, you can use the `parse` method
|
||||
// on strings to generate an object of the implementor type.
|
||||
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
|
||||
use std::error;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -11,15 +12,19 @@ struct Person {
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Steps:
|
||||
// 1. If the length of the provided string is 0, then return an error
|
||||
// 1. If the length of the provided string is 0, an error should be returned
|
||||
// 2. Split the given string on the commas present in it
|
||||
// 3. Extract the first element from the split operation and use it as the name
|
||||
// 4. Extract the other element from the split operation and parse it into a `usize` as the age
|
||||
// If while parsing the age, something goes wrong, then return an error
|
||||
// Otherwise, then return a Result of a Person object
|
||||
// 3. Only 2 elements should be returned from the split, otherwise return an error
|
||||
// 4. Extract the first element from the split operation and use it as the name
|
||||
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
|
||||
// with something like `"4".parse::<usize>()`
|
||||
// 5. If while extracting the name and the age something goes wrong, an error should be returned
|
||||
// If everything goes well, then return a Result of a Person object
|
||||
|
||||
impl FromStr for Person {
|
||||
type Err = String;
|
||||
type Err = Box<dyn error::Error>;
|
||||
fn from_str(s: &str) -> Result<Person, Self::Err> {
|
||||
}
|
||||
}
|
||||
@@ -39,11 +44,49 @@ mod tests {
|
||||
}
|
||||
#[test]
|
||||
fn good_input() {
|
||||
assert!("John,32".parse::<Person>().is_ok());
|
||||
let p = "John,32".parse::<Person>();
|
||||
assert!(p.is_ok());
|
||||
let p = p.unwrap();
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 32);
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn missing_age() {
|
||||
"John".parse::<Person>().unwrap();
|
||||
assert!("John,".parse::<Person>().is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_age() {
|
||||
assert!("John,twenty".parse::<Person>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_comma_and_age() {
|
||||
assert!("John".parse::<Person>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_name() {
|
||||
assert!(",1".parse::<Person>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_name_and_age() {
|
||||
assert!(",".parse::<Person>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_name_and_invalid_age() {
|
||||
assert!(",one".parse::<Person>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_comma() {
|
||||
assert!("John,32,".parse::<Person>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trailing_comma_and_some_string() {
|
||||
assert!("John,32,man".parse::<Person>().is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,70 +2,157 @@
|
||||
// Basically, this is the same as From. The main difference is that this should return a Result type
|
||||
// instead of the target type itself.
|
||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
|
||||
use std::convert::{TryInto, TryFrom};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::error;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: usize,
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Color {
|
||||
red: u8,
|
||||
green: u8,
|
||||
blue: u8,
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Your task is to complete this implementation
|
||||
// in order for the line `let p = Person::try_from("Mark,20")` to compile
|
||||
// and return an Ok result of inner type Person.
|
||||
// Please note that you'll need to parse the age component into a `usize`
|
||||
// with something like `"4".parse::<usize>()`. The outcome of this needs to
|
||||
// be handled appropriately.
|
||||
// and return an Ok result of inner type Color.
|
||||
// You need to create an implementation for a tuple of three integers,
|
||||
// an array of three integers and a slice of integers.
|
||||
//
|
||||
// Steps:
|
||||
// 1. If the length of the provided string is 0, then return an error
|
||||
// 2. Split the given string on the commas present in it
|
||||
// 3. Extract the first element from the split operation and use it as the name
|
||||
// 4. Extract the other element from the split operation and parse it into a `usize` as the age
|
||||
// If while parsing the age, something goes wrong, then return an error
|
||||
// Otherwise, then return a Result of a Person object
|
||||
impl TryFrom<&str> for Person {
|
||||
type Error = String;
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
}
|
||||
// Note that the implementation for tuple and array will be checked at compile time,
|
||||
// but the slice implementation needs to check the slice length!
|
||||
// Also note that correct RGB color values must be integers in the 0..=255 range.
|
||||
|
||||
// Tuple implementation
|
||||
impl TryFrom<(i16, i16, i16)> for Color {
|
||||
type Error = Box<dyn error::Error>;
|
||||
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {}
|
||||
}
|
||||
|
||||
// Array implementation
|
||||
impl TryFrom<[i16; 3]> for Color {
|
||||
type Error = Box<dyn error::Error>;
|
||||
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {}
|
||||
}
|
||||
|
||||
// Slice implementation
|
||||
impl TryFrom<&[i16]> for Color {
|
||||
type Error = Box<dyn error::Error>;
|
||||
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Use the `from` function
|
||||
let p1 = Person::try_from("Mark,20");
|
||||
// Since From is implemented for Person, we should be able to use Into
|
||||
let p2: Result<Person, _> = "Gerald,70".try_into();
|
||||
println!("{:?}", p1);
|
||||
println!("{:?}", p2);
|
||||
let c1 = Color::try_from((183, 65, 14));
|
||||
println!("{:?}", c1);
|
||||
|
||||
// Since From is implemented for Color, we should be able to use Into
|
||||
let c2: Result<Color, _> = [183, 65, 14].try_into();
|
||||
println!("{:?}", c2);
|
||||
|
||||
let v = vec![183, 65, 14];
|
||||
// With slice we should use `from` function
|
||||
let c3 = Color::try_from(&v[..]);
|
||||
println!("{:?}", c3);
|
||||
// or take slice within round brackets and use Into
|
||||
let c4: Result<Color, _> = (&v[..]).try_into();
|
||||
println!("{:?}", c4);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_bad_convert() {
|
||||
// Test that John is returned when bad string is provided
|
||||
let p = Person::try_from("");
|
||||
assert!(p.is_err());
|
||||
fn test_tuple_out_of_range_positive() {
|
||||
assert!(Color::try_from((256, 1000, 10000)).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_good_convert() {
|
||||
// Test that "Mark,20" works
|
||||
let p = Person::try_from("Mark,20");
|
||||
assert!(p.is_ok());
|
||||
let p = p.unwrap();
|
||||
assert_eq!(p.name, "Mark");
|
||||
assert_eq!(p.age, 20);
|
||||
fn test_tuple_out_of_range_negative() {
|
||||
assert!(Color::try_from((-1, -10, -256)).is_err());
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_panic_empty_input() {
|
||||
let p: Person = "".try_into().unwrap();
|
||||
fn test_tuple_sum() {
|
||||
assert!(Color::try_from((-1, 255, 255)).is_err());
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_panic_bad_age() {
|
||||
let p = Person::try_from("Mark,twenty").unwrap();
|
||||
fn test_tuple_correct() {
|
||||
let c: Result<Color, _> = (183, 65, 14).try_into();
|
||||
assert!(c.is_ok());
|
||||
assert_eq!(
|
||||
c.unwrap(),
|
||||
Color {
|
||||
red: 183,
|
||||
green: 65,
|
||||
blue: 14
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_array_out_of_range_positive() {
|
||||
let c: Result<Color, _> = [1000, 10000, 256].try_into();
|
||||
assert!(c.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_array_out_of_range_negative() {
|
||||
let c: Result<Color, _> = [-10, -256, -1].try_into();
|
||||
assert!(c.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_array_sum() {
|
||||
let c: Result<Color, _> = [-1, 255, 255].try_into();
|
||||
assert!(c.is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_array_correct() {
|
||||
let c: Result<Color, _> = [183, 65, 14].try_into();
|
||||
assert!(c.is_ok());
|
||||
assert_eq!(
|
||||
c.unwrap(),
|
||||
Color {
|
||||
red: 183,
|
||||
green: 65,
|
||||
blue: 14
|
||||
}
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_out_of_range_positive() {
|
||||
let arr = [10000, 256, 1000];
|
||||
assert!(Color::try_from(&arr[..]).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_out_of_range_negative() {
|
||||
let arr = [-256, -1, -10];
|
||||
assert!(Color::try_from(&arr[..]).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_sum() {
|
||||
let arr = [-1, 255, 255];
|
||||
assert!(Color::try_from(&arr[..]).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_correct() {
|
||||
let v = vec![183, 65, 14];
|
||||
let c: Result<Color, _> = Color::try_from(&v[..]);
|
||||
assert!(c.is_ok());
|
||||
assert_eq!(
|
||||
c.unwrap(),
|
||||
Color {
|
||||
red: 183,
|
||||
green: 65,
|
||||
blue: 14
|
||||
}
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_excess_length() {
|
||||
let v = vec![0, 0, 0, 0];
|
||||
assert!(Color::try_from(&v[..]).is_err());
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_insufficient_length() {
|
||||
let v = vec![0, 0];
|
||||
assert!(Color::try_from(&v[..]).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
// Type casting in Rust is done via the usage of the `as` operator.
|
||||
// Please note that the `as` operator is not only used when type casting.
|
||||
// It also helps with renaming imports.
|
||||
//
|
||||
// The goal is to make sure that the division does not fail to compile
|
||||
// and returns the proper type.
|
||||
|
||||
// I AM NOT DONE
|
||||
// The goal is to make sure that the division does not fail to compile
|
||||
|
||||
fn average(values: &[f64]) -> f64 {
|
||||
let total = values
|
||||
.iter()
|
||||
.fold(0.0, |a, b| a + b);
|
||||
let total = values.iter().fold(0.0, |a, b| a + b);
|
||||
total / values.len()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let values = [3.5, 0.3, 13.0, 11.7];
|
||||
println!("{}", average(&values));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn returns_proper_type_and_value() {
|
||||
assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
### Enums
|
||||
# Enums
|
||||
|
||||
Rust allows you to define types called "enums" which enumerate possible values.
|
||||
Rust allows you to define types called "enums" which enumerate possible values.
|
||||
Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
|
||||
Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
|
||||
Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
|
||||
- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)
|
||||
|
||||
@@ -16,10 +16,10 @@ impl Message {
|
||||
|
||||
fn main() {
|
||||
let messages = [
|
||||
Message::Move{ x: 10, y: 30 },
|
||||
Message::Move { x: 10, y: 30 },
|
||||
Message::Echo(String::from("hello world")),
|
||||
Message::ChangeColor(200, 255, 255),
|
||||
Message::Quit
|
||||
Message::Quit,
|
||||
];
|
||||
|
||||
for message in &messages {
|
||||
|
||||
@@ -9,13 +9,13 @@ enum Message {
|
||||
|
||||
struct Point {
|
||||
x: u8,
|
||||
y: u8
|
||||
y: u8,
|
||||
}
|
||||
|
||||
struct State {
|
||||
color: (u8, u8, u8),
|
||||
position: Point,
|
||||
quit: bool
|
||||
quit: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
@@ -46,14 +46,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_match_message_call() {
|
||||
let mut state = State{
|
||||
let mut state = State {
|
||||
quit: false,
|
||||
position: Point{ x: 0, y: 0 },
|
||||
color: (0, 0, 0)
|
||||
position: Point { x: 0, y: 0 },
|
||||
color: (0, 0, 0),
|
||||
};
|
||||
state.process(Message::ChangeColor(255, 0, 255));
|
||||
state.process(Message::ChangeColor((255, 0, 255)));
|
||||
state.process(Message::Echo(String::from("hello world")));
|
||||
state.process(Message::Move{ x: 10, y: 15 });
|
||||
state.process(Message::Move(Point { x: 10, y: 15 }));
|
||||
state.process(Message::Quit);
|
||||
|
||||
assert_eq!(state.color, (255, 0, 255));
|
||||
@@ -61,5 +61,4 @@ mod tests {
|
||||
assert_eq!(state.position.y, 15);
|
||||
assert_eq!(state.quit, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
For this exercise check out the sections:
|
||||
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
|
||||
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
|
||||
# Error handling
|
||||
Most errors aren’t serious enough to require the program to stop entirely.
|
||||
Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to.
|
||||
For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process.
|
||||
|
||||
of the Rust Book.
|
||||
## Further information
|
||||
|
||||
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
|
||||
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
|
||||
- [Result](https://doc.rust-lang.org/rust-by-example/error/result.html)
|
||||
- [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// result1.rs
|
||||
// Make this test pass! Execute `rustlings hint result1` for hints :)
|
||||
// errors4.rs
|
||||
// Make this test pass! Execute `rustlings hint errors4` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
53
exercises/error_handling/errors5.rs
Normal file
53
exercises/error_handling/errors5.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
// errors5.rs
|
||||
|
||||
// This program uses a completed version of the code from errors4.
|
||||
// It won't compile right now! Why?
|
||||
// Execute `rustlings hint errors5` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::num::ParseIntError;
|
||||
|
||||
// TODO: update the return type of `main()` to make this compile.
|
||||
fn main() -> Result<(), ParseIntError> {
|
||||
let pretend_user_input = "42";
|
||||
let x: i64 = pretend_user_input.parse()?;
|
||||
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Don't change anything below this line.
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
match value {
|
||||
x if x < 0 => Err(CreationError::Negative),
|
||||
x if x == 0 => Err(CreationError::Zero),
|
||||
x => Ok(PositiveNonzeroInteger(x as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is required so that `CreationError` can implement `error::Error`.
|
||||
impl fmt::Display for CreationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let description = match *self {
|
||||
CreationError::Negative => "number is negative",
|
||||
CreationError::Zero => "number is zero",
|
||||
};
|
||||
f.write_str(description)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CreationError {}
|
||||
95
exercises/error_handling/errors6.rs
Normal file
95
exercises/error_handling/errors6.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
// errors6.rs
|
||||
|
||||
// Using catch-all error types like `Box<dyn error::Error>` isn't recommended
|
||||
// for library code, where callers might want to make decisions based on the
|
||||
// error content, instead of printing it out or propagating it further. Here,
|
||||
// we define a custom error type to make it possible for callers to decide
|
||||
// what to do next when our function returns an error.
|
||||
|
||||
// Make these tests pass! Execute `rustlings hint errors6` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
// This is a custom error type that we will be using in `parse_pos_nonzero()`.
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum ParsePosNonzeroError {
|
||||
Creation(CreationError),
|
||||
ParseInt(ParseIntError)
|
||||
}
|
||||
|
||||
impl ParsePosNonzeroError {
|
||||
fn from_creation(err: CreationError) -> ParsePosNonzeroError {
|
||||
ParsePosNonzeroError::Creation(err)
|
||||
}
|
||||
// TODO: add another error conversion function here.
|
||||
}
|
||||
|
||||
fn parse_pos_nonzero(s: &str)
|
||||
-> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
|
||||
{
|
||||
// TODO: change this to return an appropriate error instead of panicking
|
||||
// when `parse()` returns an error.
|
||||
let x: i64 = s.parse().unwrap();
|
||||
PositiveNonzeroInteger::new(x)
|
||||
.map_err(ParsePosNonzeroError::from_creation)
|
||||
}
|
||||
|
||||
// Don't change anything below this line.
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
match value {
|
||||
x if x < 0 => Err(CreationError::Negative),
|
||||
x if x == 0 => Err(CreationError::Zero),
|
||||
x => Ok(PositiveNonzeroInteger(x as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_error() {
|
||||
// We can't construct a ParseIntError, so we have to pattern match.
|
||||
assert!(matches!(
|
||||
parse_pos_nonzero("not a number"),
|
||||
Err(ParsePosNonzeroError::ParseInt(_))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative() {
|
||||
assert_eq!(
|
||||
parse_pos_nonzero("-555"),
|
||||
Err(ParsePosNonzeroError::Creation(CreationError::Negative))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
assert_eq!(
|
||||
parse_pos_nonzero("0"),
|
||||
Err(ParsePosNonzeroError::Creation(CreationError::Zero))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_positive() {
|
||||
let x = PositiveNonzeroInteger::new(42);
|
||||
assert!(x.is_ok());
|
||||
assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap()));
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
// errorsn.rs
|
||||
// This is a bigger error exercise than the previous ones!
|
||||
// You can do it! :)
|
||||
//
|
||||
// Edit the `read_and_validate` function so that it compiles and
|
||||
// passes the tests... so many things could go wrong!
|
||||
//
|
||||
// - Reading from stdin could produce an io::Error
|
||||
// - Parsing the input could produce a num::ParseIntError
|
||||
// - Validating the input could produce a CreationError (defined below)
|
||||
//
|
||||
// How can we lump these errors into one general error? That is, what
|
||||
// type goes where the question marks are, and how do we return
|
||||
// that type from the body of read_and_validate?
|
||||
//
|
||||
// Execute `rustlings hint errorsn` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
// PositiveNonzeroInteger is a struct defined below the tests.
|
||||
fn read_and_validate(b: &mut dyn io::BufRead) -> Result<PositiveNonzeroInteger, ???> {
|
||||
let mut line = String::new();
|
||||
b.read_line(&mut line);
|
||||
let num: i64 = line.trim().parse();
|
||||
let answer = PositiveNonzeroInteger::new(num);
|
||||
answer
|
||||
}
|
||||
|
||||
// This is a test helper function that turns a &str into a BufReader.
|
||||
fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<dyn error::Error>> {
|
||||
let mut b = io::BufReader::new(s.as_bytes());
|
||||
read_and_validate(&mut b)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_success() {
|
||||
let x = test_with_str("42\n");
|
||||
assert_eq!(PositiveNonzeroInteger(42), x.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_num() {
|
||||
let x = test_with_str("eleven billion\n");
|
||||
assert!(x.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_non_positive() {
|
||||
let x = test_with_str("-40\n");
|
||||
assert!(x.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ioerror() {
|
||||
struct Broken;
|
||||
impl io::Read for Broken {
|
||||
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
|
||||
Err(io::Error::new(io::ErrorKind::BrokenPipe, "uh-oh!"))
|
||||
}
|
||||
}
|
||||
let mut b = io::BufReader::new(Broken);
|
||||
assert!(read_and_validate(&mut b).is_err());
|
||||
assert_eq!("uh-oh!", read_and_validate(&mut b).unwrap_err().to_string());
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
impl PositiveNonzeroInteger {
|
||||
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
|
||||
if value == 0 {
|
||||
Err(CreationError::Zero)
|
||||
} else if value < 0 {
|
||||
Err(CreationError::Negative)
|
||||
} else {
|
||||
Ok(PositiveNonzeroInteger(value as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_positive_nonzero_integer_creation() {
|
||||
assert!(PositiveNonzeroInteger::new(10).is_ok());
|
||||
assert_eq!(
|
||||
Err(CreationError::Negative),
|
||||
PositiveNonzeroInteger::new(-10)
|
||||
);
|
||||
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum CreationError {
|
||||
Negative,
|
||||
Zero,
|
||||
}
|
||||
|
||||
impl fmt::Display for CreationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str((self as &dyn error::Error).description())
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CreationError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
CreationError::Negative => "Negative",
|
||||
CreationError::Zero => "Zero",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// option1.rs
|
||||
// This example panics because the second time it calls `pop`, the `vec`
|
||||
// is empty, so `pop` returns `None`, and `unwrap` panics if it's called
|
||||
// on `None`. Handle this in a more graceful way than calling `unwrap`!
|
||||
// Execute `rustlings hint option1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn pop_too_much() -> bool {
|
||||
let mut list = vec![3];
|
||||
|
||||
let last = list.pop().unwrap();
|
||||
println!("The last item in the list is {:?}", last);
|
||||
|
||||
let second_to_last = list.pop().unwrap();
|
||||
println!(
|
||||
"The second-to-last item in the list is {:?}",
|
||||
second_to_last
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_not_panic() {
|
||||
assert!(pop_too_much());
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
### Functions
|
||||
# Functions
|
||||
|
||||
Here, you'll learn how to write functions and how Rust's compiler can trace things way back.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
call_me(3);
|
||||
}
|
||||
|
||||
fn call_me(num) {
|
||||
fn call_me(num:) {
|
||||
for i in 0..num {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
call_me();
|
||||
}
|
||||
|
||||
fn call_me(num: i32) {
|
||||
fn call_me(num: u32) {
|
||||
for i in 0..num {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
|
||||
11
exercises/generics/README.md
Normal file
11
exercises/generics/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Generics
|
||||
|
||||
Generics is the topic of generalizing types and functionalities to broader cases.
|
||||
This is extremely useful for reducing code duplication in many ways, but can call for rather involving syntax.
|
||||
Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid.
|
||||
The simplest and most common use of generics is for type parameters.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html)
|
||||
- [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html)
|
||||
11
exercises/generics/generics1.rs
Normal file
11
exercises/generics/generics1.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
// This shopping list program isn't compiling!
|
||||
// Use your knowledge of generics to fix it.
|
||||
|
||||
// Execute `rustlings hint generics1` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut shopping_list: Vec<?> = Vec::new();
|
||||
shopping_list.push("milk");
|
||||
}
|
||||
31
exercises/generics/generics2.rs
Normal file
31
exercises/generics/generics2.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
// This powerful wrapper provides the ability to store a positive integer value.
|
||||
// Rewrite it using generics so that it supports wrapping ANY type.
|
||||
|
||||
// Execute `rustlings hint generics2` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
struct Wrapper {
|
||||
value: u32,
|
||||
}
|
||||
|
||||
impl Wrapper {
|
||||
pub fn new(value: u32) -> Self {
|
||||
Wrapper { value }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn store_u32_in_wrapper() {
|
||||
assert_eq!(Wrapper::new(42).value, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store_str_in_wrapper() {
|
||||
assert_eq!(Wrapper::new("Foo").value, "Foo");
|
||||
}
|
||||
}
|
||||
58
exercises/generics/generics3.rs
Normal file
58
exercises/generics/generics3.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
// An imaginary magical school has a new report card generation system written in Rust!
|
||||
// Currently the system only supports creating report cards where the student's grade
|
||||
// is represented numerically (e.g. 1.0 -> 5.5).
|
||||
// However, the school also issues alphabetical grades (A+ -> F-) and needs
|
||||
// to be able to print both types of report card!
|
||||
|
||||
// Make the necessary code changes in the struct ReportCard and the impl block
|
||||
// to support alphabetical report cards. Change the Grade in the second test to "A+"
|
||||
// to show that your changes allow alphabetical grades.
|
||||
|
||||
// Execute 'rustlings hint generics3' for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub struct ReportCard {
|
||||
pub grade: f32,
|
||||
pub student_name: String,
|
||||
pub student_age: u8,
|
||||
}
|
||||
|
||||
impl ReportCard {
|
||||
pub fn print(&self) -> String {
|
||||
format!("{} ({}) - achieved a grade of {}",
|
||||
&self.student_name, &self.student_age, &self.grade)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn generate_numeric_report_card() {
|
||||
let report_card = ReportCard {
|
||||
grade: 2.1,
|
||||
student_name: "Tom Wriggle".to_string(),
|
||||
student_age: 12,
|
||||
};
|
||||
assert_eq!(
|
||||
report_card.print(),
|
||||
"Tom Wriggle (12) - achieved a grade of 2.1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_alphabetic_report_card() {
|
||||
// TODO: Make sure to change the grade here after you finish the exercise.
|
||||
let report_card = ReportCard {
|
||||
grade: 2.1,
|
||||
student_name: "Gary Plotter".to_string(),
|
||||
student_age: 11,
|
||||
};
|
||||
assert_eq!(
|
||||
report_card.print(),
|
||||
"Gary Plotter (11) - achieved a grade of A+"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
### If
|
||||
# If
|
||||
|
||||
`if`, the most basic type of control flow, is what you'll learn here.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions)
|
||||
|
||||
36
exercises/if/if2.rs
Normal file
36
exercises/if/if2.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
// if2.rs
|
||||
|
||||
// Step 1: Make me compile!
|
||||
// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
|
||||
// Execute the command `rustlings hint if2` if you want a hint :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn fizz_if_foo(fizzish: &str) -> &str {
|
||||
if fizzish == "fizz" {
|
||||
"foo"
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
// No test changes needed!
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn foo_for_fizz() {
|
||||
assert_eq!(fizz_if_foo("fizz"), "foo")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bar_for_fuzz() {
|
||||
assert_eq!(fizz_if_foo("fuzz"), "bar")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_to_baz() {
|
||||
assert_eq!(fizz_if_foo("literally anything"), "baz")
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
### Macros
|
||||
# Macros
|
||||
|
||||
Rust's macro system is very powerful, but also kind of difficult to wrap your
|
||||
head around. We're not going to teach you how to write your own fully-featured
|
||||
modules, instead we'll show you how to use and create them.
|
||||
macros. Instead, we'll show you how to use and create them.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html)
|
||||
- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
### Modules
|
||||
# Modules
|
||||
|
||||
In this section we'll give you an introduction to Rust's module system.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [The Module System](https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
### Move Semantics
|
||||
# Move Semantics
|
||||
|
||||
These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!!
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
For this section, the book links are especially important.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// move_semantics4.rs
|
||||
// Refactor this code so that instead of having `vec0` and creating the vector
|
||||
// in `fn main`, we instead create it within `fn fill_vec` and transfer the
|
||||
// in `fn main`, we create it within `fn fill_vec` and transfer the
|
||||
// freshly created vector from fill_vec to its caller.
|
||||
// Execute `rustlings hint move_semantics4` for hints!
|
||||
|
||||
@@ -18,7 +18,7 @@ fn main() {
|
||||
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
|
||||
}
|
||||
|
||||
// `fill_vec()` no longer take `vec: Vec<i32>` as argument
|
||||
// `fill_vec()` no longer takes `vec: Vec<i32>` as argument
|
||||
fn fill_vec() -> Vec<i32> {
|
||||
let mut vec = vec;
|
||||
|
||||
|
||||
15
exercises/move_semantics/move_semantics5.rs
Normal file
15
exercises/move_semantics/move_semantics5.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
// move_semantics5.rs
|
||||
// Make me compile without adding, removing, or changing any of the
|
||||
// lines in `main()`.
|
||||
// Execute `rustlings hint move_semantics5` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut x = 100;
|
||||
let y = &mut x;
|
||||
let z = &mut *y;
|
||||
*y += 100;
|
||||
*z += 1000;
|
||||
assert_eq!(x, 1200);
|
||||
}
|
||||
18
exercises/option/README.md
Normal file
18
exercises/option/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Option
|
||||
|
||||
Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
|
||||
Option types are very common in Rust code, as they have a number of uses:
|
||||
- Initial values
|
||||
- Return values for functions that are not defined over their entire input range (partial functions)
|
||||
- Return value for otherwise reporting simple errors, where None is returned on error
|
||||
- Optional struct fields
|
||||
- Struct fields that can be loaned or "taken"
|
||||
- Optional function arguments
|
||||
- Nullable pointers
|
||||
- Swapping things out of difficult situations
|
||||
|
||||
## Further Information
|
||||
|
||||
- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions)
|
||||
- [Option Module Documentation](https://doc.rust-lang.org/std/option/)
|
||||
- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)
|
||||
23
exercises/option/option1.rs
Normal file
23
exercises/option/option1.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
// option1.rs
|
||||
// Make me compile! Execute `rustlings hint option1` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// you can modify anything EXCEPT for this function's sig
|
||||
fn print_number(maybe_number: Option<u16>) {
|
||||
println!("printing: {}", maybe_number.unwrap());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print_number(13);
|
||||
print_number(99);
|
||||
|
||||
let mut numbers: [Option<u16>; 5];
|
||||
for iter in 0..5 {
|
||||
let number_to_add: u16 = {
|
||||
((iter * 1235) + 2) / (4 * 16)
|
||||
};
|
||||
|
||||
numbers[iter as usize] = number_to_add;
|
||||
}
|
||||
}
|
||||
25
exercises/option/option2.rs
Normal file
25
exercises/option/option2.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
// option2.rs
|
||||
// Make me compile! Execute `rustlings hint option2` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let optional_word = Some(String::from("rustlings"));
|
||||
// TODO: Make this an if let statement whose value is "Some" type
|
||||
word = optional_word {
|
||||
println!("The word is: {}", word);
|
||||
} else {
|
||||
println!("The optional word doesn't contain anything");
|
||||
}
|
||||
|
||||
let mut optional_integers_vec: Vec<Option<i8>> = Vec::new();
|
||||
for x in 1..10 {
|
||||
optional_integers_vec.push(Some(x));
|
||||
}
|
||||
|
||||
// TODO: make this a while let statement - remember that vector.pop also adds another layer of Option<T>
|
||||
// You can stack `Option<T>`'s into while let and if let
|
||||
integer = optional_integers_vec.pop() {
|
||||
println!("current value: {}", integer);
|
||||
}
|
||||
}
|
||||
19
exercises/option/option3.rs
Normal file
19
exercises/option/option3.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
// option3.rs
|
||||
// Make me compile! Execute `rustlings hint option3` for hints
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let y: Option<Point> = Some(Point { x: 100, y: 200 });
|
||||
|
||||
match y {
|
||||
Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y),
|
||||
_ => println!("no match"),
|
||||
}
|
||||
y; // Fix without deleting this line.
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
### Primitive Types
|
||||
# Primitive Types
|
||||
|
||||
Rust has a couple of basic types that are directly implemented into the
|
||||
compiler. In this section, we'll go through the most important ones.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html)
|
||||
- [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// primitive_types3.rs
|
||||
// Create an array with at least 100 elements in it where the ??? is.
|
||||
// Create an array with at least 100 elements in it where the ??? is.
|
||||
// Execute `rustlings hint primitive_types3` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
// primitive_types6.rs
|
||||
// Use a tuple index to access the second element of `numbers`.
|
||||
// You can put this right into the `println!` where the ??? is.
|
||||
// You can put the expression for the second element where ??? is so that the test passes.
|
||||
// Execute `rustlings hint primitive_types6` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
#[test]
|
||||
fn indexing_tuple() {
|
||||
let numbers = (1, 2, 3);
|
||||
println!("The second number is {}", ???);
|
||||
// Replace below ??? with the tuple indexing syntax.
|
||||
let second = ???;
|
||||
|
||||
assert_eq!(2, second,
|
||||
"This is not the 2nd number in the tuple!")
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// test1.rs
|
||||
// This is a test for the following sections:
|
||||
// quiz1.rs
|
||||
// This is a quiz for the following sections:
|
||||
// - Variables
|
||||
// - Functions
|
||||
|
||||
// Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy
|
||||
// more than 40 at once, each apple only costs 1! Write a function that calculates
|
||||
// the price of an order of apples given the order amount. No hints this time!
|
||||
// the price of an order of apples given the quantity bought. No hints this time!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
#[test]
|
||||
fn verify_test() {
|
||||
let price1 = calculate_apple_price(35);
|
||||
let price2 = calculate_apple_price(65);
|
||||
let price2 = calculate_apple_price(40);
|
||||
let price3 = calculate_apple_price(65);
|
||||
|
||||
assert_eq!(70, price1);
|
||||
assert_eq!(65, price2);
|
||||
assert_eq!(80, price2);
|
||||
assert_eq!(65, price3);
|
||||
}
|
||||
30
exercises/quiz2.rs
Normal file
30
exercises/quiz2.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
// quiz2.rs
|
||||
// This is a quiz for the following sections:
|
||||
// - Strings
|
||||
|
||||
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
|
||||
// task is to call one of these two functions on each value depending on what
|
||||
// you think each value is. That is, add either `string_slice` or `string`
|
||||
// before the parentheses on each line. If you're right, it will compile!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn string_slice(arg: &str) {
|
||||
println!("{}", arg);
|
||||
}
|
||||
fn string(arg: String) {
|
||||
println!("{}", arg);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
???("blue");
|
||||
???("red".to_string());
|
||||
???(String::from("hi"));
|
||||
???("rust is fun!".to_owned());
|
||||
???("nice weather".into());
|
||||
???(format!("Interpolation {}", "Station"));
|
||||
???(&String::from("abc")[0..1]);
|
||||
???(" hello there ".trim());
|
||||
???("Happy Monday!".to_string().replace("Mon", "Tues"));
|
||||
???("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// test3.rs
|
||||
// This is a test for the following sections:
|
||||
// quiz3.rs
|
||||
// This is a quiz for the following sections:
|
||||
// - Tests
|
||||
|
||||
// This test isn't testing our function -- make it do that in such a way that
|
||||
// This quiz isn't testing our function -- make it do that in such a way that
|
||||
// the test passes. Then write a second test that tests that we get the result
|
||||
// we expect to get when we call `times_two` with a negative number.
|
||||
// No hints, you can do this :)
|
||||
@@ -24,6 +24,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn returns_twice_of_negative_numbers() {
|
||||
// TODO write an assert for `times_two(-4)`
|
||||
// TODO replace unimplemented!() with an assert for `times_two(-4)`
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
// test4.rs
|
||||
// This test covers the sections:
|
||||
// quiz4.rs
|
||||
// This quiz covers the sections:
|
||||
// - Modules
|
||||
// - Macros
|
||||
|
||||
// Write a macro that passes the test! No hints this time, you can do it!
|
||||
// Write a macro that passes the quiz! No hints this time, you can do it!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
For the Arc exercise check out the chapter [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) of the Rust Book.
|
||||
# Standard library types
|
||||
|
||||
For the Iterator exercise check out the chapters [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) of the Rust Book and the [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/).
|
||||
Do not adjust your monitors-- iterators1.rs is indeed missing. Iterators is a challenging topic, so we're leaving space for a simpler exercise!
|
||||
This section will teach you about Box, Shared-State Concurrency and Iterators.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html)
|
||||
- [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html)
|
||||
- [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html)
|
||||
- [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/)
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
// arc1.rs
|
||||
// In this exercise, we are given a Vec of u32 called "numbers" with values ranging
|
||||
// from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ]
|
||||
// We would like to use this set of numbers within 8 different threads simultaneously.
|
||||
// Each thread is going to get the sum of every eighth value, with an offset.
|
||||
// The first thread (offset 0), will sum 0, 8, 16, ...
|
||||
// The second thread (offset 1), will sum 1, 9, 17, ...
|
||||
// The third thread (offset 2), will sum 2, 10, 18, ...
|
||||
// ...
|
||||
// The eighth thread (offset 7), will sum 7, 15, 23, ...
|
||||
|
||||
// Because we are using threads, our values need to be thread-safe. Therefore,
|
||||
// we are using Arc. We need to make a change in each of the two TODOs.
|
||||
|
||||
|
||||
// Make this code compile by filling in a value for `shared_numbers` where the
|
||||
// TODO comment is and create an initial binding for `child_numbers`
|
||||
// somewhere. Try not to create any copies of the `numbers` Vec!
|
||||
// first TODO comment is, and create an initial binding for `child_numbers`
|
||||
// where the second TODO comment is. Try not to create any copies of the `numbers` Vec!
|
||||
// Execute `rustlings hint arc1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#![forbid(unused_imports)] // Do not change this, (or the next) line.
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
@@ -15,12 +30,13 @@ fn main() {
|
||||
let mut joinhandles = Vec::new();
|
||||
|
||||
for offset in 0..8 {
|
||||
let child_numbers = // TODO
|
||||
joinhandles.push(thread::spawn(move || {
|
||||
let mut i = offset;
|
||||
let mut sum = 0;
|
||||
while i < child_numbers.len() {
|
||||
sum += child_numbers[i];
|
||||
i += 5;
|
||||
i += 8;
|
||||
}
|
||||
println!("Sum of offset {} is {}", offset, sum);
|
||||
}));
|
||||
|
||||
56
exercises/standard_library_types/box1.rs
Normal file
56
exercises/standard_library_types/box1.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
// box1.rs
|
||||
//
|
||||
// At compile time, Rust needs to know how much space a type takes up. This becomes problematic
|
||||
// for recursive types, where a value can have as part of itself another value of the same type.
|
||||
// To get around the issue, we can use a `Box` - a smart pointer used to store data on the heap,
|
||||
// which also allows us to wrap a recursive type.
|
||||
//
|
||||
// The recursive type we're implementing in this exercise is the `cons list` - a data structure
|
||||
// frequently found in functional programming languages. Each item in a cons list contains two
|
||||
// elements: the value of the current item and the next item. The last item is a value called `Nil`.
|
||||
//
|
||||
// Step 1: use a `Box` in the enum definition to make the code compile
|
||||
// Step 2: create both empty and non-empty cons lists by replacing `unimplemented!()`
|
||||
//
|
||||
// Note: the tests should not be changed
|
||||
//
|
||||
// Execute `rustlings hint box1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum List {
|
||||
Cons(i32, List),
|
||||
Nil,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("This is an empty cons list: {:?}", create_empty_list());
|
||||
println!(
|
||||
"This is a non-empty cons list: {:?}",
|
||||
create_non_empty_list()
|
||||
);
|
||||
}
|
||||
|
||||
pub fn create_empty_list() -> List {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn create_non_empty_list() -> List {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_create_empty_list() {
|
||||
assert_eq!(List::Nil, create_empty_list())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_non_empty_list() {
|
||||
assert_ne!(create_empty_list(), create_non_empty_list())
|
||||
}
|
||||
}
|
||||
24
exercises/standard_library_types/iterators1.rs
Normal file
24
exercises/standard_library_types/iterators1.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
// iterators1.rs
|
||||
//
|
||||
// Make me compile by filling in the `???`s
|
||||
//
|
||||
// When performing operations on elements within a collection, iterators are essential.
|
||||
// This module helps you get familiar with the structure of using an iterator and
|
||||
// how to go through elements within an iterable collection.
|
||||
//
|
||||
// Execute `rustlings hint iterators1` for hints :D
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main () {
|
||||
let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];
|
||||
|
||||
let mut my_iterable_fav_fruits = ???; // TODO: Step 1
|
||||
|
||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));
|
||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2
|
||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));
|
||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1
|
||||
assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
|
||||
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3
|
||||
}
|
||||
@@ -1,26 +1,41 @@
|
||||
// iterators2.rs
|
||||
// In this module, you'll learn some of unique advantages that iterators can offer
|
||||
// Step 1. Complete the `capitalize_first` function to pass the first two cases
|
||||
// Step 2. Apply the `capitalize_first` function to a vector of strings, ensuring that it returns a vector of strings as well
|
||||
// Step 3. Apply the `capitalize_first` function again to a list, but try and ensure it returns a single string
|
||||
// In this exercise, you'll learn some of the unique advantages that iterators
|
||||
// can offer. Follow the steps to complete the exercise.
|
||||
// As always, there are hints if you execute `rustlings hint iterators2`!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Step 1.
|
||||
// Complete the `capitalize_first` function.
|
||||
// "hello" -> "Hello"
|
||||
pub fn capitalize_first(input: &str) -> String {
|
||||
let mut c = input.chars();
|
||||
match c.next() {
|
||||
None => String::new(),
|
||||
Some(first) => first.collect::<String>() + c.as_str(),
|
||||
Some(first) => ???,
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2.
|
||||
// Apply the `capitalize_first` function to a slice of string slices.
|
||||
// Return a vector of strings.
|
||||
// ["hello", "world"] -> ["Hello", "World"]
|
||||
pub fn capitalize_words_vector(words: &[&str]) -> Vec<String> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
// Step 3.
|
||||
// Apply the `capitalize_first` function again to a slice of string slices.
|
||||
// Return a single string.
|
||||
// ["hello", " ", "world"] -> "Hello World"
|
||||
pub fn capitalize_words_string(words: &[&str]) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Step 1.
|
||||
// Tests that verify your `capitalize_first` function implementation
|
||||
#[test]
|
||||
fn test_success() {
|
||||
assert_eq!(capitalize_first("hello"), "Hello");
|
||||
@@ -31,18 +46,15 @@ mod tests {
|
||||
assert_eq!(capitalize_first(""), "");
|
||||
}
|
||||
|
||||
// Step 2.
|
||||
#[test]
|
||||
fn test_iterate_string_vec() {
|
||||
let words = vec!["hello", "world"];
|
||||
let capitalized_words: Vec<String> = // TODO
|
||||
assert_eq!(capitalized_words, ["Hello", "World"]);
|
||||
assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterate_into_string() {
|
||||
let words = vec!["hello", " ", "world"];
|
||||
let capitalized_words = // TODO
|
||||
assert_eq!(capitalized_words, "Hello World");
|
||||
assert_eq!(capitalize_words_string(&words), "Hello World");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
// iterators3.rs
|
||||
// This is a bigger exercise than most of the others! You can do it!
|
||||
// Here is your mission, should you choose to accept it:
|
||||
// 1. Complete the divide function to get the first four tests to pass
|
||||
// 2. Uncomment the last two tests and get them to pass by filling in
|
||||
// values for `x` using `division_results`.
|
||||
// 1. Complete the divide function to get the first four tests to pass.
|
||||
// 2. Get the remaining tests to pass by completing the result_with_list and
|
||||
// list_of_results functions.
|
||||
// Execute `rustlings hint iterators3` to get some hints!
|
||||
// Have fun :-)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
@@ -21,16 +20,28 @@ pub struct NotDivisibleError {
|
||||
divisor: i32,
|
||||
}
|
||||
|
||||
// This function should calculate `a` divided by `b` if `a` is
|
||||
// evenly divisible by b.
|
||||
// Otherwise, it should return a suitable error.
|
||||
// Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
|
||||
// Otherwise, return a suitable error.
|
||||
pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {}
|
||||
|
||||
// Complete the function and return a value of the correct type so the test passes.
|
||||
// Desired output: Ok([1, 11, 1426, 3])
|
||||
fn result_with_list() -> () {
|
||||
let numbers = vec![27, 297, 38502, 81];
|
||||
let division_results = numbers.into_iter().map(|n| divide(n, 27));
|
||||
}
|
||||
|
||||
// Complete the function and return a value of the correct type so the test passes.
|
||||
// Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)]
|
||||
fn list_of_results() -> () {
|
||||
let numbers = vec![27, 297, 38502, 81];
|
||||
let division_results = numbers.into_iter().map(|n| divide(n, 27));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Tests that verify your `divide` function implementation
|
||||
#[test]
|
||||
fn test_success() {
|
||||
assert_eq!(divide(81, 9), Ok(9));
|
||||
@@ -57,22 +68,16 @@ mod tests {
|
||||
assert_eq!(divide(0, 81), Ok(0));
|
||||
}
|
||||
|
||||
// Iterator exercises using your `divide` function
|
||||
/*
|
||||
#[test]
|
||||
fn result_with_list() {
|
||||
let numbers = vec![27, 297, 38502, 81];
|
||||
let division_results = numbers.into_iter().map(|n| divide(n, 27));
|
||||
let x //... Fill in here!
|
||||
assert_eq!(format!("{:?}", x), "Ok([1, 11, 1426, 3])");
|
||||
fn test_result_with_list() {
|
||||
assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_of_results() {
|
||||
let numbers = vec![27, 297, 38502, 81];
|
||||
let division_results = numbers.into_iter().map(|n| divide(n, 27));
|
||||
let x //... Fill in here!
|
||||
assert_eq!(format!("{:?}", x), "[Ok(1), Ok(11), Ok(1426), Ok(3)]");
|
||||
fn test_list_of_results() {
|
||||
assert_eq!(
|
||||
format!("{:?}", list_of_results()),
|
||||
"[Ok(1), Ok(11), Ok(1426), Ok(3)]"
|
||||
);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn factorial(num: u64) -> u64 {
|
||||
// Complete this function to return factorial of num
|
||||
// Complete this function to return the factorial of num
|
||||
// Do not use:
|
||||
// - return
|
||||
// For extra fun don't use:
|
||||
// Try not to use:
|
||||
// - imperative style loops (for, while)
|
||||
// - additional variables
|
||||
// For the most fun don't use:
|
||||
// For an extra challenge, don't use:
|
||||
// - recursion
|
||||
// Execute `rustlings hint iterators4` for hints.
|
||||
}
|
||||
|
||||
123
exercises/standard_library_types/iterators5.rs
Normal file
123
exercises/standard_library_types/iterators5.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
// iterators5.rs
|
||||
|
||||
// Let's define a simple model to track Rustlings exercise progress. Progress
|
||||
// will be modelled using a hash map. The name of the exercise is the key and
|
||||
// the progress is the value. Two counting functions were created to count the
|
||||
// number of exercises with a given progress. These counting functions use
|
||||
// imperative style for loops. Recreate this counting functionality using
|
||||
// iterators. Only the two iterator methods (count_iterator and
|
||||
// count_collection_iterator) need to be modified.
|
||||
// Execute `rustlings hint iterators5` for hints.
|
||||
//
|
||||
// Make the code compile and the tests pass.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Progress {
|
||||
None,
|
||||
Some,
|
||||
Complete,
|
||||
}
|
||||
|
||||
fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
|
||||
let mut count = 0;
|
||||
for val in map.values() {
|
||||
if val == &value {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
|
||||
// map is a hashmap with String keys and Progress values.
|
||||
// map = { "variables1": Complete, "from_str": None, ... }
|
||||
}
|
||||
|
||||
fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
|
||||
let mut count = 0;
|
||||
for map in collection {
|
||||
for val in map.values() {
|
||||
if val == &value {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
|
||||
// collection is a slice of hashmaps.
|
||||
// collection = [{ "variables1": Complete, "from_str": None, ... },
|
||||
// { "variables2": Complete, ... }, ... ]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn count_complete() {
|
||||
let map = get_map();
|
||||
assert_eq!(3, count_iterator(&map, Progress::Complete));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_equals_for() {
|
||||
let map = get_map();
|
||||
assert_eq!(
|
||||
count_for(&map, Progress::Complete),
|
||||
count_iterator(&map, Progress::Complete)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_collection_complete() {
|
||||
let collection = get_vec_map();
|
||||
assert_eq!(
|
||||
6,
|
||||
count_collection_iterator(&collection, Progress::Complete)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn count_collection_equals_for() {
|
||||
let collection = get_vec_map();
|
||||
assert_eq!(
|
||||
count_collection_for(&collection, Progress::Complete),
|
||||
count_collection_iterator(&collection, Progress::Complete)
|
||||
);
|
||||
}
|
||||
|
||||
fn get_map() -> HashMap<String, Progress> {
|
||||
use Progress::*;
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert(String::from("variables1"), Complete);
|
||||
map.insert(String::from("functions1"), Complete);
|
||||
map.insert(String::from("hashmap1"), Complete);
|
||||
map.insert(String::from("arc1"), Some);
|
||||
map.insert(String::from("as_ref_mut"), None);
|
||||
map.insert(String::from("from_str"), None);
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
fn get_vec_map() -> Vec<HashMap<String, Progress>> {
|
||||
use Progress::*;
|
||||
|
||||
let map = get_map();
|
||||
|
||||
let mut other = HashMap::new();
|
||||
other.insert(String::from("variables2"), Complete);
|
||||
other.insert(String::from("functions2"), Complete);
|
||||
other.insert(String::from("if1"), Complete);
|
||||
other.insert(String::from("from_into"), None);
|
||||
other.insert(String::from("try_from_into"), None);
|
||||
|
||||
vec![map, other]
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
### Strings
|
||||
# Strings
|
||||
|
||||
Rust has two string types, a string slice (`&str`) and an owned string (`String`).
|
||||
We're not going to dictate when you should use which one, but we'll show you how
|
||||
to identify and create them, as well as use them.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
### Structs
|
||||
# Structs
|
||||
|
||||
Rust has three struct types: a classic c struct, a tuple struct, and a unit struct.
|
||||
Rust has three struct types: a classic C struct, a tuple struct, and a unit struct.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [Structures](https://doc.rust-lang.org/rust-by-example/custom_types/structs.html)
|
||||
- [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html)
|
||||
- [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// structs2.rs
|
||||
// Address all the TODOs to make the tests pass!
|
||||
// No hints, just do it!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
|
||||
82
exercises/structs/structs3.rs
Normal file
82
exercises/structs/structs3.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
// structs3.rs
|
||||
// Structs contain data, but can also have logic. In this exercise we have
|
||||
// defined the Package struct and we want to test some logic attached to it.
|
||||
// Make the code compile and the tests pass!
|
||||
// If you have issues execute `rustlings hint structs3`
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Package {
|
||||
sender_country: String,
|
||||
recipient_country: String,
|
||||
weight_in_grams: i32,
|
||||
}
|
||||
|
||||
impl Package {
|
||||
fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
|
||||
if weight_in_grams <= 0 {
|
||||
// Something goes here...
|
||||
} else {
|
||||
return Package {
|
||||
sender_country,
|
||||
recipient_country,
|
||||
weight_in_grams,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn is_international(&self) -> ??? {
|
||||
// Something goes here...
|
||||
}
|
||||
|
||||
fn get_fees(&self, cents_per_gram: i32) -> ??? {
|
||||
// Something goes here...
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn fail_creating_weightless_package() {
|
||||
let sender_country = String::from("Spain");
|
||||
let recipient_country = String::from("Austria");
|
||||
|
||||
Package::new(sender_country, recipient_country, -2210);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_international_package() {
|
||||
let sender_country = String::from("Spain");
|
||||
let recipient_country = String::from("Russia");
|
||||
|
||||
let package = Package::new(sender_country, recipient_country, 1200);
|
||||
|
||||
assert!(package.is_international());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_local_package() {
|
||||
let sender_country = String::from("Canada");
|
||||
let recipient_country = sender_country.clone();
|
||||
|
||||
let package = Package::new(sender_country, recipient_country, 1200);
|
||||
|
||||
assert!(!package.is_international());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calculate_transport_fees() {
|
||||
let sender_country = String::from("Spain");
|
||||
let recipient_country = String::from("Spain");
|
||||
|
||||
let cents_per_gram = ???;
|
||||
|
||||
let package = Package::new(sender_country, recipient_country, 1500);
|
||||
|
||||
assert_eq!(package.get_fees(cents_per_gram), 4500);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// test2.rs
|
||||
// This is a test for the following sections:
|
||||
// - Strings
|
||||
|
||||
// Ok, here are a bunch of values-- some are `Strings`, some are `&strs`. Your
|
||||
// task is to call one of these two functions on each value depending on what
|
||||
// you think each value is. That is, add either `string_slice` or `string`
|
||||
// before the parentheses on each line. If you're right, it will compile!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn string_slice(arg: &str) {
|
||||
println!("{}", arg);
|
||||
}
|
||||
fn string(arg: String) {
|
||||
println!("{}", arg);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
("blue");
|
||||
("red".to_string());
|
||||
(String::from("hi"));
|
||||
("rust is fun!".to_owned());
|
||||
("nice weather".into());
|
||||
(format!("Interpolation {}", "Station"));
|
||||
(&String::from("abc")[0..1]);
|
||||
(" hello there ".trim());
|
||||
("Happy Monday!".to_string().replace("Mon", "Tues"));
|
||||
("mY sHiFt KeY iS sTiCkY".to_lowercase());
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
### Tests
|
||||
# Tests
|
||||
|
||||
Going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass!
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html)
|
||||
|
||||
@@ -18,4 +18,9 @@ mod tests {
|
||||
fn is_true_when_even() {
|
||||
assert!();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_false_when_odd() {
|
||||
assert!();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,9 @@
|
||||
For this exercise check out the [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) and the chapter [Concurrency](https://doc.rust-lang.org/book/ch16-01-threads.html) of the Rust Book.
|
||||
# Threads
|
||||
|
||||
In most current operating systems, an executed program’s code is run in a process, and the operating system manages multiple processes at once.
|
||||
Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html)
|
||||
- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// threads1.rs
|
||||
// Make this compile! Execute `rustlings hint threads1` for hints :)
|
||||
// The idea is the thread spawned on line 21 is completing jobs while the main thread is
|
||||
// monitoring progress until 10 jobs are completed. If you see 6 lines
|
||||
// The idea is the thread spawned on line 22 is completing jobs while the main thread is
|
||||
// monitoring progress until 10 jobs are completed. Because of the difference between the
|
||||
// spawned threads' sleep time, and the waiting threads sleep time, when you see 6 lines
|
||||
// of "waiting..." and the program ends without timing out when running,
|
||||
// you've got it :)
|
||||
|
||||
|
||||
19
exercises/traits/README.md
Normal file
19
exercises/traits/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Traits
|
||||
|
||||
A trait is a collection of methods.
|
||||
|
||||
Data types can implement traits. To do so, the methods making up the trait are defined for the data type. For example, the `String` data type implements the `From<&str>` trait. This allows a user to write `String::from("hello")`.
|
||||
|
||||
In this way, traits are somewhat similar to Java interfaces and C++ abstract classes.
|
||||
|
||||
Some additional common Rust traits include:
|
||||
- `Clone` (the `clone` method)
|
||||
- `Display` (which allows formatted display via `{}`)
|
||||
- `Debug` (which allows formatted display via `{:?}`)
|
||||
|
||||
Because traits indicate shared behavior between data types, they are useful when writing generics.
|
||||
|
||||
|
||||
## Further information
|
||||
|
||||
- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html)
|
||||
@@ -1,21 +1,21 @@
|
||||
// traits1.rs
|
||||
// Time to implement some traits!
|
||||
//
|
||||
//
|
||||
// Your task is to implement the trait
|
||||
// `AppendBar' for the type `String'.
|
||||
//
|
||||
//
|
||||
// The trait AppendBar has only one function,
|
||||
// which appends "Bar" to any object
|
||||
// implementing this trait.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
trait AppendBar {
|
||||
fn append_bar(self) -> Self;
|
||||
}
|
||||
|
||||
impl AppendBar for String {
|
||||
//Add your code here
|
||||
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -40,5 +40,4 @@ mod tests {
|
||||
String::from("BarBar")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// traits2.rs
|
||||
//
|
||||
//
|
||||
// Your task is to implement the trait
|
||||
// `AppendBar' for a vector of strings.
|
||||
//
|
||||
//
|
||||
// To implement this trait, consider for
|
||||
// a moment what it means to 'append "Bar"'
|
||||
// to a vector of strings.
|
||||
//
|
||||
//
|
||||
// No boiler plate code this time,
|
||||
// you can do this!
|
||||
|
||||
@@ -18,9 +18,6 @@ trait AppendBar {
|
||||
|
||||
//TODO: Add your code here
|
||||
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -31,5 +28,4 @@ mod tests {
|
||||
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
|
||||
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
### Variables
|
||||
# Variables
|
||||
|
||||
Here you'll learn about simple variables.
|
||||
In Rust, variables are immutable by default.
|
||||
When a variable is immutable, once a value is bound to a name, you can’t change that value.
|
||||
You can make them mutable by adding mut in front of the variable name.
|
||||
|
||||
#### Book Sections
|
||||
## Further information
|
||||
|
||||
- [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html)
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
fn main() {
|
||||
let x = 3;
|
||||
println!("Number {}", x);
|
||||
x = 5;
|
||||
x = 5; // don't change this line
|
||||
println!("Number {}", x);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let number = "3";
|
||||
println!("Number {}", number);
|
||||
let number = "T-H-R-E-E"; // don't change this line
|
||||
println!("Spell a Number : {}", number);
|
||||
number = 3;
|
||||
println!("Number {}", number);
|
||||
println!("Number plus two is : {}", number + 2);
|
||||
}
|
||||
|
||||
9
exercises/variables/variables6.rs
Normal file
9
exercises/variables/variables6.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
// variables6.rs
|
||||
// Make me compile! Execute the command `rustlings hint variables6` if you want a hint :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
const NUMBER = 3;
|
||||
fn main() {
|
||||
println!("Number {}", NUMBER);
|
||||
}
|
||||
@@ -35,7 +35,7 @@ if (Get-Command cargo -ErrorAction SilentlyContinue) {
|
||||
function vercomp($v1, $v2) {
|
||||
if ($v1 -eq $v2) {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
$v1 = $v1.Replace(".", "0")
|
||||
$v2 = $v2.Replace(".", "0")
|
||||
@@ -53,7 +53,7 @@ function vercomp($v1, $v2) {
|
||||
}
|
||||
|
||||
$rustVersion = $(rustc --version).Split(" ")[1]
|
||||
$minRustVersion = "1.31"
|
||||
$minRustVersion = "1.39"
|
||||
if ((vercomp $rustVersion $minRustVersion) -eq 2) {
|
||||
Write-Host "WARNING: Rust version is too old: $rustVersion - needs at least $minRustVersion"
|
||||
Write-Host "Please update Rust with 'rustup update'"
|
||||
|
||||
42
install.sh
42
install.sh
@@ -30,6 +30,22 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Look up python installations, starting with 3 with a fallback of 2
|
||||
if [ -x "$(command -v python3)" ]
|
||||
then
|
||||
PY="$(command -v python3)"
|
||||
elif [ -x "$(command -v python)" ]
|
||||
then
|
||||
PY="$(command -v python)"
|
||||
elif [ -x "$(command -v python2)" ]
|
||||
then
|
||||
PY="$(command -v python2)"
|
||||
else
|
||||
echo "ERROR: No working python installation was found"
|
||||
echo "Please install python and add it to the PATH variable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
|
||||
# Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2.
|
||||
function vercomp() {
|
||||
@@ -71,7 +87,7 @@ function vercomp() {
|
||||
}
|
||||
|
||||
RustVersion=$(rustc --version | cut -d " " -f 2)
|
||||
MinRustVersion=1.31
|
||||
MinRustVersion=1.39
|
||||
vercomp $RustVersion $MinRustVersion
|
||||
if [ $? -eq 2 ]
|
||||
then
|
||||
@@ -86,12 +102,30 @@ Path=${1:-rustlings/}
|
||||
echo "Cloning Rustlings at $Path..."
|
||||
git clone -q https://github.com/rust-lang/rustlings $Path
|
||||
|
||||
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | python -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
|
||||
cd $Path
|
||||
|
||||
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | ${PY} -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
|
||||
CargoBin="${CARGO_HOME:-$HOME/.cargo}/bin"
|
||||
|
||||
if [[ -z ${Version} ]]
|
||||
then
|
||||
echo "The latest tag version could not be fetched remotely."
|
||||
echo "Using the local git repository..."
|
||||
Version=$(ls -tr .git/refs/tags/ | tail -1)
|
||||
if [[ -z ${Version} ]]
|
||||
then
|
||||
echo "No valid tag version found"
|
||||
echo "Rustlings will be installed using the main branch"
|
||||
Version="main"
|
||||
else
|
||||
Version="tags/${Version}"
|
||||
fi
|
||||
else
|
||||
Version="tags/${Version}"
|
||||
fi
|
||||
|
||||
echo "Checking out version $Version..."
|
||||
cd $Path
|
||||
git checkout -q tags/$Version
|
||||
git checkout -q ${Version}
|
||||
|
||||
echo "Installing the 'rustlings' executable..."
|
||||
cargo install --force --path .
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use regex::Regex;
|
||||
use serde::Deserialize;
|
||||
use std::env;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fs::{self, remove_file, File};
|
||||
use std::io::Read;
|
||||
@@ -11,15 +12,26 @@ const I_AM_DONE_REGEX: &str = r"(?m)^\s*///?\s*I\s+AM\s+NOT\s+DONE";
|
||||
const CONTEXT: usize = 2;
|
||||
const CLIPPY_CARGO_TOML_PATH: &str = "./exercises/clippy/Cargo.toml";
|
||||
|
||||
// Get a temporary file name that is hopefully unique
|
||||
#[inline]
|
||||
fn temp_file() -> String {
|
||||
format!("./temp_{}", process::id())
|
||||
let thread_id: String = format!("{:?}", std::thread::current().id())
|
||||
.chars()
|
||||
.filter(|c| c.is_alphanumeric())
|
||||
.collect();
|
||||
|
||||
format!("./temp_{}_{}", process::id(), thread_id)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Copy, Clone)]
|
||||
// The mode of the exercise.
|
||||
#[derive(Deserialize, Copy, Clone, Debug)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Mode {
|
||||
// Indicates that the exercise should be compiled as a binary
|
||||
Compile,
|
||||
// Indicates that the exercise should be compiled as a test harness
|
||||
Test,
|
||||
// Indicates that the exercise should be linted with clippy
|
||||
Clippy,
|
||||
}
|
||||
|
||||
@@ -28,41 +40,60 @@ pub struct ExerciseList {
|
||||
pub exercises: Vec<Exercise>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
// A representation of a rustlings exercise.
|
||||
// This is deserialized from the accompanying info.toml file
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Exercise {
|
||||
// Name of the exercise
|
||||
pub name: String,
|
||||
// The path to the file containing the exercise's source code
|
||||
pub path: PathBuf,
|
||||
// The mode of the exercise (Test, Compile, or Clippy)
|
||||
pub mode: Mode,
|
||||
// The hint text associated with the exercise
|
||||
pub hint: String,
|
||||
}
|
||||
|
||||
// An enum to track of the state of an Exercise.
|
||||
// An Exercise can be either Done or Pending
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum State {
|
||||
// The state of the exercise once it's been completed
|
||||
Done,
|
||||
// The state of the exercise while it's not completed yet
|
||||
Pending(Vec<ContextLine>),
|
||||
}
|
||||
|
||||
// The context information of a pending exercise
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct ContextLine {
|
||||
// The source code that is still pending completion
|
||||
pub line: String,
|
||||
// The line number of the source code still pending completion
|
||||
pub number: usize,
|
||||
// Whether or not this is important
|
||||
pub important: bool,
|
||||
}
|
||||
|
||||
// The result of compiling an exercise
|
||||
pub struct CompiledExercise<'a> {
|
||||
exercise: &'a Exercise,
|
||||
_handle: FileHandle,
|
||||
}
|
||||
|
||||
impl<'a> CompiledExercise<'a> {
|
||||
// Run the compiled exercise
|
||||
pub fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
|
||||
self.exercise.run()
|
||||
}
|
||||
}
|
||||
|
||||
// A representation of an already executed binary
|
||||
#[derive(Debug)]
|
||||
pub struct ExerciseOutput {
|
||||
// The textual contents of the standard output of the binary
|
||||
pub stdout: String,
|
||||
// The textual contents of the standard error of the binary
|
||||
pub stderr: String,
|
||||
}
|
||||
|
||||
@@ -96,11 +127,24 @@ name = "{}"
|
||||
path = "{}.rs""#,
|
||||
self.name, self.name, self.name
|
||||
);
|
||||
fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml)
|
||||
.expect("Failed to write 📎 Clippy 📎 Cargo.toml file.");
|
||||
let cargo_toml_error_msg = if env::var("NO_EMOJI").is_ok() {
|
||||
"Failed to write Clippy Cargo.toml file."
|
||||
} else {
|
||||
"Failed to write 📎 Clippy 📎 Cargo.toml file."
|
||||
};
|
||||
fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml).expect(cargo_toml_error_msg);
|
||||
// To support the ability to run the clipy exercises, build
|
||||
// an executable, in addition to running clippy. With a
|
||||
// compilation failure, this would silently fail. But we expect
|
||||
// clippy to reflect the same failure while compiling later.
|
||||
Command::new("rustc")
|
||||
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output()
|
||||
.expect("Failed to compile!");
|
||||
// Due to an issue with Clippy, a cargo clean is required to catch all lints.
|
||||
// See https://github.com/rust-lang/rust-clippy/issues/2604
|
||||
// This is already fixed on master branch. See this issue to track merging into Cargo:
|
||||
// This is already fixed on Clippy's master branch. See this issue to track merging into Cargo:
|
||||
// https://github.com/rust-lang/rust-clippy/issues/3837
|
||||
Command::new("cargo")
|
||||
.args(&["clean", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
|
||||
@@ -131,7 +175,12 @@ path = "{}.rs""#,
|
||||
}
|
||||
|
||||
fn run(&self) -> Result<ExerciseOutput, ExerciseOutput> {
|
||||
let arg = match self.mode {
|
||||
Mode::Test => "--show-output",
|
||||
_ => "",
|
||||
};
|
||||
let cmd = Command::new(&temp_file())
|
||||
.arg(arg)
|
||||
.output()
|
||||
.expect("Failed to run 'run' command");
|
||||
|
||||
@@ -188,6 +237,16 @@ path = "{}.rs""#,
|
||||
|
||||
State::Pending(context)
|
||||
}
|
||||
|
||||
// Check that the exercise looks to be solved using self.state()
|
||||
// This is not the best way to check since
|
||||
// the user can just remove the "I AM NOT DONE" string from the file
|
||||
// without actually having solved anything.
|
||||
// The only other way to truly check this would to compile and run
|
||||
// the exercise; which would be both costly and counterintuitive
|
||||
pub fn looks_done(&self) -> bool {
|
||||
self.state() == State::Done
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Exercise {
|
||||
@@ -196,6 +255,7 @@ impl Display for Exercise {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clean() {
|
||||
let _ignored = remove_file(&temp_file());
|
||||
}
|
||||
@@ -271,4 +331,16 @@ mod test {
|
||||
|
||||
assert_eq!(exercise.state(), State::Done);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exercise_with_output() {
|
||||
let exercise = Exercise {
|
||||
name: "exercise_with_output".into(),
|
||||
path: PathBuf::from("tests/fixture/success/testSuccess.rs"),
|
||||
mode: Mode::Test,
|
||||
hint: String::new(),
|
||||
};
|
||||
let out = exercise.compile().unwrap().run().unwrap();
|
||||
assert!(out.stdout.contains("THIS TEST TOO SHALL PASS"));
|
||||
}
|
||||
}
|
||||
|
||||
295
src/main.rs
295
src/main.rs
@@ -1,13 +1,13 @@
|
||||
use crate::exercise::{Exercise, ExerciseList};
|
||||
use crate::run::run;
|
||||
use crate::verify::verify;
|
||||
use clap::{crate_version, App, Arg, SubCommand};
|
||||
use argh::FromArgs;
|
||||
use console::Emoji;
|
||||
use notify::DebouncedEvent;
|
||||
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::io::{self, prelude::*};
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc::channel;
|
||||
@@ -22,28 +22,91 @@ mod exercise;
|
||||
mod run;
|
||||
mod verify;
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("rustlings")
|
||||
.version(crate_version!())
|
||||
.author("Olivia Hugger, Carol Nichols")
|
||||
.about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
|
||||
.subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
|
||||
.subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
|
||||
.subcommand(
|
||||
SubCommand::with_name("run")
|
||||
.alias("r")
|
||||
.about("Runs/Tests a single exercise")
|
||||
.arg(Arg::with_name("name").required(true).index(1)),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("hint")
|
||||
.alias("h")
|
||||
.about("Returns a hint for the current exercise")
|
||||
.arg(Arg::with_name("name").required(true).index(1)),
|
||||
)
|
||||
.get_matches();
|
||||
// In sync with crate version
|
||||
const VERSION: &str = "4.5.0";
|
||||
|
||||
if None == matches.subcommand_name() {
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
|
||||
struct Args {
|
||||
/// show outputs from the test exercises
|
||||
#[argh(switch)]
|
||||
nocapture: bool,
|
||||
/// show the executable version
|
||||
#[argh(switch, short = 'v')]
|
||||
version: bool,
|
||||
#[argh(subcommand)]
|
||||
nested: Option<Subcommands>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand)]
|
||||
enum Subcommands {
|
||||
Verify(VerifyArgs),
|
||||
Watch(WatchArgs),
|
||||
Run(RunArgs),
|
||||
Hint(HintArgs),
|
||||
List(ListArgs),
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "verify")]
|
||||
/// Verifies all exercises according to the recommended order
|
||||
struct VerifyArgs {}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "watch")]
|
||||
/// Reruns `verify` when files were edited
|
||||
struct WatchArgs {}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "run")]
|
||||
/// Runs/Tests a single exercise
|
||||
struct RunArgs {
|
||||
#[argh(positional)]
|
||||
/// the name of the exercise
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "hint")]
|
||||
/// Returns a hint for the given exercise
|
||||
struct HintArgs {
|
||||
#[argh(positional)]
|
||||
/// the name of the exercise
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "list")]
|
||||
/// Lists the exercises available in Rustlings
|
||||
struct ListArgs {
|
||||
#[argh(switch, short = 'p')]
|
||||
/// show only the paths of the exercises
|
||||
paths: bool,
|
||||
#[argh(switch, short = 'n')]
|
||||
/// show only the names of the exercises
|
||||
names: bool,
|
||||
#[argh(option, short = 'f')]
|
||||
/// provide a string to match exercise names
|
||||
/// comma separated patterns are acceptable
|
||||
filter: Option<String>,
|
||||
#[argh(switch, short = 'u')]
|
||||
/// display only exercises not yet solved
|
||||
unsolved: bool,
|
||||
#[argh(switch, short = 's')]
|
||||
/// display only exercises that have been solved
|
||||
solved: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Args = argh::from_env();
|
||||
|
||||
if args.version {
|
||||
println!("v{}", VERSION);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
if args.nested.is_none() {
|
||||
println!();
|
||||
println!(r#" welcome to... "#);
|
||||
println!(r#" _ _ _ "#);
|
||||
@@ -73,73 +136,146 @@ fn main() {
|
||||
|
||||
let toml_str = &fs::read_to_string("info.toml").unwrap();
|
||||
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
|
||||
let verbose = args.nocapture;
|
||||
|
||||
if let Some(ref matches) = matches.subcommand_matches("run") {
|
||||
let name = matches.value_of("name").unwrap();
|
||||
|
||||
let matching_exercise = |e: &&Exercise| name == e.name;
|
||||
|
||||
let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| {
|
||||
println!("No exercise found for your given name!");
|
||||
std::process::exit(1)
|
||||
});
|
||||
|
||||
run(&exercise).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
if let Some(ref matches) = matches.subcommand_matches("hint") {
|
||||
let name = matches.value_of("name").unwrap();
|
||||
|
||||
let exercise = exercises
|
||||
.iter()
|
||||
.find(|e| name == e.name)
|
||||
.unwrap_or_else(|| {
|
||||
println!("No exercise found for your given name!");
|
||||
std::process::exit(1)
|
||||
let command = args.nested.unwrap_or_else(|| {
|
||||
let text = fs::read_to_string("default_out.txt").unwrap();
|
||||
println!("{}", text);
|
||||
std::process::exit(0);
|
||||
});
|
||||
match command {
|
||||
Subcommands::List(subargs) => {
|
||||
if !subargs.paths && !subargs.names {
|
||||
println!("{:<17}\t{:<46}\t{:<7}", "Name", "Path", "Status");
|
||||
}
|
||||
let mut exercises_done: u16 = 0;
|
||||
let filters = subargs.filter.clone().unwrap_or_default().to_lowercase();
|
||||
exercises.iter().for_each(|e| {
|
||||
let fname = format!("{}", e.path.display());
|
||||
let filter_cond = filters
|
||||
.split(',')
|
||||
.filter(|f| !f.trim().is_empty())
|
||||
.any(|f| e.name.contains(&f) || fname.contains(&f));
|
||||
let status = if e.looks_done() {
|
||||
exercises_done += 1;
|
||||
"Done"
|
||||
} else {
|
||||
"Pending"
|
||||
};
|
||||
let solve_cond = {
|
||||
(e.looks_done() && subargs.solved)
|
||||
|| (!e.looks_done() && subargs.unsolved)
|
||||
|| (!subargs.solved && !subargs.unsolved)
|
||||
};
|
||||
if solve_cond && (filter_cond || subargs.filter.is_none()) {
|
||||
let line = if subargs.paths {
|
||||
format!("{}\n", fname)
|
||||
} else if subargs.names {
|
||||
format!("{}\n", e.name)
|
||||
} else {
|
||||
format!("{:<17}\t{:<46}\t{:<7}\n", e.name, fname, status)
|
||||
};
|
||||
// Somehow using println! leads to the binary panicking
|
||||
// when its output is piped.
|
||||
// So, we're handling a Broken Pipe error and exiting with 0 anyway
|
||||
let stdout = std::io::stdout();
|
||||
{
|
||||
let mut handle = stdout.lock();
|
||||
handle.write_all(line.as_bytes()).unwrap_or_else(|e| {
|
||||
match e.kind() {
|
||||
std::io::ErrorKind::BrokenPipe => std::process::exit(0),
|
||||
_ => std::process::exit(1),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
let percentage_progress = exercises_done as f32 / exercises.len() as f32 * 100.0;
|
||||
println!(
|
||||
"Progress: You completed {} / {} exercises ({:.2} %).",
|
||||
exercises_done,
|
||||
exercises.len(),
|
||||
percentage_progress
|
||||
);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
println!("{}", exercise.hint);
|
||||
}
|
||||
Subcommands::Run(subargs) => {
|
||||
let exercise = find_exercise(&subargs.name, &exercises);
|
||||
|
||||
if matches.subcommand_matches("verify").is_some() {
|
||||
verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
run(&exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
if matches.subcommand_matches("watch").is_some() {
|
||||
if watch(&exercises).is_ok() {
|
||||
Subcommands::Hint(subargs) => {
|
||||
let exercise = find_exercise(&subargs.name, &exercises);
|
||||
|
||||
println!("{}", exercise.hint);
|
||||
}
|
||||
|
||||
Subcommands::Verify(_subargs) => {
|
||||
verify(&exercises, verbose).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
Subcommands::Watch(_subargs) => {
|
||||
if let Err(e) = watch(&exercises, verbose) {
|
||||
println!(
|
||||
"Error: Could not watch your progress. Error message was {:?}.",
|
||||
e
|
||||
);
|
||||
println!("Most likely you've run out of disk space or your 'inotify limit' has been reached.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
println!(
|
||||
"{emoji} All exercises completed! {emoji}",
|
||||
emoji = Emoji("🎉", "★")
|
||||
);
|
||||
println!("");
|
||||
println!();
|
||||
println!("+----------------------------------------------------+");
|
||||
println!("| You made it to the Fe-nish line! |");
|
||||
println!("+-------------------------- ------------------------+");
|
||||
println!(" \\/ ");
|
||||
println!(" ▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒ ");
|
||||
println!(" ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ ");
|
||||
println!(" ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒ ");
|
||||
println!(" ░░▒▒▒▒░░▒▒ ▒▒ ▒▒ ▒▒ ▒▒░░▒▒▒▒ ");
|
||||
println!(" ▓▓▓▓▓▓▓▓ ▓▓ ▓▓██ ▓▓ ▓▓██ ▓▓ ▓▓▓▓▓▓▓▓ ");
|
||||
println!(" ▒▒▒▒ ▒▒ ████ ▒▒ ████ ▒▒░░ ▒▒▒▒ ");
|
||||
println!(" ▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒ ");
|
||||
println!(" ▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓▓▒▒▓▓▒▒▒▒▒▒▒▒ ");
|
||||
println!(" ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ");
|
||||
println!(" ▒▒▒▒▒▒▒▒▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒▒▒ ");
|
||||
println!(" ▒▒ ▒▒▒▒▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒ ▒▒ ");
|
||||
println!(" ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ");
|
||||
println!(" ▒▒ ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ▒▒ ");
|
||||
println!(" ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ");
|
||||
println!(" ▒▒ ▒▒ ▒▒ ▒▒ ");
|
||||
println!();
|
||||
println!("We hope you enjoyed learning about the various aspects of Rust!");
|
||||
println!(
|
||||
"If you noticed any issues, please don't hesitate to report them to our repo."
|
||||
);
|
||||
println!("You can also contribute your own exercises to help the greater community!");
|
||||
println!("");
|
||||
println!();
|
||||
println!("Before reporting an issue or contributing, please read our guidelines:");
|
||||
println!("https://github.com/rust-lang/rustlings/blob/master/CONTRIBUTING.md");
|
||||
println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md");
|
||||
}
|
||||
}
|
||||
|
||||
if matches.subcommand_name().is_none() {
|
||||
let text = fs::read_to_string("default_out.txt").unwrap();
|
||||
println!("{}", text);
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>) {
|
||||
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
|
||||
println!("Type 'hint' to get help");
|
||||
println!("Type 'hint' or open the corresponding README.md file to get help or type 'clear' to clear the screen.");
|
||||
thread::spawn(move || loop {
|
||||
let mut input = String::new();
|
||||
match io::stdin().read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
if input.trim().eq("hint") {
|
||||
let input = input.trim();
|
||||
if input.eq("hint") {
|
||||
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
|
||||
println!("{}", hint);
|
||||
}
|
||||
} else if input.eq("clear") {
|
||||
println!("\x1B[2J\x1B[1;1H");
|
||||
} else {
|
||||
println!("unknown command: {}", input);
|
||||
}
|
||||
@@ -149,7 +285,28 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>) {
|
||||
});
|
||||
}
|
||||
|
||||
fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
|
||||
if name.eq("next") {
|
||||
exercises
|
||||
.iter()
|
||||
.find(|e| !e.looks_done())
|
||||
.unwrap_or_else(|| {
|
||||
println!("🎉 Congratulations! You have done all the exercises!");
|
||||
println!("🔚 There are no more exercises to do next!");
|
||||
std::process::exit(1)
|
||||
})
|
||||
} else {
|
||||
exercises
|
||||
.iter()
|
||||
.find(|e| e.name == name)
|
||||
.unwrap_or_else(|| {
|
||||
println!("No exercise found for '{}'!", name);
|
||||
std::process::exit(1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
|
||||
/* Clears the terminal with an ANSI escape code.
|
||||
Works in UNIX and newer Windows terminals. */
|
||||
fn clear_screen() {
|
||||
@@ -164,7 +321,7 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||
clear_screen();
|
||||
|
||||
let to_owned_hint = |t: &Exercise| t.hint.to_owned();
|
||||
let failed_exercise_hint = match verify(exercises.iter()) {
|
||||
let failed_exercise_hint = match verify(exercises.iter(), verbose) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))),
|
||||
};
|
||||
@@ -177,9 +334,15 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||
let filepath = b.as_path().canonicalize().unwrap();
|
||||
let pending_exercises = exercises
|
||||
.iter()
|
||||
.skip_while(|e| !filepath.ends_with(&e.path));
|
||||
.skip_while(|e| !filepath.ends_with(&e.path))
|
||||
// .filter(|e| filepath.ends_with(&e.path))
|
||||
.chain(
|
||||
exercises
|
||||
.iter()
|
||||
.filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)),
|
||||
);
|
||||
clear_screen();
|
||||
match verify(pending_exercises) {
|
||||
match verify(pending_exercises, verbose) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(exercise) => {
|
||||
let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap();
|
||||
|
||||
11
src/run.rs
11
src/run.rs
@@ -2,15 +2,22 @@ use crate::exercise::{Exercise, Mode};
|
||||
use crate::verify::test;
|
||||
use indicatif::ProgressBar;
|
||||
|
||||
pub fn run(exercise: &Exercise) -> Result<(), ()> {
|
||||
// Invoke the rust compiler on the path of the given exercise,
|
||||
// and run the ensuing binary.
|
||||
// The verbose argument helps determine whether or not to show
|
||||
// the output from the test harnesses (if the mode of the exercise is test)
|
||||
pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
|
||||
match exercise.mode {
|
||||
Mode::Test => test(exercise)?,
|
||||
Mode::Test => test(exercise, verbose)?,
|
||||
Mode::Compile => compile_and_run(exercise)?,
|
||||
Mode::Clippy => compile_and_run(exercise)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Invoke the rust compiler on the path of the given exercise
|
||||
// and run the ensuing binary.
|
||||
// This is strictly for non-test binaries, so output is displayed
|
||||
fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
|
||||
30
src/ui.rs
30
src/ui.rs
@@ -1,23 +1,33 @@
|
||||
macro_rules! warn {
|
||||
($fmt:literal, $ex:expr) => {{
|
||||
use console::{style, Emoji};
|
||||
use std::env;
|
||||
let formatstr = format!($fmt, $ex);
|
||||
println!(
|
||||
"{} {}",
|
||||
style(Emoji("⚠️ ", "!")).red(),
|
||||
style(formatstr).red()
|
||||
);
|
||||
if env::var("NO_EMOJI").is_ok() {
|
||||
println!("{} {}", style("!").red(), style(formatstr).red());
|
||||
} else {
|
||||
println!(
|
||||
"{} {}",
|
||||
style(Emoji("⚠️ ", "!")).red(),
|
||||
style(formatstr).red()
|
||||
);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! success {
|
||||
($fmt:literal, $ex:expr) => {{
|
||||
use console::{style, Emoji};
|
||||
use std::env;
|
||||
let formatstr = format!($fmt, $ex);
|
||||
println!(
|
||||
"{} {}",
|
||||
style(Emoji("✅", "✓")).green(),
|
||||
style(formatstr).green()
|
||||
);
|
||||
if env::var("NO_EMOJI").is_ok() {
|
||||
println!("{} {}", style("✓").green(), style(formatstr).green());
|
||||
} else {
|
||||
println!(
|
||||
"{} {}",
|
||||
style(Emoji("✅", "✓")).green(),
|
||||
style(formatstr).green()
|
||||
);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
146
src/verify.rs
146
src/verify.rs
@@ -1,12 +1,21 @@
|
||||
use crate::exercise::{Exercise, Mode, State};
|
||||
use crate::exercise::{CompiledExercise, Exercise, Mode, State};
|
||||
use console::style;
|
||||
use indicatif::ProgressBar;
|
||||
use std::env;
|
||||
|
||||
pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<(), &'a Exercise> {
|
||||
// Verify that the provided container of Exercise objects
|
||||
// can be compiled and run without any failures.
|
||||
// Any such failures will be reported to the end user.
|
||||
// If the Exercise being verified is a test, the verbose boolean
|
||||
// determines whether or not the test harness outputs are displayed.
|
||||
pub fn verify<'a>(
|
||||
start_at: impl IntoIterator<Item = &'a Exercise>,
|
||||
verbose: bool,
|
||||
) -> Result<(), &'a Exercise> {
|
||||
for exercise in start_at {
|
||||
let compile_result = match exercise.mode {
|
||||
Mode::Test => compile_and_test(&exercise, RunMode::Interactive),
|
||||
Mode::Compile => compile_only(&exercise),
|
||||
Mode::Test => compile_and_test(&exercise, RunMode::Interactive, verbose),
|
||||
Mode::Compile => compile_and_run_interactively(&exercise),
|
||||
Mode::Clippy => compile_only(&exercise),
|
||||
};
|
||||
if !compile_result.unwrap_or(false) {
|
||||
@@ -21,61 +30,71 @@ enum RunMode {
|
||||
NonInteractive,
|
||||
}
|
||||
|
||||
pub fn test(exercise: &Exercise) -> Result<(), ()> {
|
||||
compile_and_test(exercise, RunMode::NonInteractive)?;
|
||||
// Compile and run the resulting test harness of the given Exercise
|
||||
pub fn test(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
|
||||
compile_and_test(exercise, RunMode::NonInteractive, verbose)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Invoke the rust compiler without running the resulting binary
|
||||
fn compile_only(exercise: &Exercise) -> Result<bool, ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let compilation_result = exercise.compile();
|
||||
|
||||
let _ = compile(&exercise, &progress_bar)?;
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
match compilation_result {
|
||||
Ok(_) => {
|
||||
success!("Successfully compiled {}!", exercise);
|
||||
Ok(prompt_for_completion(&exercise))
|
||||
}
|
||||
Err(output) => {
|
||||
warn!(
|
||||
"Compilation of {} failed! Compiler error message:\n",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stderr);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
success!("Successfully compiled {}!", exercise);
|
||||
Ok(prompt_for_completion(&exercise, None))
|
||||
}
|
||||
|
||||
fn compile_and_test(exercise: &Exercise, run_mode: RunMode) -> Result<bool, ()> {
|
||||
// Compile the given Exercise and run the resulting binary in an interactive mode
|
||||
fn compile_and_run_interactively(exercise: &Exercise) -> Result<bool, ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compilation_result = exercise.compile();
|
||||
let compilation = compile(&exercise, &progress_bar)?;
|
||||
|
||||
let compilation = match compilation_result {
|
||||
Ok(compilation) => compilation,
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
let result = compilation.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
let output = match result {
|
||||
Ok(output) => output,
|
||||
Err(output) => {
|
||||
progress_bar.finish_and_clear();
|
||||
warn!(
|
||||
"Compiling of {} failed! Please try again. Here's the output:",
|
||||
exercise
|
||||
);
|
||||
warn!("Ran {} with errors", exercise);
|
||||
println!("{}", output.stdout);
|
||||
println!("{}", output.stderr);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
success!("Successfully ran {}!", exercise);
|
||||
|
||||
Ok(prompt_for_completion(&exercise, Some(output.stdout)))
|
||||
}
|
||||
|
||||
// Compile the given Exercise as a test harness and display
|
||||
// the output if verbose is set to true
|
||||
fn compile_and_test(exercise: &Exercise, run_mode: RunMode, verbose: bool) -> Result<bool, ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compilation = compile(exercise, &progress_bar)?;
|
||||
let result = compilation.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
Ok(output) => {
|
||||
if verbose {
|
||||
println!("{}", output.stdout);
|
||||
}
|
||||
success!("Successfully tested {}", &exercise);
|
||||
if let RunMode::Interactive = run_mode {
|
||||
Ok(prompt_for_completion(&exercise))
|
||||
Ok(prompt_for_completion(&exercise, None))
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
@@ -91,32 +110,75 @@ fn compile_and_test(exercise: &Exercise, run_mode: RunMode) -> Result<bool, ()>
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_for_completion(exercise: &Exercise) -> bool {
|
||||
// Compile the given Exercise and return an object with information
|
||||
// about the state of the compilation
|
||||
fn compile<'a, 'b>(
|
||||
exercise: &'a Exercise,
|
||||
progress_bar: &'b ProgressBar,
|
||||
) -> Result<CompiledExercise<'a>, ()> {
|
||||
let compilation_result = exercise.compile();
|
||||
|
||||
match compilation_result {
|
||||
Ok(compilation) => Ok(compilation),
|
||||
Err(output) => {
|
||||
progress_bar.finish_and_clear();
|
||||
warn!(
|
||||
"Compiling of {} failed! Please try again. Here's the output:",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stderr);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prompt_for_completion(exercise: &Exercise, prompt_output: Option<String>) -> bool {
|
||||
let context = match exercise.state() {
|
||||
State::Done => return true,
|
||||
State::Pending(context) => context,
|
||||
};
|
||||
|
||||
let no_emoji = env::var("NO_EMOJI").is_ok();
|
||||
|
||||
let clippy_success_msg = if no_emoji {
|
||||
"The code is compiling, and Clippy is happy!"
|
||||
} else {
|
||||
"The code is compiling, and 📎 Clippy 📎 is happy!"
|
||||
};
|
||||
|
||||
let success_msg = match exercise.mode {
|
||||
Mode::Compile => "The code is compiling!",
|
||||
Mode::Test => "The code is compiling, and the tests pass!",
|
||||
Mode::Clippy => "The code is compiling, and 📎 Clippy 📎 is happy!",
|
||||
Mode::Clippy => clippy_success_msg,
|
||||
};
|
||||
|
||||
println!("");
|
||||
println!("🎉 🎉 {} 🎉 🎉", success_msg);
|
||||
println!("");
|
||||
println!();
|
||||
if no_emoji {
|
||||
println!("~*~ {} ~*~", success_msg)
|
||||
} else {
|
||||
println!("🎉 🎉 {} 🎉 🎉", success_msg)
|
||||
}
|
||||
println!();
|
||||
|
||||
if let Some(output) = prompt_output {
|
||||
println!("Output:");
|
||||
println!("{}", separator());
|
||||
println!("{}", output);
|
||||
println!("{}", separator());
|
||||
println!();
|
||||
}
|
||||
|
||||
println!("You can keep working on this exercise,");
|
||||
println!(
|
||||
"or jump into the next one by removing the {} comment:",
|
||||
style("`I AM NOT DONE`").bold()
|
||||
);
|
||||
println!("");
|
||||
println!();
|
||||
for context_line in context {
|
||||
let formatted_line = if context_line.important {
|
||||
format!("{}", style(context_line.line).bold())
|
||||
} else {
|
||||
format!("{}", context_line.line)
|
||||
context_line.line.to_string()
|
||||
};
|
||||
|
||||
println!(
|
||||
@@ -129,3 +191,7 @@ fn prompt_for_completion(exercise: &Exercise) -> bool {
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn separator() -> console::StyledObject<&'static str> {
|
||||
style("====================").bold()
|
||||
}
|
||||
|
||||
@@ -9,3 +9,10 @@ name = "pending_test_exercise"
|
||||
path = "pending_test_exercise.rs"
|
||||
mode = "test"
|
||||
hint = """"""
|
||||
|
||||
[[exercises]]
|
||||
name = "finished_exercise"
|
||||
path = "finished_exercise.rs"
|
||||
mode = "compile"
|
||||
hint = """"""
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#[test]
|
||||
fn passing() {
|
||||
println!("THIS TEST TOO SHALL PASS");
|
||||
assert!(true);
|
||||
}
|
||||
|
||||
@@ -24,17 +24,17 @@ fn fails_when_in_wrong_dir() {
|
||||
fn verify_all_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("v")
|
||||
.arg("verify")
|
||||
.current_dir("tests/fixture/success")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_all_failure() {
|
||||
fn verify_fails_if_some_fails() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("v")
|
||||
.arg("verify")
|
||||
.current_dir("tests/fixture/failure")
|
||||
.assert()
|
||||
.code(1);
|
||||
@@ -44,7 +44,7 @@ fn verify_all_failure() {
|
||||
fn run_single_compile_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compSuccess"])
|
||||
.args(&["run", "compSuccess"])
|
||||
.current_dir("tests/fixture/success/")
|
||||
.assert()
|
||||
.success();
|
||||
@@ -54,7 +54,7 @@ fn run_single_compile_success() {
|
||||
fn run_single_compile_failure() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compFailure"])
|
||||
.args(&["run", "compFailure"])
|
||||
.current_dir("tests/fixture/failure/")
|
||||
.assert()
|
||||
.code(1);
|
||||
@@ -64,7 +64,7 @@ fn run_single_compile_failure() {
|
||||
fn run_single_test_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "testSuccess"])
|
||||
.args(&["run", "testSuccess"])
|
||||
.current_dir("tests/fixture/success/")
|
||||
.assert()
|
||||
.success();
|
||||
@@ -74,7 +74,7 @@ fn run_single_test_success() {
|
||||
fn run_single_test_failure() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "testFailure"])
|
||||
.args(&["run", "testFailure"])
|
||||
.current_dir("tests/fixture/failure/")
|
||||
.assert()
|
||||
.code(1);
|
||||
@@ -84,7 +84,7 @@ fn run_single_test_failure() {
|
||||
fn run_single_test_not_passed() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "testNotPassed.rs"])
|
||||
.args(&["run", "testNotPassed.rs"])
|
||||
.current_dir("tests/fixture/failure/")
|
||||
.assert()
|
||||
.code(1);
|
||||
@@ -94,7 +94,7 @@ fn run_single_test_not_passed() {
|
||||
fn run_single_test_no_filename() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("r")
|
||||
.arg("run")
|
||||
.current_dir("tests/fixture/")
|
||||
.assert()
|
||||
.code(1);
|
||||
@@ -104,7 +104,7 @@ fn run_single_test_no_filename() {
|
||||
fn run_single_test_no_exercise() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compNoExercise.rs"])
|
||||
.args(&["run", "compNoExercise.rs"])
|
||||
.current_dir("tests/fixture/failure")
|
||||
.assert()
|
||||
.code(1);
|
||||
@@ -114,7 +114,7 @@ fn run_single_test_no_exercise() {
|
||||
fn get_hint_for_single_test() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["h", "testFailure"])
|
||||
.args(&["hint", "testFailure"])
|
||||
.current_dir("tests/fixture/failure")
|
||||
.assert()
|
||||
.code(0)
|
||||
@@ -131,10 +131,15 @@ fn all_exercises_require_confirmation() {
|
||||
file.read_to_string(&mut s).unwrap();
|
||||
s
|
||||
};
|
||||
source.matches("// I AM NOT DONE").next().expect(&format!(
|
||||
"There should be an `I AM NOT DONE` annotation in {:?}",
|
||||
path
|
||||
));
|
||||
source
|
||||
.matches("// I AM NOT DONE")
|
||||
.next()
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"There should be an `I AM NOT DONE` annotation in {:?}",
|
||||
path
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +147,7 @@ fn all_exercises_require_confirmation() {
|
||||
fn run_compile_exercise_does_not_prompt() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "pending_exercise"])
|
||||
.args(&["run", "pending_exercise"])
|
||||
.current_dir("tests/fixture/state")
|
||||
.assert()
|
||||
.code(0)
|
||||
@@ -153,9 +158,85 @@ fn run_compile_exercise_does_not_prompt() {
|
||||
fn run_test_exercise_does_not_prompt() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "pending_test_exercise"])
|
||||
.args(&["run", "pending_test_exercise"])
|
||||
.current_dir("tests/fixture/state")
|
||||
.assert()
|
||||
.code(0)
|
||||
.stdout(predicates::str::contains("I AM NOT DONE").not());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_success_with_output() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["--nocapture", "run", "testSuccess"])
|
||||
.current_dir("tests/fixture/success/")
|
||||
.assert()
|
||||
.code(0)
|
||||
.stdout(predicates::str::contains("THIS TEST TOO SHALL PAS"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_success_without_output() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["run", "testSuccess"])
|
||||
.current_dir("tests/fixture/success/")
|
||||
.assert()
|
||||
.code(0)
|
||||
.stdout(predicates::str::contains("THIS TEST TOO SHALL PAS").not());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_rustlings_list() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["list"])
|
||||
.current_dir("tests/fixture/success")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_rustlings_list_no_pending() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["list"])
|
||||
.current_dir("tests/fixture/success")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicates::str::contains("Pending").not());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_rustlings_list_both_done_and_pending() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["list"])
|
||||
.current_dir("tests/fixture/state")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicates::str::contains("Done").and(predicates::str::contains("Pending")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_rustlings_list_without_pending() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["list", "--solved"])
|
||||
.current_dir("tests/fixture/state")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicates::str::contains("Pending").not());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_rustlings_list_without_done() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["list", "--unsolved"])
|
||||
.current_dir("tests/fixture/state")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicates::str::contains("Done").not());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user