mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
231 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
8b9479071c | ||
|
|
3d9b03c52b | ||
|
|
a03d9655a8 | ||
|
|
1e2fd9c92f | ||
|
|
7e8530b21f | ||
|
|
98358597a9 | ||
|
|
8064facbb8 | ||
|
|
f981dcfde4 | ||
|
|
6eb62fa2ce | ||
|
|
78295ce92f | ||
|
|
358fb473cd | ||
|
|
a45486f2d0 | ||
|
|
8b971ffab6 | ||
|
|
dc84aacc65 | ||
|
|
bbf8922ef7 | ||
|
|
b559cdd73f | ||
|
|
ec51cdb229 | ||
|
|
a3f70124dc | ||
|
|
bec8e3a644 | ||
|
|
c228a06e49 | ||
|
|
17d0951e66 | ||
|
|
43dc31193a | ||
|
|
83bbd9e82e | ||
|
|
39fa7ae8b7 | ||
|
|
3161a8fd9d | ||
|
|
ade52ffb73 | ||
|
|
89c73647f1 | ||
|
|
0c73609e6f | ||
|
|
19a93428b3 | ||
|
|
32a9cf7b8d | ||
|
|
c86b217e1d | ||
|
|
fd57f8f2c1 | ||
|
|
0d1f1a19b7 | ||
|
|
d25ee55a32 | ||
|
|
3afa96bed4 | ||
|
|
dfdf8093eb | ||
|
|
3906efcd52 | ||
|
|
2021a1ac7d | ||
|
|
426a7bb87f | ||
|
|
fc26b5e151 | ||
|
|
0c85dc1193 | ||
|
|
fe10e06c37 | ||
|
|
419f7797f2 | ||
|
|
54571a5fca | ||
|
|
4b79691d5e | ||
|
|
615ce32798 | ||
|
|
31c25ebb50 | ||
|
|
f4acb888a6 | ||
|
|
8143d57b4e | ||
|
|
a40ad092e9 | ||
|
|
b565c4d3e7 | ||
|
|
e9a835c1c0 | ||
|
|
cf38f03459 | ||
|
|
4c5189df2b | ||
|
|
a09f684f05 | ||
|
|
8cc5af121c | ||
|
|
c42c3b2101 | ||
|
|
fda5a47069 | ||
|
|
57a837bde6 | ||
|
|
ded2c034ba | ||
|
|
eac07df96c | ||
|
|
8c1376df07 | ||
|
|
45d68d9b39 | ||
|
|
c371b853af | ||
|
|
bc32a63c69 | ||
|
|
4b26546589 | ||
|
|
bc56788fe6 | ||
|
|
b4d41c1b7a | ||
|
|
36a033b87a | ||
|
|
9544ba1029 | ||
|
|
1a7bb5a400 | ||
|
|
48c35bcfbc | ||
|
|
ec2d4bd3ee | ||
|
|
ce9fa6ebbf | ||
|
|
9a9007abae | ||
|
|
88ec6f6b16 | ||
|
|
795b6e3480 | ||
|
|
9bdb0a12e4 | ||
|
|
2cdd61294f | ||
|
|
627cdc07d0 |
465
.all-contributorsrc
Normal file
465
.all-contributorsrc
Normal file
@@ -0,0 +1,465 @@
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 8,
|
||||
"projectName": "rustlings",
|
||||
"projectOwner": "fmoko",
|
||||
"repoType": "github",
|
||||
"repoHost": "https://github.com",
|
||||
"skipCi": true
|
||||
}
|
||||
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@@ -0,0 +1,7 @@
|
||||
root = true
|
||||
|
||||
[*.rs]
|
||||
end_of_line = lf
|
||||
insert_final_newfile = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,3 +2,7 @@
|
||||
target/
|
||||
**/*.rs.bk
|
||||
.DS_Store
|
||||
*.pdb
|
||||
exercises/clippy/Cargo.toml
|
||||
exercises/clippy/Cargo.lock
|
||||
.idea
|
||||
|
||||
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
|
||||
145
CHANGELOG.md
145
CHANGELOG.md
@@ -1,3 +1,148 @@
|
||||
<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)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Re-add cloning the repo to install scripts ([3d9b03c5](https://github.com/rust-lang/rustlings/commit/3d9b03c52b8dc51b140757f6fd25ad87b5782ef5))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add clippy lints (#269) ([1e2fd9c9](https://github.com/rust-lang/rustlings/commit/1e2fd9c92f8cd6e389525ca1a999fca4c90b5921))
|
||||
|
||||
<a name="2.2.0"></a>
|
||||
## 2.2.0 (2020-02-25)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* 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))
|
||||
* 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)
|
||||
* Correct test command in tests1.rs comment (#263) ([39fa7ae](https://github.com/rust-lang/rustlings/commit/39fa7ae8b70ad468da49b06f11b2383135a63bcf))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add variables5.rs exercise (#264) ([0c73609e](https://github.com/rust-lang/rustlings/commit/0c73609e6f2311295e95d6f96f8c747cfc4cba03))
|
||||
* Show a completion message when watching (#253) ([d25ee55a](https://github.com/rust-lang/rustlings/commit/d25ee55a3205882d35782e370af855051b39c58c))
|
||||
* Add type conversion and parsing exercises (#249) ([0c85dc11](https://github.com/rust-lang/rustlings/commit/0c85dc1193978b5165491b99cc4922caf8d14a65))
|
||||
* Created consistent money unit (#258) ([fd57f8f](https://github.com/rust-lang/rustlings/commit/fd57f8f2c1da2af8ddbebbccec214e6f40f4dbab))
|
||||
* Enable test for exercise test4 (#276) ([8b971ff](https://github.com/rust-lang/rustlings/commit/8b971ffab6079a706ac925f5917f987932b55c07))
|
||||
* Added traits exercises (#274 but specifically #216, which originally added
|
||||
this :heart:) ([b559cdd](https://github.com/rust-lang/rustlings/commit/b559cdd73f32c0d0cfc1feda39f82b3e3583df17))
|
||||
|
||||
|
||||
<a name="2.1.0"></a>
|
||||
## 2.1.0 (2019-11-27)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* add line numbers in several exercises and hints ([b565c4d3](https://github.com/rust-lang/rustlings/commit/b565c4d3e74e8e110bef201a082fa1302722a7c3))
|
||||
* **arc1:** Fix some words in the comment ([c42c3b21](https://github.com/rust-lang/rustlings/commit/c42c3b2101df9164c8cd7bb344def921e5ba3e61))
|
||||
* **enums:** Add link to chapter on pattern syntax (#242) ([615ce327](https://github.com/rust-lang/rustlings/commit/615ce3279800c56d89f19d218ccb7ef576624feb))
|
||||
* **primitive_types4:**
|
||||
* update outdated hint ([4c5189df](https://github.com/rust-lang/rustlings/commit/4c5189df2bdd9a231f6b2611919ba5aa14da0d3f))
|
||||
* update outdated comment ([ded2c034](https://github.com/rust-lang/rustlings/commit/ded2c034ba93fa1e3c2c2ea16b83abc1a57265e8))
|
||||
* **strings2:** update line number in hint ([a09f684f](https://github.com/rust-lang/rustlings/commit/a09f684f05c58d239a6fc59ec5f81c2533e8b820))
|
||||
* **variables1:** Correct wrong word in comment ([fda5a470](https://github.com/rust-lang/rustlings/commit/fda5a47069e0954f16a04e8e50945e03becb71a5))
|
||||
|
||||
#### Features
|
||||
|
||||
* **watch:** show hint while watching ([8143d57b](https://github.com/rust-lang/rustlings/commit/8143d57b4e88c51341dd4a18a14c536042cc009c))
|
||||
|
||||
<a name="2.0.0"></a>
|
||||
## 2.0.0 (2019-11-12)
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **default:** Clarify the installation procedure ([c371b853](https://github.com/rust-lang/rustlings/commit/c371b853afa08947ddeebec0edd074b171eeaae0))
|
||||
* **info:** Fix trailing newlines for hints ([795b6e34](https://github.com/rust-lang/rustlings/commit/795b6e348094a898e9227a14f6232f7bb94c8d31))
|
||||
* **run:** make `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* Refactor hint system ([9bdb0a12](https://github.com/rust-lang/rustlings/commit/9bdb0a12e45a8e9f9f6a4bd4a9c172c5376c7f60))
|
||||
* improve `watch` execution mode ([2cdd6129](https://github.com/rust-lang/rustlings/commit/2cdd61294f0d9a53775ee24ad76435bec8a21e60))
|
||||
* Index exercises by name ([627cdc07](https://github.com/rust-lang/rustlings/commit/627cdc07d07dfe6a740e885e0ddf6900e7ec336b))
|
||||
* **run:** makes `run` never prompt ([4b265465](https://github.com/rust-lang/rustlings/commit/4b26546589f7d2b50455429482cf1f386ceae8b3))
|
||||
|
||||
#### Features
|
||||
|
||||
* **cli:** check for rustc before doing anything ([36a033b8](https://github.com/rust-lang/rustlings/commit/36a033b87a6549c1e5639c908bf7381c84f4f425))
|
||||
* **hint:** Add test for hint ([ce9fa6eb](https://github.com/rust-lang/rustlings/commit/ce9fa6ebbfdc3e7585d488d9409797285708316f))
|
||||
|
||||
<a name="1.5.1"></a>
|
||||
### 1.5.1 (2019-11-11)
|
||||
|
||||
|
||||
@@ -35,8 +35,11 @@ You want to make sure where in the file you add your exercise. If you're not sur
|
||||
```diff
|
||||
...
|
||||
+ [[exercises]]
|
||||
+ name = "yourTopicN"
|
||||
+ path = "exercises/yourTopic/yourTopicN.rs"
|
||||
+ mode = "compile"
|
||||
+ hint = """
|
||||
+ Some kind of useful hint for your exercise."""
|
||||
...
|
||||
```
|
||||
|
||||
@@ -125,4 +128,4 @@ BREAKING CHANGE: This has to be done because lorem ipsum dolor
|
||||
Once you open a Pull Request, it may be reviewed or labeled (or both) until
|
||||
the maintainers accept your change. Then, [bors](https://github.com/bors) will
|
||||
run the test suite with your changes and if it's successful, automatically
|
||||
merge it in!
|
||||
merge it in!
|
||||
|
||||
189
Cargo.lock
generated
189
Cargo.lock
generated
@@ -1,13 +1,5 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.3"
|
||||
@@ -21,7 +13,7 @@ name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -42,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -74,17 +66,6 @@ dependencies = [
|
||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clicolors-control"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clicolors-control"
|
||||
version = "1.0.0"
|
||||
@@ -93,7 +74,7 @@ dependencies = [
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -106,23 +87,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clicolors-control 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.7.5"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -134,7 +99,22 @@ dependencies = [
|
||||
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -168,6 +148,14 @@ dependencies = [
|
||||
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.4.0"
|
||||
@@ -204,20 +192,26 @@ name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.9.0"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"console 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.6.1"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -256,11 +250,6 @@ dependencies = [
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.3.0"
|
||||
@@ -343,25 +332,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "normalize-line-endings"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.12"
|
||||
version = "4.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "number_prefix"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -391,7 +400,7 @@ dependencies = [
|
||||
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -400,7 +409,10 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"normalize-line-endings 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -448,7 +460,7 @@ dependencies = [
|
||||
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -496,7 +508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -509,7 +521,7 @@ dependencies = [
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -550,18 +562,6 @@ dependencies = [
|
||||
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.1.6"
|
||||
@@ -574,14 +574,6 @@ dependencies = [
|
||||
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.6"
|
||||
@@ -600,13 +592,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustlings"
|
||||
version = "1.5.1"
|
||||
version = "3.0.0"
|
||||
dependencies = [
|
||||
"assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"console 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indicatif 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -774,7 +769,7 @@ version = "2.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -785,7 +780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.7"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -807,7 +802,7 @@ name = "winapi-util"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -825,7 +820,6 @@ dependencies = [
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
|
||||
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e"
|
||||
@@ -834,27 +828,27 @@ dependencies = [
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum clicolors-control 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f84dec9bc083ce2503908cd305af98bd363da6f54bf8d4bf0ac14ee749ad5d1"
|
||||
"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum console 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd48adf136733979b49e15bc3b4c43cc0d3c85ece7bd08e6daa414c6fcb13e6"
|
||||
"checksum console 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2bf3720d3f3fc30b721ef1ae54e13af3264af4af39dc476a8de56a6ee1e2184b"
|
||||
"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628"
|
||||
"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242"
|
||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd"
|
||||
"checksum escargot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ceb9adbf9874d5d028b5e4c5739d22b71988252b25c9c98fe7cf9738bee84597"
|
||||
"checksum filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2f8c63033fcba1f51ef744505b3cad42510432b904c062afa67ad7ece008429d"
|
||||
"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600"
|
||||
"checksum fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
|
||||
"checksum fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
|
||||
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum indicatif 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a29b2fa6f00010c268bface64c18bb0310aaa70d46a195d5382d288c477fb016"
|
||||
"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
|
||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
"checksum indicatif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "40ecd1e2ee08e6c255ce890f5a99d17000850e664e7acf119fb03b25b0575bfe"
|
||||
"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8"
|
||||
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
|
||||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
|
||||
@@ -865,7 +859,10 @@ dependencies = [
|
||||
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3572d71f13ea8ed41867accd971fd564aa75934cf7a1fae03ddb8c74a8a49943"
|
||||
"checksum normalize-line-endings 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2e0a1a39eab95caf4f5556da9289b9e68f0aafac901b2ce80daaf020d3b733a8"
|
||||
"checksum notify 4.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "80ae4a7688d1fab81c5bf19c64fc8db920be8d519ce6336ed4e7efe024724dbd"
|
||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||
"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
|
||||
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||
"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7"
|
||||
"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c"
|
||||
@@ -887,9 +884,7 @@ dependencies = [
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
|
||||
"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
|
||||
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
|
||||
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
|
||||
@@ -917,7 +912,7 @@ dependencies = [
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
||||
|
||||
13
Cargo.toml
13
Cargo.toml
@@ -1,15 +1,16 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "1.5.1"
|
||||
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
|
||||
version = "4.0.0"
|
||||
authors = ["Marisa <mokou@posteo.de>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.32.0"
|
||||
indicatif = "0.9.0"
|
||||
console = "0.6.2"
|
||||
notify = "4.0.0"
|
||||
indicatif = "0.10.3"
|
||||
console = "0.7.7"
|
||||
notify = "4.0.15"
|
||||
toml = "0.4.10"
|
||||
regex = "1.1.6"
|
||||
serde = {version = "1.0.10", features = ["derive"]}
|
||||
|
||||
[[bin]]
|
||||
@@ -18,3 +19,5 @@ path = "src/main.rs"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "0.11.0"
|
||||
predicates = "1.0.1"
|
||||
glob = "0.3.0"
|
||||
|
||||
105
README.md
105
README.md
@@ -1,6 +1,9 @@
|
||||

|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
# rustlings 🦀❤️
|
||||
# rustlings 🦀❤️ [](https://buildkite.com/mokou/rustlings)
|
||||
|
||||
Greetings and welcome to `rustlings`. This project contains small exercises to get you used to reading and writing Rust code. This includes reading and responding to compiler messages!
|
||||
|
||||
@@ -15,8 +18,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
|
||||
@@ -33,10 +34,16 @@ This will install Rustlings and give you access to the `rustlings` command. Run
|
||||
|
||||
## Windows
|
||||
|
||||
You can run:
|
||||
In PowerShell, set `ExecutionPolicy` to `RemoteSigned`:
|
||||
|
||||
```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
|
||||
Set-ExecutionPolicy RemoteSigned
|
||||
```
|
||||
|
||||
Then, you can run:
|
||||
|
||||
```ps
|
||||
Start-BitsTransfer -Source https://git.io/rustlings-win -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.
|
||||
@@ -48,7 +55,7 @@ Basically: Clone the repository, checkout to the latest tag, run `cargo install`
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings
|
||||
cd rustlings
|
||||
git checkout tags/1.5.1 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
git checkout tags/4.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
cargo install --force --path .
|
||||
```
|
||||
|
||||
@@ -80,14 +87,19 @@ This will do the same as watch, but it'll quit after running.
|
||||
In case you want to go by your own order, or want to only verify a single exercise, you can run:
|
||||
|
||||
```bash
|
||||
rustlings run exercises/path/to/exercise.rs
|
||||
rustlings run myExercise1
|
||||
```
|
||||
|
||||
In case you get stuck, there is usually a hint at the bottom of each exercise.
|
||||
In case you get stuck, you can run the following command to get a hint for your
|
||||
exercise:
|
||||
|
||||
``` bash
|
||||
rustlings hint myExercise1
|
||||
```
|
||||
|
||||
## 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`.
|
||||
|
||||
## Completion
|
||||
|
||||
@@ -111,7 +123,78 @@ 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" width="100px;" alt=""/><br /><sub><b>Carol (Nichols || Goulding)</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>QuietMisdreavus</b></sub></a><br /><a href="https://github.com/fmoko/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" 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" width="100px;" alt=""/><br /><sub><b>Hynek Schlawack</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Katharina Fey</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>lukabavdaz</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Erik Vesteraas</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>delet0r</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Shaun Bennett</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Andrew Bagshaw</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Kyle Isom</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Colin Pitrat</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Zac Anger</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Matthias Geier</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Chris Pearce</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Yvan Sraka</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Denys Smirnov</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>eddyp</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Brian Kung</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Russell</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Dan Wilhelm</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Jesse</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Fredrik Jambrén</b></sub></a><br /><a href="https://github.com/fmoko/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" 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" width="100px;" alt=""/><br /><sub><b>nkanderson</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Ajax M</b></sub></a><br /><a href="https://github.com/fmoko/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" 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" width="100px;" alt=""/><br /><sub><b>vyaslav</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>George</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Thomas Holloway</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Jubilee</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>WofWca</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Roberto Vidal</b></sub></a><br /><a href="https://github.com/fmoko/rustlings/commits?author=jrvidal" title="Code">💻</a> <a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Jens</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Rahat Ahmed</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Abdou Seck</b></sub></a><br /><a href="https://github.com/fmoko/rustlings/commits?author=AbdouSeck" title="Code">💻</a> <a href="#content-AbdouSeck" title="Content">🖋</a> <a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Katie</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Socrates</b></sub></a><br /><a href="https://github.com/fmoko/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" 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" width="100px;" alt=""/><br /><sub><b>Harrison Metzger</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Torben Jonas</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Paul Bissex</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Steven Mann</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Mario Reder</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>skim</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Sanjay K</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Rohan Jain</b></sub></a><br /><a href="https://github.com/fmoko/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" width="100px;" alt=""/><br /><sub><b>Said Aspen</b></sub></a><br /><a href="https://github.com/fmoko/rustlings/commits?author=saidaspen" title="Code">💻</a> <a href="#content-saidaspen" title="Content">🖋</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- 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!
|
||||
|
||||
5
buildkite.yml
Normal file
5
buildkite.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
steps:
|
||||
- label: "Test with stable"
|
||||
command: rustup run stable cargo test
|
||||
- label: "Test with beta"
|
||||
command: rustup run beta cargo test
|
||||
@@ -7,7 +7,8 @@ Let's make sure you're up to speed:
|
||||
- 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:
|
||||
- You have locally installed the `rustlings` command by running an
|
||||
installation script or manually executing:
|
||||
|
||||
cargo install --force --path .
|
||||
|
||||
@@ -15,4 +16,4 @@ 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!
|
||||
Make sure to have your editor open!
|
||||
|
||||
8
exercises/clippy/README.md
Normal file
8
exercises/clippy/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
### 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/).
|
||||
17
exercises/clippy/clippy1.rs
Normal file
17
exercises/clippy/clippy1.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
// clippy1.rs
|
||||
// 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
|
||||
|
||||
fn main() {
|
||||
let x = 1.2331f64;
|
||||
let y = 1.2332f64;
|
||||
if y != x {
|
||||
println!("Success!");
|
||||
}
|
||||
}
|
||||
13
exercises/clippy/clippy2.rs
Normal file
13
exercises/clippy/clippy2.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
// clippy2.rs
|
||||
// Make me compile! Execute `rustlings hint clippy2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut res = 42;
|
||||
let option = Some(12);
|
||||
for x in option {
|
||||
res += x;
|
||||
}
|
||||
println!("{}", res);
|
||||
}
|
||||
20
exercises/conversions/README.md
Normal file
20
exercises/conversions/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
### Type conversions
|
||||
|
||||
|
||||
Rust offers a multitude of ways to convert a value of a given type into another type.
|
||||
|
||||
The simplest form of type conversion is a type cast expression. It is denoted with the binary operator `as`. For instance, `println!("{}", 1 + 1.0);` would not compile, since `1` is an integer while `1.0` is a float. However, `println!("{}", 1 as f32 + 1.0)` should compile. The exercise [`using_as`](using_as.rs) tries to cover this.
|
||||
|
||||
Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module.
|
||||
The traits are the following:
|
||||
- `From` and `Into` covered in [`from_into`](from_into.rs)
|
||||
- `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs)
|
||||
- `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs)
|
||||
|
||||
Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) which helps with converting strings into target types via the `parse` method on strings. If properly implemented for a given type `Person`, then `let p: Person = "Mark,20".parse().unwrap()` should both compile and run without panicking.
|
||||
|
||||
These should be the main ways ***within the standard library*** to convert data into your desired types.
|
||||
|
||||
#### Book Sections
|
||||
|
||||
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).
|
||||
51
exercises/conversions/as_ref_mut.rs
Normal file
51
exercises/conversions/as_ref_mut.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
// AsRef and AsMut allow for cheap reference-to-reference conversions.
|
||||
// Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html
|
||||
// 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()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
arg.as_ref().chars().count()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Café au lait";
|
||||
println!("{}", char_counter(s));
|
||||
println!("{}", byte_counter(s));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn different_counts() {
|
||||
let s = "Café au lait";
|
||||
assert_ne!(char_counter(s), byte_counter(s));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_counts() {
|
||||
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));
|
||||
}
|
||||
}
|
||||
116
exercises/conversions/from_into.rs
Normal file
116
exercises/conversions/from_into.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
// The From trait is used for value-to-value conversions.
|
||||
// If From is implemented correctly for a type, the Into trait should work conversely.
|
||||
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html
|
||||
#[derive(Debug)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: usize,
|
||||
}
|
||||
|
||||
// We implement the Default trait to use it as a fallback
|
||||
// when the provided string is not convertible into a Person object
|
||||
impl Default for Person {
|
||||
fn default() -> Person {
|
||||
Person {
|
||||
name: String::from("John"),
|
||||
age: 30,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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`
|
||||
// with something like `"4".parse::<usize>()`. The outcome of this needs to
|
||||
// be handled appropriately.
|
||||
//
|
||||
// Steps:
|
||||
// 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. 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 object with the results
|
||||
impl From<&str> for Person {
|
||||
fn from(s: &str) -> Person {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Use the `from` function
|
||||
let p1 = Person::from("Mark,20");
|
||||
// Since From is implemented for Person, we should be able to use Into
|
||||
let p2: Person = "Gerald,70".into();
|
||||
println!("{:?}", p1);
|
||||
println!("{:?}", p2);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_default() {
|
||||
// Test that the default person is 30 year old John
|
||||
let dp = Person::default();
|
||||
assert_eq!(dp.name, "John");
|
||||
assert_eq!(dp.age, 30);
|
||||
}
|
||||
#[test]
|
||||
fn test_bad_convert() {
|
||||
// Test that John is returned when bad string is provided
|
||||
let p = Person::from("");
|
||||
assert_eq!(p.name, "John");
|
||||
assert_eq!(p.age, 30);
|
||||
}
|
||||
#[test]
|
||||
fn test_good_convert() {
|
||||
// Test that "Mark,20" works
|
||||
let p = Person::from("Mark,20");
|
||||
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);
|
||||
}
|
||||
}
|
||||
86
exercises/conversions/from_str.rs
Normal file
86
exercises/conversions/from_str.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
// This does practically the same thing that TryFrom<&str> does.
|
||||
// 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::str::FromStr;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Person {
|
||||
name: String,
|
||||
age: usize,
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
// 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. If the name is empty, then return an error
|
||||
// 5. Extract the other element from the split operation and parse it into a `usize` as the age
|
||||
// with something like `"4".parse::<usize>()`.
|
||||
// If while parsing the age, something goes wrong, then return an error
|
||||
// Otherwise, then return a Result of a Person object
|
||||
impl FromStr for Person {
|
||||
type Err = String;
|
||||
fn from_str(s: &str) -> Result<Person, Self::Err> {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let p = "Mark,20".parse::<Person>().unwrap();
|
||||
println!("{:?}", p);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn empty_input() {
|
||||
assert!("".parse::<Person>().is_err());
|
||||
}
|
||||
#[test]
|
||||
fn good_input() {
|
||||
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();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn invalid_age() {
|
||||
"John,twenty".parse::<Person>().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn missing_comma_and_age() {
|
||||
"John".parse::<Person>().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn missing_name() {
|
||||
",1".parse::<Person>().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn missing_name_and_age() {
|
||||
",".parse::<Person>().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn missing_name_and_invalid_age() {
|
||||
",one".parse::<Person>().unwrap();
|
||||
}
|
||||
|
||||
}
|
||||
130
exercises/conversions/try_from_into.rs
Normal file
130
exercises/conversions/try_from_into.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
// TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances.
|
||||
// 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};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Color {
|
||||
red: u8,
|
||||
green: u8,
|
||||
blue: u8,
|
||||
}
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Your task is to complete this implementation
|
||||
// and return an Ok result of inner type Color.
|
||||
// You need create implementation for a tuple of three integer,
|
||||
// an array of three integer and slice of integer.
|
||||
//
|
||||
// Note, that implementation for tuple and array will be checked at compile-time,
|
||||
// but slice implementation need check slice length!
|
||||
// Also note, that chunk of correct rgb color must be integer in range 0..=255.
|
||||
|
||||
// Tuple implementation
|
||||
impl TryFrom<(i16, i16, i16)> for Color {
|
||||
type Error = String;
|
||||
fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
|
||||
}
|
||||
}
|
||||
|
||||
// Array implementation
|
||||
impl TryFrom<[i16; 3]> for Color {
|
||||
type Error = String;
|
||||
fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
|
||||
}
|
||||
}
|
||||
|
||||
// Slice implementation
|
||||
impl TryFrom<&[i16]> for Color {
|
||||
type Error = String;
|
||||
fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Use the `from` function
|
||||
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]
|
||||
#[should_panic]
|
||||
fn test_tuple_out_of_range_positive() {
|
||||
let _ = Color::try_from((256, 1000, 10000)).unwrap();
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_tuple_out_of_range_negative() {
|
||||
let _ = Color::try_from((-1, -10, -256)).unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn test_tuple_correct() {
|
||||
let c: Color = (183, 65, 14).try_into().unwrap();
|
||||
assert_eq!(c.red, 183);
|
||||
assert_eq!(c.green, 65);
|
||||
assert_eq!(c.blue, 14);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_array_out_of_range_positive() {
|
||||
let _: Color = [1000, 10000, 256].try_into().unwrap();
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_array_out_of_range_negative() {
|
||||
let _: Color = [-10, -256, -1].try_into().unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn test_array_correct() {
|
||||
let c: Color = [183, 65, 14].try_into().unwrap();
|
||||
assert_eq!(c.red, 183);
|
||||
assert_eq!(c.green, 65);
|
||||
assert_eq!(c.blue, 14);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_slice_out_of_range_positive() {
|
||||
let arr = [10000, 256, 1000];
|
||||
let _ = Color::try_from(&arr[..]).unwrap();
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_slice_out_of_range_negative() {
|
||||
let arr = [-256, -1, -10];
|
||||
let _ = Color::try_from(&arr[..]).unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn test_slice_correct() {
|
||||
let v = vec![183, 65, 14];
|
||||
let c = Color::try_from(&v[..]).unwrap();
|
||||
assert_eq!(c.red, 183);
|
||||
assert_eq!(c.green, 65);
|
||||
assert_eq!(c.blue, 14);
|
||||
}
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_slice_excess_length() {
|
||||
let v = vec![0, 0, 0, 0];
|
||||
let _ = Color::try_from(&v[..]).unwrap();
|
||||
}
|
||||
}
|
||||
17
exercises/conversions/using_as.rs
Normal file
17
exercises/conversions/using_as.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
// 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);
|
||||
total / values.len()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let values = [3.5, 0.3, 13.0, 11.7];
|
||||
println!("{}", average(&values));
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
### Enums
|
||||
|
||||
Rust allows you to define a type called `enums` which allow you to enumerate possible values. In combination with enums, we have the concept of `pattern matching` in Rust, which makes it easy to run different code for different values of an enumeration. Enums, while available in many languages, Rust's enums are most similar to `algebraic data types` in functional languages, such as F#, OCaml, and Haskell.
|
||||
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.
|
||||
|
||||
#### Book Sections
|
||||
|
||||
- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
|
||||
- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// enums1.rs
|
||||
// Make me compile! Scroll down for hints!
|
||||
// Make me compile! Execute `rustlings hint enums1` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Message {
|
||||
@@ -12,31 +14,3 @@ fn main() {
|
||||
println!("{:?}", Message::Move);
|
||||
println!("{:?}", Message::ChangeColor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Hint: The declaration of the enumeration type has not been defined yet.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// enums2.rs
|
||||
// Make me compile! Scroll down for hints
|
||||
// Make me compile! Execute `rustlings hint enums2` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Message {
|
||||
@@ -24,38 +26,3 @@ fn main() {
|
||||
message.call();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Hint: you can create enumerations that have different variants with different types
|
||||
// such as no data, anonymous structs, a single string, tuples, ...etc
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// enums3.rs
|
||||
// Address all the TODOs to make the tests pass!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
enum Message {
|
||||
// TODO: implement the message variant types based on their usage below
|
||||
}
|
||||
@@ -51,7 +53,7 @@ mod tests {
|
||||
};
|
||||
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));
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
// was, instead of just sometimes returning `None`. The 2nd test currently
|
||||
// does not compile or pass, but it illustrates the behavior we would like
|
||||
// this function to have.
|
||||
// Scroll down for hints!!!
|
||||
// Execute `rustlings hint errors1` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn generate_nametag_text(name: String) -> Option<String> {
|
||||
if name.len() > 0 {
|
||||
@@ -38,36 +40,3 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// `Err` is one of the variants of `Result`, so what the 2nd test is saying
|
||||
// is that `generate_nametag_text` should return a `Result` instead of an
|
||||
// `Option`.
|
||||
|
||||
// To make this change, you'll need to:
|
||||
// - update the return type in the function signature to be a Result<String, String> that
|
||||
// could be the variants `Ok(String)` and `Err(String)`
|
||||
// - change the body of the function to return `Ok(stuff)` where it currently
|
||||
// returns `Some(stuff)`
|
||||
// - change the body of the function to return `Err(error message)` where it
|
||||
// currently returns `None`
|
||||
// - change the first test to expect `Ok(stuff)` where it currently expects
|
||||
// `Some(stuff)`.
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
// and add.
|
||||
|
||||
// There are at least two ways to implement this that are both correct-- but
|
||||
// one is a lot shorter! Scroll down for hints to both ways.
|
||||
// one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
@@ -43,27 +45,3 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// One way to handle this is using a `match` statement on
|
||||
// `item_quantity.parse::<i32>()` where the cases are `Ok(something)` and
|
||||
// `Err(something)`. This pattern is very common in Rust, though, so there's
|
||||
// a `?` operator that does pretty much what you would make that match statement
|
||||
// do for you! Take a look at this section of the Error Handling chapter:
|
||||
// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
// and give it a try!
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// errors3.rs
|
||||
// This is a program that is trying to use a completed version of the
|
||||
// `total_cost` function from the previous exercise. It's not working though!
|
||||
// Why not? What should we do to fix it? Scroll for hints!
|
||||
// Why not? What should we do to fix it?
|
||||
// Execute `rustlings hint errors3` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
@@ -26,22 +29,3 @@ pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
|
||||
|
||||
Ok(qty * cost_per_item + processing_fee)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// If other functions can return a `Result`, why shouldn't `main`?
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
// 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!
|
||||
// Edit the `read_and_validate` function ONLY. Don't create any Errors
|
||||
// that do not already exist.
|
||||
//
|
||||
// So many things could go wrong!
|
||||
//
|
||||
// - Reading from stdin could produce an io::Error
|
||||
// - Parsing the input could produce a num::ParseIntError
|
||||
@@ -13,7 +15,9 @@
|
||||
// type goes where the question marks are, and how do we return
|
||||
// that type from the body of read_and_validate?
|
||||
//
|
||||
// Scroll down for hints :)
|
||||
// Execute `rustlings hint errorsn` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
@@ -28,6 +32,10 @@ fn read_and_validate(b: &mut dyn io::BufRead) -> Result<PositiveNonzeroInteger,
|
||||
answer
|
||||
}
|
||||
|
||||
//
|
||||
// Nothing below this needs to be modified
|
||||
//
|
||||
|
||||
// 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());
|
||||
@@ -98,150 +106,12 @@ enum CreationError {
|
||||
|
||||
impl fmt::Display for CreationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str((self as &dyn error::Error).description())
|
||||
let description = match *self {
|
||||
CreationError::Negative => "Number is negative",
|
||||
CreationError::Zero => "Number is zero",
|
||||
};
|
||||
f.write_str(description)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CreationError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
CreationError::Negative => "Negative",
|
||||
CreationError::Zero => "Zero",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// First hint: To figure out what type should go where the ??? is, take a look
|
||||
// at the test helper function `test_with_str`, since it returns whatever
|
||||
// `read_and_validate` returns and`test_with_str` has its signature fully
|
||||
// specified.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Next hint: There are three places in `read_and_validate` that we call a
|
||||
// function that returns a `Result` (that is, the functions might fail).
|
||||
// Apply the `?` operator on those calls so that we return immediately from
|
||||
// `read_and_validate` if those function calls fail.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Another hint: under the hood, the `?` operator calls `From::from`
|
||||
// on the error value to convert it to a boxed trait object, a Box<dyn error::Error>,
|
||||
// which is polymorphic-- that means that lots of different kinds of errors
|
||||
// can be returned from the same function because all errors act the same
|
||||
// since they all implement the `error::Error` trait.
|
||||
// Check out this section of the book:
|
||||
// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Another another hint: Note that because the `?` operator returns
|
||||
// the *unwrapped* value in the `Ok` case, if we want to return a `Result` from
|
||||
// `read_and_validate` for *its* success case, we'll have to rewrap a value
|
||||
// that we got from the return value of a `?`ed call in an `Ok`-- this will
|
||||
// look like `Ok(something)`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Another another another hint: `Result`s must be "used", that is, you'll
|
||||
// get a warning if you don't handle a `Result` that you get in your
|
||||
// function. Read more about that in the `std::result` module docs:
|
||||
// https://doc.rust-lang.org/std/result/#results-must-be-used
|
||||
impl error::Error for CreationError {}
|
||||
|
||||
@@ -1,57 +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`!
|
||||
// Scroll down for hints :)
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Try using a `match` statement where the arms are `Some(thing)` and `None`.
|
||||
// Or set a default value to print out if you get `None` by using the
|
||||
// function `unwrap_or`.
|
||||
// Or use an `if let` statement on the result of `pop()` to both destructure
|
||||
// a `Some` value and only print out something if we have a value!
|
||||
@@ -1,5 +1,7 @@
|
||||
// result1.rs
|
||||
// Make this test pass! Scroll down for hints :)
|
||||
// Make this test pass! Execute `rustlings hint result1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
@@ -25,22 +27,3 @@ fn test_creation() {
|
||||
);
|
||||
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// `PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result.
|
||||
// It should be doing some checking, returning an `Err` result if those checks fail, and only
|
||||
// returning an `Ok` result if those checks determine that everything is... okay :)
|
||||
|
||||
@@ -1,44 +1,8 @@
|
||||
// functions1.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint functions1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
call_me();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// This main function is calling a function that it expects to exist, but the
|
||||
// function doesn't exist. It expects this function to have the name `call_me`.
|
||||
// It expects this function to not take any arguments and not return a value.
|
||||
// Sounds a lot like `main`, doesn't it?
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// functions2.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint functions2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
call_me(3);
|
||||
@@ -10,33 +12,3 @@ fn call_me(num) {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Rust requires that all parts of a function's signature have type annotations,
|
||||
// but `call_me` is missing the type annotation of `num`.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// functions3.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint functions3` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
call_me();
|
||||
@@ -10,33 +12,3 @@ fn call_me(num: i32) {
|
||||
println!("Ring! Call number {}", i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// This time, the function *declaration* is okay, but there's something wrong
|
||||
// with the place where we're calling the function.
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// functions4.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint functions4` for hints :)
|
||||
|
||||
// This store is having a sale where if the price is an even number, you get
|
||||
// 10 (money unit) off, but if it's an odd number, it's 3 (money unit) less.
|
||||
// 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let original_price = 51;
|
||||
@@ -20,25 +22,3 @@ fn sale_price(price: i32) -> {
|
||||
fn is_even(num: i32) -> bool {
|
||||
num % 2 == 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The error message points to line 12 and says it expects a type after the
|
||||
// `->`. This is where the function's return type should be-- take a look at
|
||||
// the `is_even` function for an example!
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// functions5.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint functions5` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let answer = square(3);
|
||||
@@ -9,39 +11,3 @@ fn main() {
|
||||
fn square(num: i32) -> i32 {
|
||||
num * num;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// This is a really common error that can be fixed by removing one character.
|
||||
// It happens because Rust distinguishes between expressions and statements: expressions return
|
||||
// a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language.
|
||||
// We want to return a value of `i32` type from the `square` function, but it is returning a `()` type...
|
||||
// They are not the same. There are two solutions:
|
||||
// 1. Add a `return` ahead of `num * num;`
|
||||
// 2. remove `;`, make it to be `num * num`
|
||||
|
||||
7
exercises/generics/README.md
Normal file
7
exercises/generics/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
### Generics
|
||||
|
||||
In this section you'll learn about saving yourself many lines of code with generics!
|
||||
|
||||
### Book Sections
|
||||
|
||||
- [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html)
|
||||
10
exercises/generics/generics1.rs
Normal file
10
exercises/generics/generics1.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
// This shopping list program isn't compiling!
|
||||
// Use your knowledge of generics to fix it.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let mut shopping_list: Vec<?> = Vec::new();
|
||||
shopping_list.push("milk");
|
||||
}
|
||||
|
||||
28
exercises/generics/generics2.rs
Normal file
28
exercises/generics/generics2.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
// This powerful wrapper provides the ability to store a positive integer value.
|
||||
// Rewrite it using generics so that it supports wrapping ANY type.
|
||||
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
48
exercises/generics/generics3.rs
Normal file
48
exercises/generics/generics3.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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 to support alphabetical report cards, thereby making
|
||||
// the second test pass.
|
||||
|
||||
// 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,11 +1,13 @@
|
||||
// if1.rs
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn bigger(a: i32, b: i32) -> i32 {
|
||||
// Complete this function to return the bigger number!
|
||||
// Do not use:
|
||||
// - another function call
|
||||
// - additional variables
|
||||
// Scroll down for hints.
|
||||
// Execute `rustlings hint if1` for hints
|
||||
}
|
||||
|
||||
// Don't mind this for now :)
|
||||
@@ -23,36 +25,3 @@ mod tests {
|
||||
assert_eq!(42, bigger(32, 42));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// It's possible to do this in one line if you would like!
|
||||
// Some similar examples from other languages:
|
||||
// - In C(++) this would be: `a > b ? a : b`
|
||||
// - In Python this would be: `a if a > b else b`
|
||||
// Remember in Rust that:
|
||||
// - the `if` condition does not need to be surrounded by parentheses
|
||||
// - `if`/`else` conditionals are expressions
|
||||
// - Each condition is followed by a `{}` block.
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// macros1.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint macros1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
@@ -10,55 +12,3 @@ macro_rules! my_macro {
|
||||
fn main() {
|
||||
my_macro();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// When you call a macro, you need to add something special compared to a
|
||||
// regular function call. If you're stuck, take a look at what's inside
|
||||
// `my_macro`.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// macros2.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint macros2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
my_macro!();
|
||||
@@ -10,64 +12,3 @@ macro_rules! my_macro {
|
||||
println!("Check out my macro!");
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Macros don't quite play by the same rules as the rest of Rust, in terms of
|
||||
// what's available where.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Unlike other things in Rust, the order of "where you define a macro" versus
|
||||
// "where you use it" actually matters.
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// macros3.rs
|
||||
// Make me compile, without taking the macro out of the module! Scroll down for hints :)
|
||||
// Make me compile, without taking the macro out of the module!
|
||||
// Execute `rustlings hint macros3` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
mod macros {
|
||||
macro_rules! my_macro {
|
||||
@@ -12,64 +15,3 @@ mod macros {
|
||||
fn main() {
|
||||
my_macro!();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// In order to use a macro outside of its module, you need to do something
|
||||
// special to the module to lift the macro out into its parent.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The same trick also works on "extern crate" statements for crates that have
|
||||
// exported macros, if you've seen any of those around.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// macros4.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint macros4` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
@@ -14,64 +16,3 @@ fn main() {
|
||||
my_macro!();
|
||||
my_macro!(7777);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// You only need to add a single character to make this compile.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The way macros are written, it wants to see something between each
|
||||
// "macro arm", so it can separate them.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// modules1.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint modules1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
mod sausage_factory {
|
||||
fn make_sausage() {
|
||||
@@ -10,34 +12,3 @@ mod sausage_factory {
|
||||
fn main() {
|
||||
sausage_factory::make_sausage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Everything is private in Rust by default-- but there's a keyword we can use
|
||||
// to make something public! The compiler error should point to the thing that
|
||||
// needs to be public.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// modules2.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint modules2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
mod delicious_snacks {
|
||||
use self::fruits::PEAR as fruit;
|
||||
@@ -23,25 +25,3 @@ fn main() {
|
||||
delicious_snacks::veggie
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The delicious_snacks module is trying to present an external
|
||||
// interface (the `fruit` and `veggie` constants) that is different than
|
||||
// its internal structure (the `fruits` and `veggies` modules and
|
||||
// associated constants). It's almost there except for one keyword missing for
|
||||
// each constant.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// move_semantics1.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute `rustlings hint move_semantics1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let vec0 = Vec::new();
|
||||
@@ -22,21 +24,3 @@ fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 11,
|
||||
// right? The fix for this is going to be adding one keyword, and the addition is NOT on line 11
|
||||
// where the error is.
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// move_semantics2.rs
|
||||
// Make me compile without changing line 10! Scroll down for hints :)
|
||||
// Make me compile without changing line 13!
|
||||
// Execute `rustlings hint move_semantics2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let vec0 = Vec::new();
|
||||
@@ -23,31 +26,3 @@ fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// So `vec0` is being *moved* into the function `fill_vec` when we call it on
|
||||
// line 7, which means it gets dropped at the end of `fill_vec`, which means we
|
||||
// can't use `vec0` again on line 10 (or anywhere else in `main` after the
|
||||
// `fill_vec` call for that matter). We could fix this in a few ways, try them
|
||||
// all!
|
||||
// 1. Make another, separate version of the data that's in `vec0` and pass that
|
||||
// to `fill_vec` instead.
|
||||
// 2. Make `fill_vec` borrow its argument instead of taking ownership of it,
|
||||
// and then copy the data within the function in order to return an owned
|
||||
// `Vec<i32>`
|
||||
// 3. Make `fill_vec` *mutably* borrow its argument (which will need to be
|
||||
// mutable), modify it directly, then not return anything. Then you can get rid
|
||||
// of `vec1` entirely -- note that this will change what gets printed by the
|
||||
// first `println!`
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// move_semantics3.rs
|
||||
// Make me compile without adding new lines-- just changing existing lines!
|
||||
// (no lines with multiple semicolons necessary!)
|
||||
// Scroll down for hints :)
|
||||
// Execute `rustlings hint move_semantics3` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let vec0 = Vec::new();
|
||||
@@ -22,24 +24,3 @@ fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The difference between this one and the previous ones is that the first line
|
||||
// of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can,
|
||||
// instead of adding that line back, add `mut` in one place that will change
|
||||
// an existing binding to be a mutable binding instead of an immutable one :)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// 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
|
||||
// freshly created vector from fill_vec to its caller. Scroll for hints!
|
||||
// freshly created vector from fill_vec to its caller.
|
||||
// Execute `rustlings hint move_semantics4` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let vec0 = Vec::new();
|
||||
@@ -25,24 +28,3 @@ fn fill_vec() -> Vec<i32> {
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Stop reading whenever you feel like you have enough direction :) Or try
|
||||
// doing one step and then fixing the compiler errors that result!
|
||||
// So the end goal is to:
|
||||
// - get rid of the first line in main that creates the new vector
|
||||
// - so then `vec0` doesn't exist, so we can't pass it to `fill_vec`
|
||||
// - we don't want to pass anything to `fill_vec`, so its signature should
|
||||
// reflect that it does not take any arguments
|
||||
// - since we're not creating a new vec in `main` anymore, we need to create
|
||||
// a new vec in `fill_vec`, similarly to the way we did in `main`
|
||||
|
||||
9
exercises/option/README.md
Normal file
9
exercises/option/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
### Option
|
||||
|
||||
#### Book Sections
|
||||
|
||||
To learn about Option<T>, check out these links:
|
||||
|
||||
- [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_value = Some(String::from("rustlings"));
|
||||
// TODO: Make this an if let statement whose value is "Some" type
|
||||
value = optional_value {
|
||||
println!("the value of optional value is: {}", value);
|
||||
} else {
|
||||
println!("The optional value doesn't contain anything!");
|
||||
}
|
||||
|
||||
let mut optional_values_vec: Vec<Option<i8>> = Vec::new();
|
||||
for x in 1..10 {
|
||||
optional_values_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
|
||||
value = optional_values_vec.pop() {
|
||||
println!("current value: {}", value);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
// Fill in the rest of the line that has code missing!
|
||||
// No hints, there's no tricks, just get used to typing these :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
// Booleans (`bool`)
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Fill in the rest of the line that has code missing!
|
||||
// No hints, there's no tricks, just get used to typing these :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
// Characters (`char`)
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// primitive_types3.rs
|
||||
// Create an array with at least 100 elements in it where the ??? is.
|
||||
// Scroll down for hints!
|
||||
// Execute `rustlings hint primitive_types3` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let a = ???
|
||||
@@ -11,37 +13,3 @@ fn main() {
|
||||
println!("Meh, I eat arrays like that for breakfast.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// There's a shorthand to initialize Arrays with a certain size that does not
|
||||
// require you to type in 100 items (but you certainly can if you want!).
|
||||
// For example, you can do:
|
||||
// let array = ["Are we there yet?"; 10];
|
||||
|
||||
// Bonus: what are some other things you could have that would return true
|
||||
// for `a.len() >= 100`?
|
||||
|
||||
@@ -1,68 +1,14 @@
|
||||
// primitive_types4.rs
|
||||
// Get a slice out of Array a where the ??? is so that the `if` statement
|
||||
// returns true. Scroll down for hints!!
|
||||
// Get a slice out of Array a where the ??? is so that the test passes.
|
||||
// Execute `rustlings hint primitive_types4` for hints!!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[test]
|
||||
fn main() {
|
||||
fn slice_out_of_array() {
|
||||
let a = [1, 2, 3, 4, 5];
|
||||
|
||||
let nice_slice = ???
|
||||
|
||||
assert_eq!([2, 3, 4], nice_slice)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book:
|
||||
// https://doc.rust-lang.org/book/ch04-03-slices.html
|
||||
// and use the starting and ending indices of the items in the Array
|
||||
// that you want to end up in the slice.
|
||||
|
||||
// If you're curious why the right hand of the `==` comparison does not
|
||||
// have an ampersand for a reference since the left hand side is a
|
||||
// reference, take a look at the Deref coercions section of the book:
|
||||
// https://doc.rust-lang.org/book/ch15-02-deref.html
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// primitive_types5.rs
|
||||
// Destructure the `cat` tuple so that the println will work.
|
||||
// Scroll down for hints!
|
||||
// Execute `rustlings hint primitive_types5` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let cat = ("Furry McFurson", 3.5);
|
||||
@@ -8,38 +10,3 @@ fn main() {
|
||||
|
||||
println!("{} is {} years old.", name, age);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Take a look at the Data Types -> The Tuple Type section of the book:
|
||||
// https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
|
||||
// Particularly the part about destructuring (second to last example in the section).
|
||||
// You'll need to make a pattern to bind `name` and `age` to the appropriate parts
|
||||
// of the tuple. You can do it!!
|
||||
|
||||
@@ -1,45 +1,11 @@
|
||||
// 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.
|
||||
// Scroll down for hints!
|
||||
// Execute `rustlings hint primitive_types6` for hints!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let numbers = (1, 2, 3);
|
||||
println!("The second number is {}", ???);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// While you could use a destructuring `let` for the tuple here, try
|
||||
// indexing into it instead, as explained in the last example of the
|
||||
// Data Types -> The Tuple Type section of the book:
|
||||
// https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
|
||||
// Now you have another tool in your toolbox!
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
// 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 dollars, but if you buy
|
||||
// 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!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
// Put your function here!
|
||||
// fn ..... {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
// test2.rs
|
||||
// This is a test for the following sections:
|
||||
// quiz2.rs
|
||||
// This is a quiz for the following sections:
|
||||
// - Strings
|
||||
|
||||
// Ok, here are a bunch of values-- some are `Strings`, some are `&strs`. Your
|
||||
// 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);
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
// 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 :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn times_two(num: i32) -> i32 {
|
||||
num * 2
|
||||
}
|
||||
23
exercises/quiz4.rs
Normal file
23
exercises/quiz4.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
// quiz4.rs
|
||||
// This quiz covers the sections:
|
||||
// - Modules
|
||||
// - Macros
|
||||
|
||||
// Write a macro that passes the quiz! No hints this time, you can do it!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_my_macro_world() {
|
||||
assert_eq!(my_macro!("world!"), "Hello world!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_my_macro_goodbye() {
|
||||
assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
For the Box exercise check out the chapter [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html).
|
||||
|
||||
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.
|
||||
|
||||
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-- iterators 1 and 2 are indeed missing. Iterator 3 is a bit challenging so we're leaving space for some exercises to lead up to it!
|
||||
Do not adjust your monitors-- iterators1.rs is indeed missing. Iterators is a challenging topic, so we're leaving space for a simpler exercise!
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// arc1.rs
|
||||
// Make this code compile by filling in a value for `shared_numbers` where the
|
||||
// TODO comment is and creating an initial binding for `child_numbers`
|
||||
// TODO comment is and create an initial binding for `child_numbers`
|
||||
// somewhere. Try not to create any copies of the `numbers` Vec!
|
||||
// Scroll down for hints :)
|
||||
// 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;
|
||||
|
||||
@@ -27,29 +30,3 @@ fn main() {
|
||||
handle.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order
|
||||
// to avoid creating a copy of `numbers`, you'll need to create `child_numbers`
|
||||
// inside the loop but still in the main thread.
|
||||
|
||||
// `child_numbers` should be a clone of the Arc of the numbers instead of a
|
||||
// thread-local copy of the numbers.
|
||||
|
||||
53
exercises/standard_library_types/box1.rs
Normal file
53
exercises/standard_library_types/box1.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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())
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
// 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
|
||||
// As always, there are hints below!
|
||||
// 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.
|
||||
// Ensure that it returns a vector of strings as well.
|
||||
// Step 3. Apply the `capitalize_first` function again to a list.
|
||||
// Try to ensure it returns a single string.
|
||||
// As always, there are hints if you execute `rustlings hint iterators2`!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn capitalize_first(input: &str) -> String {
|
||||
let mut c = input.chars();
|
||||
@@ -44,102 +48,3 @@ mod tests {
|
||||
assert_eq!(capitalized_words, "Hello World");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Step 1
|
||||
// You need to call something on `first` before it can be collected
|
||||
// Currently its type is `char`. Have a look at the methods that are available on that type:
|
||||
// https://doc.rust-lang.org/std/primitive.char.html
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Step 2
|
||||
// First you'll need to turn the Vec into an iterator
|
||||
// Then you'll need to apply your function unto each item in the vector
|
||||
// P.s. Don't forget to collect() at the end!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Step 3.
|
||||
// This is very similar to the previous test. The only real change is that you will need to
|
||||
// alter the type that collect is coerced into. For a bonus you could try doing this with a
|
||||
// turbofish
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
// 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`.
|
||||
// Scroll down for a minor hint for part 2, and scroll down further for
|
||||
// a major hint.
|
||||
// Execute `rustlings hint iterators3` to get some hints!
|
||||
// Have fun :-)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum DivisionError {
|
||||
NotDivisible(NotDivisibleError),
|
||||
@@ -75,72 +76,3 @@ mod tests {
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Minor hint: In each of the two cases in the match in main, you can create x with either
|
||||
// a 'turbofish' or by hinting the type of x to the compiler. You may try both.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Major hint: Have a look at the Iter trait and at the explanation of its collect function.
|
||||
// Especially the part about Result is interesting.
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
// iterators4.rs
|
||||
|
||||
// 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
|
||||
// Scroll down for hints.
|
||||
// Execute `rustlings hint iterators4` for hints.
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -30,32 +32,3 @@ mod tests {
|
||||
assert_eq!(24, factorial(4));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// In an imperative language you might write a for loop to iterate through
|
||||
// multiply the values into a mutable variable. Or you might write code more
|
||||
// functionally with recursion and a match clause. But you can also use ranges
|
||||
// and iterators to solve this in rust.
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// strings1.rs
|
||||
// Make me compile without changing the function signature! Scroll down for hints :)
|
||||
// Make me compile without changing the function signature!
|
||||
// Execute `rustlings hint strings1` for hints ;)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let answer = current_favorite_color();
|
||||
@@ -9,38 +12,3 @@ fn main() {
|
||||
fn current_favorite_color() -> String {
|
||||
"blue"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The `current_favorite_color` function is currently returning a string slice with the `'static`
|
||||
// lifetime. We know this because the data of the string lives in our code itself -- it doesn't
|
||||
// come from a file or user input or another program -- so it will live as long as our program
|
||||
// lives. But it is still a string slice. There's one way to create a `String` by converting a
|
||||
// string slice covered in the Strings chapter of the book, and another way that uses the `From`
|
||||
// trait.
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// strings2.rs
|
||||
// Make me compile without changing the function signature! Scroll down for hints :)
|
||||
// Make me compile without changing the function signature!
|
||||
// Execute `rustlings hint strings2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let word = String::from("green"); // Try not changing this line :)
|
||||
@@ -13,32 +16,3 @@ fn main() {
|
||||
fn is_a_color_word(attempt: &str) -> bool {
|
||||
attempt == "green" || attempt == "blue" || attempt == "red"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Yes, it would be really easy to fix this by just changing the value bound to `word` to be a
|
||||
// string slice instead of a `String`, wouldn't it?? There is a way to add one character to line
|
||||
// 6, though, that will coerce the `String` into a string slice.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// structs1.rs
|
||||
// Address all the TODOs to make the tests pass!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
struct ColorClassicStruct {
|
||||
// TODO: Something goes here
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// structs2.rs
|
||||
// Address all the TODOs to make the tests pass!
|
||||
// No hints, just do it!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Order {
|
||||
|
||||
67
exercises/structs/structs3.rs
Normal file
67
exercises/structs/structs3.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
// structs3.rs
|
||||
// Structs contain more than simply some data, they 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_kg: i32) -> ??? {
|
||||
// Something goes here... (beware of grams to kg conversion)
|
||||
}
|
||||
}
|
||||
|
||||
#[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 calculate_transport_fees() {
|
||||
let sender_country = String::from("Spain");
|
||||
let recipient_country = String::from("Spain");
|
||||
|
||||
let cents_per_kg = ???;
|
||||
|
||||
let package = Package::new(sender_country, recipient_country, 1500);
|
||||
|
||||
assert_eq!(package.get_fees(cents_per_kg), 4500);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// test4.rs
|
||||
// This test covers the sections:
|
||||
// - Modules
|
||||
// - Macros
|
||||
|
||||
// Write a macro that passes the test! No hints this time, you can do it!
|
||||
|
||||
fn main() {
|
||||
if my_macro!("world!") != "Hello world!" {
|
||||
panic!("Oh no! Wrong output!");
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
// tests1.rs
|
||||
// Tests are important to ensure that your code does what you think it should do.
|
||||
// Tests can be run on this file with the following command:
|
||||
// rustlings run --test exercises/tests/tests1.rs
|
||||
// rustlings run tests1
|
||||
|
||||
// This test has a problem with it -- make the test compile! Make the test
|
||||
// pass! Make the test fail! Scroll down for hints :)
|
||||
// pass! Make the test fail! Execute `rustlings hint tests1` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -13,37 +15,3 @@ mod tests {
|
||||
assert!();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// You don't even need to write any code to test -- you can just test values and run that, even
|
||||
// though you wouldn't do that in real life :) `assert!` is a macro that needs an argument.
|
||||
// Depending on the value of the argument, `assert!` will do nothing (in which case the test will
|
||||
// pass) or `assert!` will panic (in which case the test will fail). So try giving different values
|
||||
// to `assert!` and see which ones compile, which ones pass, and which ones fail :)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// tests2.rs
|
||||
// This test has a problem with it -- make the test compile! Make the test
|
||||
// pass! Make the test fail! Scroll down for hints :)
|
||||
// pass! Make the test fail! Execute `rustlings hint tests2` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -9,36 +11,3 @@ mod tests {
|
||||
assert_eq!();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Like the previous exercise, you don't need to write any code to get this test to compile and
|
||||
// run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two
|
||||
// values that are equal! Try giving it two arguments that are different! Try giving it two values
|
||||
// that are of different types! Try switching which argument comes first and which comes second!
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// tests3.rs
|
||||
// This test isn't testing our function -- make it do that in such a way that
|
||||
// the test passes. Then write a second test that tests whether we get the result
|
||||
// we expect to get when we call `is_even(5)`. Scroll down for hints!
|
||||
// we expect to get when we call `is_even(5)`.
|
||||
// Execute `rustlings hint tests3` for hints :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
pub fn is_even(num: i32) -> bool {
|
||||
num % 2 == 0
|
||||
@@ -16,28 +19,3 @@ mod tests {
|
||||
assert!();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// You can call a function right where you're passing arguments to `assert!` -- so you could do
|
||||
// something like `assert!(having_fun())`. If you want to check that you indeed get false, you
|
||||
// can negate the result of what you're doing using `!`, like `assert!(!having_fun())`.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// threads1.rs
|
||||
// Make this compile! Scroll down for hints :) The idea is the thread
|
||||
// spawned on line 19 is completing jobs while the main thread is
|
||||
// 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
|
||||
// of "waiting..." and the program ends without timing out the playground,
|
||||
// of "waiting..." and the program ends without timing out when running,
|
||||
// you've got it :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
@@ -27,69 +29,3 @@ fn main() {
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// `Arc` is an Atomic Reference Counted pointer that allows safe, shared access
|
||||
// to **immutable** data. But we want to *change* the number of `jobs_completed`
|
||||
// so we'll need to also use another type that will only allow one thread to
|
||||
// mutate the data at a time. Take a look at this section of the book:
|
||||
// https://doc.rust-lang.org/book/ch16-03-shared-state.html#atomic-reference-counting-with-arct
|
||||
// and keep scrolling if you'd like more hints :)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like:
|
||||
// `let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));`
|
||||
// Similar to the code in the example in the book that happens after the text
|
||||
// that says "We can use Arc<T> to fix this.". If not, give that a try! If you
|
||||
// do and would like more hints, keep scrolling!!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Make sure neither of your threads are holding onto the lock of the mutex
|
||||
// while they are sleeping, since this will prevent the other thread from
|
||||
// being allowed to get the lock. Locks are automatically released when
|
||||
// they go out of scope.
|
||||
|
||||
// Ok, so, real talk, this was actually tricky for *me* to do too. And
|
||||
// I could see a lot of different problems you might run into, so at this
|
||||
// point I'm not sure which one you've hit :) Please see a few possible
|
||||
// answers on https://github.com/carols10cents/rustlings/issues/3 --
|
||||
// mine is a little more complicated because I decided I wanted to see
|
||||
// the number of jobs currently done when I was checking the status.
|
||||
|
||||
// Please open an issue if you're still running into a problem that
|
||||
// these hints are not helping you with, or if you've looked at the sample
|
||||
// answers and don't understand why they work and yours doesn't.
|
||||
|
||||
// If you've learned from the sample solutions, I encourage you to come
|
||||
// back to this exercise and try it again in a few days to reinforce
|
||||
// what you've learned :)
|
||||
|
||||
20
exercises/traits/README.md
Normal file
20
exercises/traits/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
### 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 `{}`), and
|
||||
+ `Debug` (which allows formatted display via `{:?}`).
|
||||
|
||||
Because traits indicate shared behavior between data types, they are useful when writing generics.
|
||||
|
||||
|
||||
#### Book Sections
|
||||
|
||||
- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html)
|
||||
44
exercises/traits/traits1.rs
Normal file
44
exercises/traits/traits1.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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() {
|
||||
let s = String::from("Foo");
|
||||
let s = s.append_bar();
|
||||
println!("s: {}", s);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn is_FooBar() {
|
||||
assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_BarBar() {
|
||||
assert_eq!(
|
||||
String::from("").append_bar().append_bar(),
|
||||
String::from("BarBar")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
35
exercises/traits/traits2.rs
Normal file
35
exercises/traits/traits2.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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!
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
trait AppendBar {
|
||||
fn append_bar(self) -> Self;
|
||||
}
|
||||
|
||||
//TODO: Add your code here
|
||||
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn is_vec_pop_eq_bar() {
|
||||
let mut foo = vec![String::from("Foo")].append_bar();
|
||||
assert_eq!(foo.pop().unwrap(), String::from("Bar"));
|
||||
assert_eq!(foo.pop().unwrap(), String::from("Foo"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +1,14 @@
|
||||
// variables1.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :)
|
||||
|
||||
// About this `I AM NOT DONE` thing:
|
||||
// We sometimes encourage you to keep trying things on a given exercise,
|
||||
// even after you already figured it out. If you got everything working and
|
||||
// feel ready for the next exercise, remove the `I AM NOT DONE` comment below.
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
x = 5;
|
||||
println!("x has the value {}", x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Hint: The declaration on line 5 is missing a keyword that is needed in Rust
|
||||
// to create a new variable binding.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// variables2.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute the command `rustlings hint variables2` if you want a hint :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let x;
|
||||
@@ -9,39 +11,3 @@ fn main() {
|
||||
println!("Not ten!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The compiler message is saying that Rust cannot infer the type that the
|
||||
// variable binding `x` has with what is given here.
|
||||
// What happens if you annotate line 5 with a type annotation?
|
||||
// What if you give x a value?
|
||||
// What if you do both?
|
||||
// What type should x be, anyway?
|
||||
// What if x is the same type as 10? What if it's a different type?
|
||||
|
||||
@@ -1,43 +1,11 @@
|
||||
// variables3.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute the command `rustlings hint variables3` if you want a hint :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let x = 3;
|
||||
println!("Number {}", x);
|
||||
x = 5;
|
||||
x = 5; // don't change this line
|
||||
println!("Number {}", x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// In Rust, variable bindings are immutable by default. But here we're trying
|
||||
// to reassign a different value to x! There's a keyword we can use to make
|
||||
// a variable binding mutable instead.
|
||||
|
||||
@@ -1,45 +1,9 @@
|
||||
// variables4.rs
|
||||
// Make me compile! Scroll down for hints :)
|
||||
// Make me compile! Execute the command `rustlings hint variables4` if you want a hint :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let x: i32;
|
||||
println!("Number {}", x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Oops! In this exercise, we have a variable binding that we've created on
|
||||
// line 5, and we're trying to use it on line 6, but we haven't given it a
|
||||
// value. We can't print out something that isn't there; try giving x a value!
|
||||
// This is an error that can cause bugs that's very easy to make in any
|
||||
// programming language -- thankfully the Rust compiler has caught this for us!
|
||||
|
||||
11
exercises/variables/variables5.rs
Normal file
11
exercises/variables/variables5.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
// variables5.rs
|
||||
// Make me compile! Execute the command `rustlings hint variables5` if you want a hint :)
|
||||
|
||||
// I AM NOT DONE
|
||||
|
||||
fn main() {
|
||||
let number = "3"; // don't change this line
|
||||
println!("Number {}", number);
|
||||
number = 3;
|
||||
println!("Number {}", number);
|
||||
}
|
||||
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);
|
||||
}
|
||||
599
info.toml
599
info.toml
@@ -1,241 +1,824 @@
|
||||
# VARIABLES
|
||||
|
||||
[[exercises]]
|
||||
name = "variables1"
|
||||
path = "exercises/variables/variables1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Hint: The declaration on line 12 is missing a keyword that is needed in Rust
|
||||
to create a new variable binding."""
|
||||
|
||||
[[exercises]]
|
||||
name = "variables2"
|
||||
path = "exercises/variables/variables2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
The compiler message is saying that Rust cannot infer the type that the
|
||||
variable binding `x` has with what is given here.
|
||||
What happens if you annotate line 7 with a type annotation?
|
||||
What if you give x a value?
|
||||
What if you do both?
|
||||
What type should x be, anyway?
|
||||
What if x is the same type as 10? What if it's a different type?"""
|
||||
|
||||
[[exercises]]
|
||||
name = "variables3"
|
||||
path = "exercises/variables/variables3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
In Rust, variable bindings are immutable by default. But here we're trying
|
||||
to reassign a different value to x! There's a keyword we can use to make
|
||||
a variable binding mutable instead."""
|
||||
|
||||
[[exercises]]
|
||||
name = "variables4"
|
||||
path = "exercises/variables/variables4.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Oops! In this exercise, we have a variable binding that we've created on
|
||||
line 7, and we're trying to use it on line 8, but we haven't given it a
|
||||
value. We can't print out something that isn't there; try giving x a value!
|
||||
This is an error that can cause bugs that's very easy to make in any
|
||||
programming language -- thankfully the Rust compiler has caught this for us!"""
|
||||
|
||||
[[exercises]]
|
||||
name = "variables5"
|
||||
path = "exercises/variables/variables5.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
In variables3 we already learned how to make an immutable variable mutable
|
||||
using a special keyword. Unfortunately this doesn't help us much in this exercise
|
||||
because we want to assign a different typed value to an existing variable. Sometimes
|
||||
you may also like to reuse existing variable names because you are just converting
|
||||
values to different types like in this exercise.
|
||||
Fortunately Rust has a powerful solution to this problem: 'Shadowing'!
|
||||
You can read more about 'Shadowing' in the book's section 'Variables and Mutability':
|
||||
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing
|
||||
Try to solve this exercise afterwards using this technique."""
|
||||
|
||||
[[exercises]]
|
||||
name = "variables6"
|
||||
path = "exercises/variables/variables6.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
We know about variables and mutability, but there is another important type of
|
||||
variable available; constants.
|
||||
Constants are always immutable and they are declared with keyword 'const' rather
|
||||
than keyword 'let'.
|
||||
Constants types must also always be annotated.
|
||||
|
||||
Read more about constants under 'Differences Between Variables and Constants' in the book's section 'Variables and Mutability':
|
||||
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
|
||||
"""
|
||||
|
||||
# IF
|
||||
|
||||
[[exercises]]
|
||||
name = "if1"
|
||||
path = "exercises/if/if1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
It's possible to do this in one line if you would like!
|
||||
Some similar examples from other languages:
|
||||
- In C(++) this would be: `a > b ? a : b`
|
||||
- In Python this would be: `a if a > b else b`
|
||||
Remember in Rust that:
|
||||
- the `if` condition does not need to be surrounded by parentheses
|
||||
- `if`/`else` conditionals are expressions
|
||||
- Each condition is followed by a `{}` block."""
|
||||
|
||||
[[exercises]]
|
||||
name = "if2"
|
||||
path = "exercises/if/if2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
For that first compiler error, it's important in Rust that each conditional
|
||||
block return the same type! To get the tests passing, you will need a couple
|
||||
conditions checking different input values."""
|
||||
|
||||
# FUNCTIONS
|
||||
|
||||
[[exercises]]
|
||||
name = "functions1"
|
||||
path = "exercises/functions/functions1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
This main function is calling a function that it expects to exist, but the
|
||||
function doesn't exist. It expects this function to have the name `call_me`.
|
||||
It expects this function to not take any arguments and not return a value.
|
||||
Sounds a lot like `main`, doesn't it?"""
|
||||
|
||||
[[exercises]]
|
||||
name = "functions2"
|
||||
path = "exercises/functions/functions2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Rust requires that all parts of a function's signature have type annotations,
|
||||
but `call_me` is missing the type annotation of `num`."""
|
||||
|
||||
[[exercises]]
|
||||
name = "functions3"
|
||||
path = "exercises/functions/functions3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
This time, the function *declaration* is okay, but there's something wrong
|
||||
with the place where we're calling the function."""
|
||||
|
||||
[[exercises]]
|
||||
name = "functions4"
|
||||
path = "exercises/functions/functions4.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
The error message points to line 14 and says it expects a type after the
|
||||
`->`. This is where the function's return type should be-- take a look at
|
||||
the `is_even` function for an example!"""
|
||||
|
||||
[[exercises]]
|
||||
name = "functions5"
|
||||
path = "exercises/functions/functions5.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
This is a really common error that can be fixed by removing one character.
|
||||
It happens because Rust distinguishes between expressions and statements: expressions return
|
||||
a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language.
|
||||
We want to return a value of `i32` type from the `square` function, but it is returning a `()` type...
|
||||
They are not the same. There are two solutions:
|
||||
1. Add a `return` ahead of `num * num;`
|
||||
2. remove `;`, make it to be `num * num`"""
|
||||
|
||||
# TEST 1
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test1.rs"
|
||||
name = "quiz1"
|
||||
path = "exercises/quiz1.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# PRIMITIVE TYPES
|
||||
|
||||
[[exercises]]
|
||||
name = "primitive_types1"
|
||||
path = "exercises/primitive_types/primitive_types1.rs"
|
||||
mode = "compile"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
[[exercises]]
|
||||
name = "primitive_types2"
|
||||
path = "exercises/primitive_types/primitive_types2.rs"
|
||||
mode = "compile"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
[[exercises]]
|
||||
name = "primitive_types3"
|
||||
path = "exercises/primitive_types/primitive_types3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
There's a shorthand to initialize Arrays with a certain size that does not
|
||||
require you to type in 100 items (but you certainly can if you want!).
|
||||
For example, you can do:
|
||||
let array = ["Are we there yet?"; 10];
|
||||
|
||||
Bonus: what are some other things you could have that would return true
|
||||
for `a.len() >= 100`?"""
|
||||
|
||||
[[exercises]]
|
||||
name = "primitive_types4"
|
||||
path = "exercises/primitive_types/primitive_types4.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Take a look at the Understanding Ownership -> Slices -> Other Slices section of the book:
|
||||
https://doc.rust-lang.org/book/ch04-03-slices.html
|
||||
and use the starting and ending indices of the items in the Array
|
||||
that you want to end up in the slice.
|
||||
|
||||
If you're curious why the first argument of `assert_eq!` does not
|
||||
have an ampersand for a reference since the second argument is a
|
||||
reference, take a look at the Deref coercions section of the book:
|
||||
https://doc.rust-lang.org/book/ch15-02-deref.html"""
|
||||
|
||||
[[exercises]]
|
||||
name = "primitive_types5"
|
||||
path = "exercises/primitive_types/primitive_types5.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Take a look at the Data Types -> The Tuple Type section of the book:
|
||||
https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
|
||||
Particularly the part about destructuring (second to last example in the section).
|
||||
You'll need to make a pattern to bind `name` and `age` to the appropriate parts
|
||||
of the tuple. You can do it!!"""
|
||||
|
||||
[[exercises]]
|
||||
name = "primitive_types6"
|
||||
path = "exercises/primitive_types/primitive_types6.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
While you could use a destructuring `let` for the tuple here, try
|
||||
indexing into it instead, as explained in the last example of the
|
||||
Data Types -> The Tuple Type section of the book:
|
||||
https://doc.rust-lang.org/book/ch03-02-data-types.html#the-tuple-type
|
||||
Now you have another tool in your toolbox!"""
|
||||
|
||||
# STRUCTS
|
||||
|
||||
[[exercises]]
|
||||
name = "structs1"
|
||||
path = "exercises/structs/structs1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Rust has more than one type of struct. Both variants are used to package related data together.
|
||||
On the one hand, there are normal, or classic, structs. These are named collections of related data stored in fields.
|
||||
The other variant is tuple structs. Basically just named tuples.
|
||||
In this exercise you need to implement one of each kind.
|
||||
|
||||
Read more about structs in The Book: https://doc.rust-lang.org/stable/book/ch05-00-structs.html"""
|
||||
|
||||
[[exercises]]
|
||||
name = "structs2"
|
||||
path = "exercises/structs/structs2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Creating instances of structs is easy, all you need to do is assign some values to its fields.
|
||||
There is however some shortcuts that can be taken when instantiating structs.
|
||||
Have a look in The Book, to find out more: https://doc.rust-lang.org/stable/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax"""
|
||||
|
||||
[[exercises]]
|
||||
name = "structs3"
|
||||
path = "exercises/structs/structs3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
The new method needs to panic if the weight is physically impossible :), how do we do that in Rust?
|
||||
|
||||
For is_international: What makes a package international? Seems related to the places it goes through right?
|
||||
|
||||
For calculate_transport_fees: Bigger is more expensive usually, we don't have size, but something may fit the bill here :)
|
||||
|
||||
Have a look in The Book, to find out more about method implementations: https://doc.rust-lang.org/book/ch05-03-method-syntax.html"""
|
||||
|
||||
# STRINGS
|
||||
|
||||
[[exercises]]
|
||||
name = "strings1"
|
||||
path = "exercises/strings/strings1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
The `current_favorite_color` function is currently returning a string slice with the `'static`
|
||||
lifetime. We know this because the data of the string lives in our code itself -- it doesn't
|
||||
come from a file or user input or another program -- so it will live as long as our program
|
||||
lives. But it is still a string slice. There's one way to create a `String` by converting a
|
||||
string slice covered in the Strings chapter of the book, and another way that uses the `From`
|
||||
trait."""
|
||||
|
||||
[[exercises]]
|
||||
name = "strings2"
|
||||
path = "exercises/strings/strings2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Yes, it would be really easy to fix this by just changing the value bound to `word` to be a
|
||||
string slice instead of a `String`, wouldn't it?? There is a way to add one character to line
|
||||
9, though, that will coerce the `String` into a string slice."""
|
||||
|
||||
# TEST 2
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test2.rs"
|
||||
name = "quiz2"
|
||||
path = "exercises/quiz2.rs"
|
||||
mode = "compile"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# ENUMS
|
||||
|
||||
[[exercises]]
|
||||
name = "enums1"
|
||||
path = "exercises/enums/enums1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Hint: The declaration of the enumeration type has not been defined yet."""
|
||||
|
||||
[[exercises]]
|
||||
name = "enums2"
|
||||
path = "exercises/enums/enums2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Hint: you can create enumerations that have different variants with different types
|
||||
such as no data, anonymous structs, a single string, tuples, ...etc"""
|
||||
|
||||
[[exercises]]
|
||||
name = "enums3"
|
||||
path = "exercises/enums/enums3.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# TESTS
|
||||
|
||||
[[exercises]]
|
||||
name = "tests1"
|
||||
path = "exercises/tests/tests1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
You don't even need to write any code to test -- you can just test values and run that, even
|
||||
though you wouldn't do that in real life :) `assert!` is a macro that needs an argument.
|
||||
Depending on the value of the argument, `assert!` will do nothing (in which case the test will
|
||||
pass) or `assert!` will panic (in which case the test will fail). So try giving different values
|
||||
to `assert!` and see which ones compile, which ones pass, and which ones fail :)"""
|
||||
|
||||
[[exercises]]
|
||||
name = "tests2"
|
||||
path = "exercises/tests/tests2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Like the previous exercise, you don't need to write any code to get this test to compile and
|
||||
run. `assert_eq!` is a macro that takes two arguments and compares them. Try giving it two
|
||||
values that are equal! Try giving it two arguments that are different! Try giving it two values
|
||||
that are of different types! Try switching which argument comes first and which comes second!"""
|
||||
|
||||
[[exercises]]
|
||||
name = "tests3"
|
||||
path = "exercises/tests/tests3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
You can call a function right where you're passing arguments to `assert!` -- so you could do
|
||||
something like `assert!(having_fun())`. If you want to check that you indeed get false, you
|
||||
can negate the result of what you're doing using `!`, like `assert!(!having_fun())`."""
|
||||
|
||||
# TEST 3
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test3.rs"
|
||||
name = "quiz3"
|
||||
path = "exercises/quiz3.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# MODULES
|
||||
|
||||
[[exercises]]
|
||||
name = "modules1"
|
||||
path = "exercises/modules/modules1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Everything is private in Rust by default-- but there's a keyword we can use
|
||||
to make something public! The compiler error should point to the thing that
|
||||
needs to be public."""
|
||||
|
||||
[[exercises]]
|
||||
name = "modules2"
|
||||
path = "exercises/modules/modules2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
The delicious_snacks module is trying to present an external
|
||||
interface (the `fruit` and `veggie` constants) that is different than
|
||||
its internal structure (the `fruits` and `veggies` modules and
|
||||
associated constants). It's almost there except for one keyword missing for
|
||||
each constant."""
|
||||
|
||||
# MACROS
|
||||
|
||||
[[exercises]]
|
||||
name = "macros1"
|
||||
path = "exercises/macros/macros1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
When you call a macro, you need to add something special compared to a
|
||||
regular function call. If you're stuck, take a look at what's inside
|
||||
`my_macro`."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros2"
|
||||
path = "exercises/macros/macros2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Macros don't quite play by the same rules as the rest of Rust, in terms of
|
||||
what's available where.
|
||||
|
||||
Unlike other things in Rust, the order of "where you define a macro" versus
|
||||
"where you use it" actually matters."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros3"
|
||||
path = "exercises/macros/macros3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
In order to use a macro outside of its module, you need to do something
|
||||
special to the module to lift the macro out into its parent.
|
||||
|
||||
The same trick also works on "extern crate" statements for crates that have
|
||||
exported macros, if you've seen any of those around."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros4"
|
||||
path = "exercises/macros/macros4.rs"
|
||||
mode = "compile"
|
||||
|
||||
hint = """
|
||||
You only need to add a single character to make this compile.
|
||||
The way macros are written, it wants to see something between each
|
||||
"macro arm", so it can separate them."""
|
||||
# TEST 4
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test4.rs"
|
||||
mode = "compile"
|
||||
name = "quiz4"
|
||||
path = "exercises/quiz4.rs"
|
||||
mode = "test"
|
||||
hint = "No hints this time ;)"
|
||||
|
||||
# MOVE SEMANTICS
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics1"
|
||||
path = "exercises/move_semantics/move_semantics1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
So you've got the "cannot borrow immutable local variable `vec1` as mutable" error on line 13,
|
||||
right? The fix for this is going to be adding one keyword, and the addition is NOT on line 13
|
||||
where the error is."""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics2"
|
||||
path = "exercises/move_semantics/move_semantics2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
So `vec0` is being *moved* into the function `fill_vec` when we call it on
|
||||
line 10, which means it gets dropped at the end of `fill_vec`, which means we
|
||||
can't use `vec0` again on line 13 (or anywhere else in `main` after the
|
||||
`fill_vec` call for that matter). We could fix this in a few ways, try them
|
||||
all!
|
||||
1. Make another, separate version of the data that's in `vec0` and pass that
|
||||
to `fill_vec` instead.
|
||||
2. Make `fill_vec` borrow its argument instead of taking ownership of it,
|
||||
and then copy the data within the function in order to return an owned
|
||||
`Vec<i32>`
|
||||
3. Make `fill_vec` *mutably* borrow its argument (which will need to be
|
||||
mutable), modify it directly, then not return anything. Then you can get rid
|
||||
of `vec1` entirely -- note that this will change what gets printed by the
|
||||
first `println!`"""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics3"
|
||||
path = "exercises/move_semantics/move_semantics3.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
The difference between this one and the previous ones is that the first line
|
||||
of `fn fill_vec` that had `let mut vec = vec;` is no longer there. You can,
|
||||
instead of adding that line back, add `mut` in one place that will change
|
||||
an existing binding to be a mutable binding instead of an immutable one :)"""
|
||||
|
||||
[[exercises]]
|
||||
name = "move_semantics4"
|
||||
path = "exercises/move_semantics/move_semantics4.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Stop reading whenever you feel like you have enough direction :) Or try
|
||||
doing one step and then fixing the compiler errors that result!
|
||||
So the end goal is to:
|
||||
- get rid of the first line in main that creates the new vector
|
||||
- so then `vec0` doesn't exist, so we can't pass it to `fill_vec`
|
||||
- we don't want to pass anything to `fill_vec`, so its signature should
|
||||
reflect that it does not take any arguments
|
||||
- since we're not creating a new vec in `main` anymore, we need to create
|
||||
a new vec in `fill_vec`, similarly to the way we did in `main`"""
|
||||
|
||||
# ERROR HANDLING
|
||||
|
||||
[[exercises]]
|
||||
name = "errors1"
|
||||
path = "exercises/error_handling/errors1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
`Err` is one of the variants of `Result`, so what the 2nd test is saying
|
||||
is that `generate_nametag_text` should return a `Result` instead of an
|
||||
`Option`.
|
||||
|
||||
To make this change, you'll need to:
|
||||
- update the return type in the function signature to be a Result<String, String> that
|
||||
could be the variants `Ok(String)` and `Err(String)`
|
||||
- change the body of the function to return `Ok(stuff)` where it currently
|
||||
returns `Some(stuff)`
|
||||
- change the body of the function to return `Err(error message)` where it
|
||||
currently returns `None`
|
||||
- change the first test to expect `Ok(stuff)` where it currently expects
|
||||
`Some(stuff)`."""
|
||||
|
||||
[[exercises]]
|
||||
name = "errors2"
|
||||
path = "exercises/error_handling/errors2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
One way to handle this is using a `match` statement on
|
||||
`item_quantity.parse::<i32>()` where the cases are `Ok(something)` and
|
||||
`Err(something)`. This pattern is very common in Rust, though, so there's
|
||||
a `?` operator that does pretty much what you would make that match statement
|
||||
do for you! Take a look at this section of the Error Handling chapter:
|
||||
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
and give it a try!"""
|
||||
|
||||
[[exercises]]
|
||||
name = "errors3"
|
||||
path = "exercises/error_handling/errors3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
If other functions can return a `Result`, why shouldn't `main`?"""
|
||||
|
||||
[[exercises]]
|
||||
name = "errorsn"
|
||||
path = "exercises/error_handling/errorsn.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
First hint: To figure out what type should go where the ??? is, take a look
|
||||
at the test helper function `test_with_str`, since it returns whatever
|
||||
`read_and_validate` returns and `test_with_str` has its signature fully
|
||||
specified.
|
||||
|
||||
|
||||
Next hint: There are three places in `read_and_validate` that we call a
|
||||
function that returns a `Result` (that is, the functions might fail).
|
||||
Apply the `?` operator on those calls so that we return immediately from
|
||||
`read_and_validate` if those function calls fail.
|
||||
|
||||
|
||||
Another hint: under the hood, the `?` operator calls `From::from`
|
||||
on the error value to convert it to a boxed trait object, a Box<dyn error::Error>,
|
||||
which is polymorphic-- that means that lots of different kinds of errors
|
||||
can be returned from the same function because all errors act the same
|
||||
since they all implement the `error::Error` trait.
|
||||
Check out this section of the book:
|
||||
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
|
||||
|
||||
Another another hint: Note that because the `?` operator returns
|
||||
the *unwrapped* value in the `Ok` case, if we want to return a `Result` from
|
||||
`read_and_validate` for *its* success case, we'll have to rewrap a value
|
||||
that we got from the return value of a `?`ed call in an `Ok`-- this will
|
||||
look like `Ok(something)`.
|
||||
|
||||
|
||||
Another another another hint: `Result`s must be "used", that is, you'll
|
||||
get a warning if you don't handle a `Result` that you get in your
|
||||
function. Read more about that in the `std::result` module docs:
|
||||
https://doc.rust-lang.org/std/result/#results-must-be-used"""
|
||||
|
||||
# OPTIONS / RESULTS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/option1.rs"
|
||||
mode = "test"
|
||||
name = "option1"
|
||||
path = "exercises/option/option1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Hint 1: Check out some functions of Option:
|
||||
is_some
|
||||
is_none
|
||||
unwrap
|
||||
|
||||
and:
|
||||
pattern matching
|
||||
|
||||
Hint 2: There are no sensible defaults for the value of an Array; the values need to be filled before use.
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "option2"
|
||||
path = "exercises/option/option2.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
check out:
|
||||
https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html
|
||||
https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html
|
||||
|
||||
Remember that Options can be stacked in if let and while let.
|
||||
For example: Some(Some(variable)) = variable2
|
||||
|
||||
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "result1"
|
||||
path = "exercises/error_handling/result1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
`PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result.
|
||||
It should be doing some checking, returning an `Err` result if those checks fail, and only
|
||||
returning an `Ok` result if those checks determine that everything is... okay :)"""
|
||||
|
||||
# CLIPPY
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy1"
|
||||
path = "exercises/clippy/clippy1.rs"
|
||||
mode = "clippy"
|
||||
hint = """
|
||||
Floating point calculations are usually imprecise, so asking if two values are exactly equal is asking for trouble"""
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy2"
|
||||
path = "exercises/clippy/clippy2.rs"
|
||||
mode = "clippy"
|
||||
hint = """
|
||||
`for` loops over Option values are more clearly expressed as an `if let`"""
|
||||
|
||||
# STANDARD LIBRARY TYPES
|
||||
|
||||
[[exercises]]
|
||||
name = "box1"
|
||||
path = "exercises/standard_library_types/box1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Step 1
|
||||
The compiler's message should help: since we cannot store the value of the actual type
|
||||
when working with recursive types, we need to store a reference (pointer) to its value.
|
||||
We should, therefore, place our `List` inside a `Box`. More details in the book here:
|
||||
https://doc.rust-lang.org/book/ch15-01-box.html#enabling-recursive-types-with-boxes
|
||||
|
||||
Step 2
|
||||
Creating an empty list should be fairly straightforward (hint: peek at the assertions).
|
||||
For a non-empty list keep in mind that we want to use our Cons "list builder".
|
||||
Although the current list is one of integers (i32), feel free to change the definition
|
||||
and try other types!
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "arc1"
|
||||
path = "exercises/standard_library_types/arc1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Make `shared_numbers` be an `Arc` from the numbers vector. Then, in order
|
||||
to avoid creating a copy of `numbers`, you'll need to create `child_numbers`
|
||||
inside the loop but still in the main thread.
|
||||
|
||||
`child_numbers` should be a clone of the Arc of the numbers instead of a
|
||||
thread-local copy of the numbers."""
|
||||
|
||||
[[exercises]]
|
||||
name = "iterators2"
|
||||
path = "exercises/standard_library_types/iterators2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Step 1
|
||||
You need to call something on `first` before it can be collected
|
||||
Currently its type is `char`. Have a look at the methods that are available on that type:
|
||||
https://doc.rust-lang.org/std/primitive.char.html
|
||||
|
||||
|
||||
Step 2
|
||||
First you'll need to turn the Vec into an iterator
|
||||
Then you'll need to apply your function unto each item in the vector
|
||||
P.s. Don't forget to collect() at the end!
|
||||
|
||||
|
||||
Step 3.
|
||||
This is very similar to the previous test. The only real change is that you will need to
|
||||
alter the type that collect is coerced into. For a bonus you could try doing this with a
|
||||
turbofish"""
|
||||
|
||||
[[exercises]]
|
||||
name = "iterators3"
|
||||
path = "exercises/standard_library_types/iterators3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Minor hint: In each of the two cases in the match in main, you can create x with either
|
||||
a 'turbofish' or by hinting the type of x to the compiler. You may try both.
|
||||
|
||||
Major hint: Have a look at the Iter trait and at the explanation of its collect function.
|
||||
Especially the part about Result is interesting."""
|
||||
|
||||
[[exercises]]
|
||||
name = "iterators4"
|
||||
path = "exercises/standard_library_types/iterators4.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
In an imperative language, you might write a for loop that updates
|
||||
a mutable variable. Or, you might write code utilizing recursion
|
||||
and a match clause. In Rust you can take another functional
|
||||
approach, computing the factorial elegantly with ranges and iterators."""
|
||||
|
||||
# TRAITS
|
||||
|
||||
[[exercises]]
|
||||
name = "traits1"
|
||||
path = "exercises/traits/traits1.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
A discussion about Traits in Rust can be found at:
|
||||
https://doc.rust-lang.org/book/ch10-02-traits.html
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "traits2"
|
||||
path = "exercises/traits/traits2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Notice how the trait takes ownership of 'self',and returns `Self'.
|
||||
Try mutating the incoming string vector.
|
||||
|
||||
Vectors provide suitable methods for adding an element at the end. See
|
||||
the documentation at: https://doc.rust-lang.org/std/vec/struct.Vec.html"""
|
||||
|
||||
# Generics
|
||||
|
||||
[[exercises]]
|
||||
name = "generics1"
|
||||
path = "exercises/generics/generics1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Vectors in rust make use of generics to create dynamically sized arrays of any type.
|
||||
You need to tell the compiler what type we are pushing onto this vector."""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics2"
|
||||
path = "exercises/generics/generics2.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Currently we are wrapping only values of type 'u32'.
|
||||
Maybe we could update the explicit references to this data type somehow?
|
||||
|
||||
If you are still stuck https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-method-definitions
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "generics3"
|
||||
path = "exercises/generics/generics3.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
To find the best solution to this challenge you're going to need to think back to your
|
||||
knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;"
|
||||
|
||||
This is definitely harder than the last two exercises! You need to think about not only making the
|
||||
ReportCard struct generic, but also the correct property - you will need to change the implementation
|
||||
of the struct slightly too...you can do it!
|
||||
"""
|
||||
|
||||
# THREADS
|
||||
|
||||
[[exercises]]
|
||||
name = "threads1"
|
||||
path = "exercises/threads/threads1.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
`Arc` is an Atomic Reference Counted pointer that allows safe, shared access
|
||||
to **immutable** data. But we want to *change* the number of `jobs_completed`
|
||||
so we'll need to also use another type that will only allow one thread to
|
||||
mutate the data at a time. Take a look at this section of the book:
|
||||
https://doc.rust-lang.org/book/ch16-03-shared-state.html#atomic-reference-counting-with-arct
|
||||
and keep reading if you'd like more hints :)
|
||||
|
||||
|
||||
Do you now have an `Arc` `Mutex` `JobStatus` at the beginning of main? Like:
|
||||
`let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));`
|
||||
Similar to the code in the example in the book that happens after the text
|
||||
that says "We can use Arc<T> to fix this.". If not, give that a try! If you
|
||||
do and would like more hints, keep reading!!
|
||||
|
||||
|
||||
Make sure neither of your threads are holding onto the lock of the mutex
|
||||
while they are sleeping, since this will prevent the other thread from
|
||||
being allowed to get the lock. Locks are automatically released when
|
||||
they go out of scope.
|
||||
|
||||
Ok, so, real talk, this was actually tricky for *me* to do too. And
|
||||
I could see a lot of different problems you might run into, so at this
|
||||
point I'm not sure which one you've hit :)
|
||||
|
||||
Please open an issue if you're still running into a problem that
|
||||
these hints are not helping you with, or if you've looked at the sample
|
||||
answers and don't understand why they work and yours doesn't.
|
||||
|
||||
If you've learned from the sample solutions, I encourage you to come
|
||||
back to this exercise and try it again in a few days to reinforce
|
||||
what you've learned :)"""
|
||||
|
||||
# TYPE CONVERSIONS
|
||||
|
||||
[[exercises]]
|
||||
name = "using_as"
|
||||
path = "exercises/conversions/using_as.rs"
|
||||
mode = "compile"
|
||||
hint = """
|
||||
Use the `as` operator to cast one of the operands in the last line of the
|
||||
`average` function into the expected return type."""
|
||||
|
||||
[[exercises]]
|
||||
name = "from_into"
|
||||
path = "exercises/conversions/from_into.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Follow the steps provided right before the `From` implementation"""
|
||||
|
||||
[[exercises]]
|
||||
name = "try_from_into"
|
||||
path = "exercises/conversions/try_from_into.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Follow the steps provided right before the `TryFrom` implementation.
|
||||
You can also use the example at https://doc.rust-lang.org/std/convert/trait.TryFrom.html"""
|
||||
|
||||
[[exercises]]
|
||||
name = "as_ref_mut"
|
||||
path = "exercises/conversions/as_ref_mut.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
Add AsRef<str> as a trait bound to the functions."""
|
||||
|
||||
[[exercises]]
|
||||
name = "from_str"
|
||||
path = "exercises/conversions/from_str.rs"
|
||||
mode = "test"
|
||||
hint = """
|
||||
The implementation of FromStr should return an Ok with a Person object,
|
||||
or an Err with a string if the string is not valid.
|
||||
This is almost like the `try_from_into` exercise."""
|
||||
|
||||
@@ -72,6 +72,7 @@ if (!($LASTEXITCODE -eq 0)) {
|
||||
# but anyone running pwsh 5 will have to pass the argument.
|
||||
$version = Invoke-WebRequest -UseBasicParsing https://api.github.com/repos/rust-lang/rustlings/releases/latest `
|
||||
| ConvertFrom-Json | Select-Object -ExpandProperty tag_name
|
||||
|
||||
Write-Host "Checking out version $version..."
|
||||
Set-Location $path
|
||||
git checkout -q tags/$version
|
||||
@@ -82,4 +83,12 @@ if (!(Get-Command rustlings -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
|
||||
}
|
||||
|
||||
# Checking whether Clippy is installed.
|
||||
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
|
||||
$clippy = (rustup component list | Select-String "clippy" | Select-String "installed") | Out-String
|
||||
if (!$clippy) {
|
||||
Write-Host "Installing the 'cargo-clippy' executable..."
|
||||
rustup component add clippy
|
||||
}
|
||||
|
||||
Write-Host "All done! Run 'rustlings' to get started."
|
||||
|
||||
61
install.sh
61
install.sh
@@ -7,7 +7,7 @@ if [ -x "$(command -v git)" ]
|
||||
then
|
||||
echo "SUCCESS: Git is installed"
|
||||
else
|
||||
echo "WARNING: Git does not seem to be installed."
|
||||
echo "ERROR: Git does not seem to be installed."
|
||||
echo "Please download Git using your package manager or over https://git-scm.com/!"
|
||||
exit 1
|
||||
fi
|
||||
@@ -16,7 +16,7 @@ if [ -x "$(command -v rustc)" ]
|
||||
then
|
||||
echo "SUCCESS: Rust is installed"
|
||||
else
|
||||
echo "WARNING: Rust does not seem to be installed."
|
||||
echo "ERROR: Rust does not seem to be installed."
|
||||
echo "Please download Rust using https://rustup.rs!"
|
||||
exit 1
|
||||
fi
|
||||
@@ -25,11 +25,27 @@ if [ -x "$(command -v cargo)" ]
|
||||
then
|
||||
echo "SUCCESS: Cargo is installed"
|
||||
else
|
||||
echo "WARNING: Cargo does not seem to be installed."
|
||||
echo "ERROR: Cargo does not seem to be installed."
|
||||
echo "Please download Rust and Cargo using https://rustup.rs!"
|
||||
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() {
|
||||
@@ -75,7 +91,7 @@ MinRustVersion=1.31
|
||||
vercomp $RustVersion $MinRustVersion
|
||||
if [ $? -eq 2 ]
|
||||
then
|
||||
echo "WARNING: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
|
||||
echo "ERROR: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
|
||||
echo "Please update Rust with 'rustup update'"
|
||||
exit 1
|
||||
else
|
||||
@@ -86,17 +102,46 @@ 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']);")
|
||||
echo "Checking out version $Version..."
|
||||
cd $Path
|
||||
git checkout -q tags/$Version
|
||||
|
||||
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..."
|
||||
git checkout -q ${Version}
|
||||
|
||||
echo "Installing the 'rustlings' executable..."
|
||||
cargo install --force --path .
|
||||
|
||||
if ! [ -x "$(command -v rustlings)" ]
|
||||
then
|
||||
echo "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
|
||||
echo "WARNING: Please check that you have '$CargoBin' in your PATH environment variable!"
|
||||
fi
|
||||
|
||||
# Checking whether Clippy is installed.
|
||||
# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514
|
||||
Clippy=$(rustup component list | grep "clippy" | grep "installed")
|
||||
if [ -z "$Clippy" ]
|
||||
then
|
||||
echo "Installing the 'cargo-clippy' executable..."
|
||||
rustup component add clippy
|
||||
fi
|
||||
|
||||
echo "All done! Run 'rustlings' to get started."
|
||||
|
||||
276
src/exercise.rs
276
src/exercise.rs
@@ -1,20 +1,32 @@
|
||||
use regex::Regex;
|
||||
use serde::Deserialize;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fs::remove_file;
|
||||
use std::fs::{self, remove_file, File};
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, Command, Output};
|
||||
use std::process::{self, Command};
|
||||
|
||||
const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];
|
||||
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 to this process
|
||||
#[inline]
|
||||
fn temp_file() -> String {
|
||||
format!("./temp_{}", process::id())
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
// The mode of the exercise.
|
||||
#[derive(Deserialize, Copy, Clone)]
|
||||
#[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,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -22,15 +34,74 @@ pub struct ExerciseList {
|
||||
pub exercises: Vec<Exercise>,
|
||||
}
|
||||
|
||||
// A representation of a rustlings exercise.
|
||||
// This is deserialized from the accompanying info.toml file
|
||||
#[derive(Deserialize)]
|
||||
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,
|
||||
}
|
||||
|
||||
struct FileHandle;
|
||||
|
||||
impl Drop for FileHandle {
|
||||
fn drop(&mut self) {
|
||||
clean();
|
||||
}
|
||||
}
|
||||
|
||||
impl Exercise {
|
||||
pub fn compile(&self) -> Output {
|
||||
match self.mode {
|
||||
pub fn compile(&self) -> Result<CompiledExercise, ExerciseOutput> {
|
||||
let cmd = match self.mode {
|
||||
Mode::Compile => Command::new("rustc")
|
||||
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
@@ -39,18 +110,121 @@ impl Exercise {
|
||||
.args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output(),
|
||||
Mode::Clippy => {
|
||||
let cargo_toml = format!(
|
||||
r#"[package]
|
||||
name = "{}"
|
||||
version = "0.0.1"
|
||||
edition = "2018"
|
||||
[[bin]]
|
||||
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.");
|
||||
// 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 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])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output()
|
||||
.expect("Failed to run 'cargo clean'");
|
||||
Command::new("cargo")
|
||||
.args(&["clippy", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.args(&["--", "-D", "warnings"])
|
||||
.output()
|
||||
}
|
||||
}
|
||||
.expect("Failed to run 'compile' command.");
|
||||
|
||||
if cmd.status.success() {
|
||||
Ok(CompiledExercise {
|
||||
exercise: &self,
|
||||
_handle: FileHandle,
|
||||
})
|
||||
} else {
|
||||
clean();
|
||||
Err(ExerciseOutput {
|
||||
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
|
||||
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
|
||||
})
|
||||
}
|
||||
.expect("Failed to run 'compile' command.")
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Output {
|
||||
Command::new(&temp_file())
|
||||
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")
|
||||
.expect("Failed to run 'run' command");
|
||||
|
||||
let output = ExerciseOutput {
|
||||
stdout: String::from_utf8_lossy(&cmd.stdout).to_string(),
|
||||
stderr: String::from_utf8_lossy(&cmd.stderr).to_string(),
|
||||
};
|
||||
|
||||
if cmd.status.success() {
|
||||
Ok(output)
|
||||
} else {
|
||||
Err(output)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clean(&self) {
|
||||
let _ignored = remove_file(&temp_file());
|
||||
pub fn state(&self) -> State {
|
||||
let mut source_file =
|
||||
File::open(&self.path).expect("We were unable to open the exercise file!");
|
||||
|
||||
let source = {
|
||||
let mut s = String::new();
|
||||
source_file
|
||||
.read_to_string(&mut s)
|
||||
.expect("We were unable to read the exercise file!");
|
||||
s
|
||||
};
|
||||
|
||||
let re = Regex::new(I_AM_DONE_REGEX).unwrap();
|
||||
|
||||
if !re.is_match(&source) {
|
||||
return State::Done;
|
||||
}
|
||||
|
||||
let matched_line_index = source
|
||||
.lines()
|
||||
.enumerate()
|
||||
.filter_map(|(i, line)| if re.is_match(line) { Some(i) } else { None })
|
||||
.next()
|
||||
.expect("This should not happen at all");
|
||||
|
||||
let min_line = ((matched_line_index as i32) - (CONTEXT as i32)).max(0) as usize;
|
||||
let max_line = matched_line_index + CONTEXT;
|
||||
|
||||
let context = source
|
||||
.lines()
|
||||
.enumerate()
|
||||
.filter(|&(i, _)| i >= min_line && i <= max_line)
|
||||
.map(|(i, line)| ContextLine {
|
||||
line: line.to_string(),
|
||||
number: i + 1,
|
||||
important: i == matched_line_index,
|
||||
})
|
||||
.collect();
|
||||
|
||||
State::Pending(context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,20 +234,92 @@ impl Display for Exercise {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clean() {
|
||||
let _ignored = remove_file(&temp_file());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn test_clean() {
|
||||
File::create(&temp_file()).unwrap();
|
||||
let exercise = Exercise {
|
||||
path: PathBuf::from("example.rs"),
|
||||
mode: Mode::Test,
|
||||
name: String::from("example"),
|
||||
path: PathBuf::from("tests/fixture/state/pending_exercise.rs"),
|
||||
mode: Mode::Compile,
|
||||
hint: String::from(""),
|
||||
};
|
||||
exercise.clean();
|
||||
let compiled = exercise.compile().unwrap();
|
||||
drop(compiled);
|
||||
assert!(!Path::new(&temp_file()).exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pending_state() {
|
||||
let exercise = Exercise {
|
||||
name: "pending_exercise".into(),
|
||||
path: PathBuf::from("tests/fixture/state/pending_exercise.rs"),
|
||||
mode: Mode::Compile,
|
||||
hint: String::new(),
|
||||
};
|
||||
|
||||
let state = exercise.state();
|
||||
let expected = vec![
|
||||
ContextLine {
|
||||
line: "// fake_exercise".to_string(),
|
||||
number: 1,
|
||||
important: false,
|
||||
},
|
||||
ContextLine {
|
||||
line: "".to_string(),
|
||||
number: 2,
|
||||
important: false,
|
||||
},
|
||||
ContextLine {
|
||||
line: "// I AM NOT DONE".to_string(),
|
||||
number: 3,
|
||||
important: true,
|
||||
},
|
||||
ContextLine {
|
||||
line: "".to_string(),
|
||||
number: 4,
|
||||
important: false,
|
||||
},
|
||||
ContextLine {
|
||||
line: "fn main() {".to_string(),
|
||||
number: 5,
|
||||
important: false,
|
||||
},
|
||||
];
|
||||
|
||||
assert_eq!(state, State::Pending(expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finished_exercise() {
|
||||
let exercise = Exercise {
|
||||
name: "finished_exercise".into(),
|
||||
path: PathBuf::from("tests/fixture/state/finished_exercise.rs"),
|
||||
mode: Mode::Compile,
|
||||
hint: String::new(),
|
||||
};
|
||||
|
||||
assert_eq!(exercise.state(), State::Done);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exercise_with_output() {
|
||||
let exercise = Exercise {
|
||||
name: "finished_exercise".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"));
|
||||
}
|
||||
}
|
||||
|
||||
141
src/main.rs
141
src/main.rs
@@ -2,14 +2,22 @@ use crate::exercise::{Exercise, ExerciseList};
|
||||
use crate::run::run;
|
||||
use crate::verify::verify;
|
||||
use clap::{crate_version, App, Arg, SubCommand};
|
||||
use console::Emoji;
|
||||
use notify::DebouncedEvent;
|
||||
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[macro_use]
|
||||
mod ui;
|
||||
|
||||
mod exercise;
|
||||
mod run;
|
||||
mod verify;
|
||||
@@ -19,18 +27,36 @@ fn main() {
|
||||
.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"))
|
||||
.arg(
|
||||
Arg::with_name("nocapture")
|
||||
.long("nocapture")
|
||||
.help("Show outputs from the test exercises")
|
||||
)
|
||||
.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("file").required(true).index(1))
|
||||
.arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
|
||||
.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();
|
||||
|
||||
if None == matches.subcommand_name() {
|
||||
if matches.subcommand_name().is_none() {
|
||||
println!();
|
||||
println!(r#" welcome to... "#);
|
||||
println!(r#" _ _ _ "#);
|
||||
@@ -51,36 +77,62 @@ fn main() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if !rustc_exists() {
|
||||
println!("We cannot find `rustc`.");
|
||||
println!("Try running `rustc --version` to diagnose your problem.");
|
||||
println!("For instructions on how to install Rust, check the README.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let toml_str = &fs::read_to_string("info.toml").unwrap();
|
||||
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
|
||||
let verbose = matches.is_present("nocapture");
|
||||
|
||||
if let Some(ref matches) = matches.subcommand_matches("run") {
|
||||
let filename = matches.value_of("file").unwrap_or_else(|| {
|
||||
println!("Please supply a file name!");
|
||||
std::process::exit(1);
|
||||
});
|
||||
let name = matches.value_of("name").unwrap();
|
||||
|
||||
let matching_exercise = |e: &&Exercise| {
|
||||
Path::new(filename)
|
||||
.canonicalize()
|
||||
.map(|p| p.ends_with(&e.path))
|
||||
.unwrap_or(false)
|
||||
};
|
||||
let matching_exercise = |e: &&Exercise| name == e.name;
|
||||
|
||||
let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| {
|
||||
println!("No exercise found for your file name!");
|
||||
println!("No exercise found for your given name!");
|
||||
std::process::exit(1)
|
||||
});
|
||||
|
||||
run(&exercise).unwrap_or_else(|_| std::process::exit(1));
|
||||
run(&exercise, verbose).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)
|
||||
});
|
||||
|
||||
println!("{}", exercise.hint);
|
||||
}
|
||||
|
||||
if matches.subcommand_matches("verify").is_some() {
|
||||
verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
|
||||
verify(&exercises, verbose).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
if matches.subcommand_matches("watch").is_some() {
|
||||
watch(&exercises).unwrap();
|
||||
if matches.subcommand_matches("watch").is_some() && watch(&exercises, verbose).is_ok() {
|
||||
println!(
|
||||
"{emoji} All exercises completed! {emoji}",
|
||||
emoji = Emoji("🎉", "★")
|
||||
);
|
||||
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!("Before reporting an issue or contributing, please read our guidelines:");
|
||||
println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md");
|
||||
}
|
||||
|
||||
if matches.subcommand_name().is_none() {
|
||||
@@ -89,7 +141,27 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||
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");
|
||||
thread::spawn(move || loop {
|
||||
let mut input = String::new();
|
||||
match io::stdin().read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
if input.trim().eq("hint") {
|
||||
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
|
||||
println!("{}", hint);
|
||||
}
|
||||
} else {
|
||||
println!("unknown command: {}", input);
|
||||
}
|
||||
}
|
||||
Err(error) => println!("error reading command: {}", error),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -102,19 +174,30 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
|
||||
|
||||
clear_screen();
|
||||
let _ignored = verify(exercises.iter());
|
||||
|
||||
let to_owned_hint = |t: &Exercise| t.hint.to_owned();
|
||||
let failed_exercise_hint = match verify(exercises.iter(), verbose) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))),
|
||||
};
|
||||
spawn_watch_shell(&failed_exercise_hint);
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(event) => match event {
|
||||
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
|
||||
if b.extension() == Some(OsStr::new("rs")) && b.exists() {
|
||||
let filepath = b.as_path().canonicalize().unwrap();
|
||||
let exercise = exercises
|
||||
let pending_exercises = exercises
|
||||
.iter()
|
||||
.skip_while(|e| !filepath.ends_with(&e.path));
|
||||
clear_screen();
|
||||
let _ignored = verify(exercise);
|
||||
match verify(pending_exercises, verbose) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(exercise) => {
|
||||
let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap();
|
||||
*failed_exercise_hint = Some(to_owned_hint(exercise));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -123,3 +206,13 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rustc_exists() -> bool {
|
||||
Command::new("rustc")
|
||||
.args(&["--version"])
|
||||
.stdout(Stdio::null())
|
||||
.spawn()
|
||||
.and_then(|mut child| child.wait())
|
||||
.map(|status| status.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
66
src/run.rs
66
src/run.rs
@@ -1,52 +1,58 @@
|
||||
use crate::exercise::{Exercise, Mode};
|
||||
use crate::verify::test;
|
||||
use console::{style, Emoji};
|
||||
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(())
|
||||
}
|
||||
|
||||
pub fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
|
||||
// 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());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compilecmd = exercise.compile();
|
||||
let compilation_result = exercise.compile();
|
||||
let compilation = match compilation_result {
|
||||
Ok(compilation) => compilation,
|
||||
Err(output) => {
|
||||
progress_bar.finish_and_clear();
|
||||
warn!(
|
||||
"Compilation of {} failed!, Compiler error message:\n",
|
||||
exercise
|
||||
);
|
||||
println!("{}", output.stderr);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
if compilecmd.status.success() {
|
||||
let runcmd = exercise.run();
|
||||
progress_bar.finish_and_clear();
|
||||
let result = compilation.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
if runcmd.status.success() {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
let formatstr = format!("{} Successfully ran {}", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
exercise.clean();
|
||||
match result {
|
||||
Ok(output) => {
|
||||
println!("{}", output.stdout);
|
||||
success!("Successfully ran {}", exercise);
|
||||
Ok(())
|
||||
} else {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
|
||||
}
|
||||
Err(output) => {
|
||||
println!("{}", output.stdout);
|
||||
println!("{}", output.stderr);
|
||||
|
||||
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), exercise);
|
||||
println!("{}", style(formatstr).red());
|
||||
exercise.clean();
|
||||
warn!("Ran {} with errors", exercise);
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
progress_bar.finish_and_clear();
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
23
src/ui.rs
Normal file
23
src/ui.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
macro_rules! warn {
|
||||
($fmt:literal, $ex:expr) => {{
|
||||
use console::{style, Emoji};
|
||||
let formatstr = format!($fmt, $ex);
|
||||
println!(
|
||||
"{} {}",
|
||||
style(Emoji("⚠️ ", "!")).red(),
|
||||
style(formatstr).red()
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! success {
|
||||
($fmt:literal, $ex:expr) => {{
|
||||
use console::{style, Emoji};
|
||||
let formatstr = format!($fmt, $ex);
|
||||
println!(
|
||||
"{} {}",
|
||||
style(Emoji("✅", "✓")).green(),
|
||||
style(formatstr).green()
|
||||
);
|
||||
}};
|
||||
}
|
||||
214
src/verify.rs
214
src/verify.rs
@@ -1,79 +1,185 @@
|
||||
use crate::exercise::{Exercise, Mode};
|
||||
use console::{style, Emoji};
|
||||
use crate::exercise::{CompiledExercise, Exercise, Mode, State};
|
||||
use console::style;
|
||||
use indicatif::ProgressBar;
|
||||
|
||||
pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<(), ()> {
|
||||
// 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 {
|
||||
match exercise.mode {
|
||||
Mode::Test => test(&exercise)?,
|
||||
Mode::Compile => compile_only(&exercise)?,
|
||||
let compile_result = match exercise.mode {
|
||||
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) {
|
||||
return Err(exercise);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_only(exercise: &Exercise) -> Result<(), ()> {
|
||||
enum RunMode {
|
||||
Interactive,
|
||||
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 compile_output = exercise.compile();
|
||||
|
||||
let _ = compile(&exercise, &progress_bar)?;
|
||||
progress_bar.finish_and_clear();
|
||||
if compile_output.status.success() {
|
||||
let formatstr = format!("{} Successfully compiled {}!", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
|
||||
success!("Successfully compiled {}!", exercise);
|
||||
Ok(prompt_for_completion(&exercise, None))
|
||||
}
|
||||
|
||||
pub fn test(exercise: &Exercise) -> Result<(), ()> {
|
||||
// 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!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compilation = compile(&exercise, &progress_bar)?;
|
||||
|
||||
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) => {
|
||||
warn!("Ran {} with errors", exercise);
|
||||
println!("{}", output.stdout);
|
||||
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 compile_output = exercise.compile();
|
||||
if compile_output.status.success() {
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
let compilation = compile(exercise, &progress_bar)?;
|
||||
let result = compilation.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
let runcmd = exercise.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
if runcmd.status.success() {
|
||||
let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
let formatstr = format!(
|
||||
"{} Testing of {} failed! Please try again. Here's the output:",
|
||||
Emoji("⚠️ ", "!"),
|
||||
match result {
|
||||
Ok(output) => {
|
||||
if verbose {
|
||||
println!("{}", output.stdout);
|
||||
}
|
||||
success!("Successfully tested {}", &exercise);
|
||||
if let RunMode::Interactive = run_mode {
|
||||
Ok(prompt_for_completion(&exercise, None))
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
Err(output) => {
|
||||
warn!(
|
||||
"Testing of {} failed! Please try again. Here's the output:",
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
exercise.clean();
|
||||
println!("{}", output.stdout);
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
progress_bar.finish_and_clear();
|
||||
let formatstr = format!(
|
||||
"{} Compiling of {} failed! Please try again. Here's the output:",
|
||||
Emoji("⚠️ ", "!"),
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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!",
|
||||
};
|
||||
|
||||
println!();
|
||||
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!();
|
||||
for context_line in context {
|
||||
let formatted_line = if context_line.important {
|
||||
format!("{}", style(context_line.line).bold())
|
||||
} else {
|
||||
context_line.line.to_string()
|
||||
};
|
||||
|
||||
println!(
|
||||
"{:>2} {} {}",
|
||||
style(context_line.number).blue().bold(),
|
||||
style("|").blue(),
|
||||
formatted_line
|
||||
);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn separator() -> console::StyledObject<&'static str> {
|
||||
style("====================").bold()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
[[exercises]]
|
||||
name = "compFailure"
|
||||
path = "compFailure.rs"
|
||||
mode = "compile"
|
||||
hint = ""
|
||||
|
||||
[[exercises]]
|
||||
name = "testFailure"
|
||||
path = "testFailure.rs"
|
||||
mode = "test"
|
||||
mode = "test"
|
||||
hint = "Hello!"
|
||||
|
||||
5
tests/fixture/state/finished_exercise.rs
Normal file
5
tests/fixture/state/finished_exercise.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
// fake_exercise
|
||||
|
||||
fn main() {
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user