1// the Event type is an enum, where its variants can carry data
2enum Event {
3 // carries no data
4 Connected,
5 // carries one field
6 Message(String),
7 // carries multiple fields
8 FileUpload { filename: String, size_bytes: usize },
9 // carry an enum inside another enum
10 Error(ErrorKind),
11}
12
13enum ErrorKind {
14 Network(String),
15 Server(u16),
16}
17
18// function for the server to handle an event
19fn handle(event: Event) {
20 // we are basically pattern matching on the 'event' parameter
21 // we know it's of type Event, meaning we check all the possible
22 // variants of Event, and handle them accordingly. The match also
23 // MUST be exhaustive, if we don't explicitly handle every POSSIBLE
24 // variant of Event, it's illegal and the code won't compile.
25
26 // in other words, 'match event' is saying:
27 // here's the 'event' variable, please check it against all these patterns,
28 // and whichever pattern it matches, we'll evaluate that code
29 match event {
30 // simplest because Connected doesn't have data attached
31 // so we can just run some code and move on
32 Event::Connected => println!("User connected!"),
33 // we can access the attached data and do stuff with it
34 // btw the variable names (text, filename, etc) can be anything,
35 // since they're only bound within these blocks
36 Event::Message(text) => println!("Broadcast: {}", text),
37 Event::FileUpload { filename, bytes } => {
38 println!("Receiving file {}", filename);
39 store_file(filename, bytes);
40 }
41 // since Error holds ANOTHER enum, we can match on ITS variants too
42 // enums within enums within enums is a common pattern actually, and because
43 // the compiler errors if we don't handle EVERY variant in EVERY match block,
44 // it's a great way of doing this kind of branching logic safely
45 Event::Error(kind) => match kind {
46 ErrorKind::Network(msg) => eprintln!("Network error: {}", msg),
47 ErrorKind::Server(code) => eprintln!("Server error code {}", code),
48 },
49 }
50}