{"id":16057990,"url":"https://github.com/psfried/tokio-fizz-buzz","last_synced_at":"2025-08-19T10:24:21.588Z","repository":{"id":79497310,"uuid":"73349119","full_name":"psFried/tokio-fizz-buzz","owner":"psFried","description":"Do the FizzBuzz exercise as a simple intro to Tokio","archived":false,"fork":false,"pushed_at":"2016-11-11T02:17:44.000Z","size":6,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-05T08:15:00.462Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/psFried.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-10T05:11:08.000Z","updated_at":"2016-11-10T05:11:50.000Z","dependencies_parsed_at":"2023-03-12T08:19:43.669Z","dependency_job_id":null,"html_url":"https://github.com/psFried/tokio-fizz-buzz","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/psFried/tokio-fizz-buzz","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psFried%2Ftokio-fizz-buzz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psFried%2Ftokio-fizz-buzz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psFried%2Ftokio-fizz-buzz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psFried%2Ftokio-fizz-buzz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/psFried","download_url":"https://codeload.github.com/psFried/tokio-fizz-buzz/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/psFried%2Ftokio-fizz-buzz/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271135934,"owners_count":24705104,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-19T02:00:09.176Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-09T03:05:47.125Z","updated_at":"2025-08-19T10:24:21.541Z","avatar_url":"https://github.com/psFried.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"Async IO in Rust\n================\n\n## Foundation\n\n- **[Mio](https://github.com/carllerche/mio)**\n    - Provides abstraction over OS-specific async IO features\n    - Event loop is defined here\n- **[Futures](https://github.com/alexcrichton/futures-rs)**\n    - Abstraction over some asynchronous unit of work\n    - Allows asynchronous units of computation to be composed!\n    - Futures crate primarily contains only abstractions\n    - Different from other Futures libraries in that this crate uses a pull model\n- **[Tokio-Core](https://github.com/tokio-rs/tokio-core)**\n    - Depends on both Futures and Mio crates\n    - Provides concrete implementations of Futures for basic things\n- **[Tokio-Service](https://github.com/tokio-rs/tokio-service)**\n    - Depends on Tokio-Core\n    - Defines a Service trait that allows dealing with things in terms of Request/Response\n    - Tokio-Service only contains abstractions\n- **[Tokio-Hyper](https://github.com/tokio-rs/tokio-hyper)**\n    - Provides a Tokio Service for HTTP Request-Response\n    - Still in kind of a proof-of-concept state\n    \n## Mio\n\nMio is a fairly low-level library that abstracts over platform-specific async io primitives. This provides the basis for all of the async io in Tokio. Mio by itself is definitely lower level than you'd typically want for doing things like making http requests and stuff like that.\n    \n## Futures\n\nThe futures crate provides a few primary abstractions:\n\n- **Future**\n    - Represents some asynchronous unit of work that may complete at some point in the... future\n    - It's a monad, you can flat map that shit! This allows them to be very easily composable\n    - All basic io methods in `tokio_core::io` return `Future`s. For instance reading or writing some bytes\n    - Primary method is `fn poll(\u0026mut self) -\u003e Result\u003cAsync\u003cSelf::Item\u003e, Self::Error\u003e`\n        - `Async\u003cT\u003e` has two variants: `Ready(T)` and `NotReady`\n- **Stream**\n    - Represents an asynchronous sequential iterator of Futures\n    - `into_future` returns a Future that resolves to the next element in the Stream, plus the Stream itself\n    - `TCPListener::incoming()` returns a `Stream` of `TCPStream`s\n- **Task**\n    - WTF? See below\n    - Provides `park` and `unpark` methods. Starts to sort of be like green threads\n    \n### WTF is a Task?\n\nMost folks follow along just fine until the `Task` comes into play. This is where Rust's Futures are different from what you're probably used to. Most implementations of Futures use a 'push' model. In a push model, there is typically a callback that is invoked once the Future is resolved to a value. The 'pull' model is just the opposite. Instead of invoking a callback once the Future is completed, the Future is polled to see if it's ready yet (if not, then it will be polled again once the resources it needs are ready, thanks to Mio). When the Future is ready, then the function is invoked with the value yielded by the future. _Something_ has to do all that work polling futures and invoking callback functions. That's what the `Task` manages. Note that `Task` doesn't itself decide _when_ to unpark itself and poll the future, that's where Mio will end up being useful. \n\n## Tokio\n\nHere's where things start getting a lot more usable. Think of Tokio as something that adapts the Futures abstractions to work with Mio to make it much easier to use. Things like network streams are now just represented as Futures, and so are operations like reading and writing to them.\n\n### Hello World, Explained\n\nThis is just the hello world example from [the tokio repository](https://github.com/tokio-rs/tokio-core/blob/master/examples/hello.rs).\n\n```rust\nextern crate futures;\nextern crate tokio_core;\n\nuse futures::stream::Stream;\nuse tokio_core::reactor::Core;\nuse tokio_core::net::TcpListener;\n\nfn main() {\n    let mut core = Core::new().unwrap();\n    let address = \"127.0.0.1:8080\".parse().unwrap();\n    let listener = TcpListener::bind(\u0026address, \u0026core.handle()).unwrap();\n\n    let addr = listener.local_addr().unwrap();\n    println!(\"Listening for connections on {}\", addr);\n\n    let clients = listener.incoming();\n    let welcomes = clients.and_then(|(socket, _peer_addr)| {\n        tokio_core::io::write_all(socket, b\"Hello!\\n\")\n    });\n    let server = welcomes.for_each(|(_socket, _welcome)| {\n        Ok(())\n    });\n\n    core.run(server).unwrap();\n}\n```\n\n#### `Core`\n\nLet's go back to the `Task` that polls a `Future` to see if it's ready yet. Something needs to tell it when to poll. A naive implementation might just continuously poll the future in a loop. Mio allows us to receive an event when the underlying resource (i.e. socket) is ready, so we could wait until then to poll the future. This is `Core`s job. \n\n#### `TCPListener`\n\nNotice the `let clients = listener.incoming()` call? That returns a `Stream` of `TCPStream`s and client addresses. Tokio's `TCPListener` will automatically register with the Mio event loop, so that's all handled for you. On the next line, `clients.and_then` will invoke the given closure for each client that connects.\n\n#### `TCPStream`\n\nYou've dealt with these before. Nothing too special, except here they have methods to `poll` the stream and register it in the Mio event loop if the stream isn't ready yet. Implements both `Read` and `Write`. Notice the call to `tokio_core::io::write_all(socket, b\"Hello!\\n\")`, which returns a `Future` representing the completion of the write.\n\n#### Actually making things happen\n\nRemember when we said that Rust's Futures used a 'pull' model. Well, these things aren't just going to execute themselves. First off, there's the call to `welcomes.for_each`. This is going to continuously poll for the next item in the stream so that we keep accepting new client connections. Like their second cousins, `Iterator`s, `Stream`s are lazy. So, something needs to keep asking for the next item. `for_each` returns another `Future` whose output is `()`. If the closure passed to `for_each` ever returns an error result, then iteration is immediately stopped. This provides a way to short circuit streams.\n\nLastly, there's the call to `core.run(server)`. Well, all it does is just to run that one future and keep polling it until it's done.\n\n\n\n# Tokio FizzBuzz kata\n\nThis is a bit of a twist on the normal FuzzBuzz. We're going to use Tokio to implement a simple FizzBuzz server.\n\nThe protocol is _really_ simple:\n\n- Client simply sends a number as a string, using only the characters 0-9.\n- Server responds with a single line of text:\n    - 'Fizz' if the number is divisible by 3\n    - 'Buzz' if the number is divisible by 5\n    - 'FizzBuzz' if the number is divisible by both 3 and 5\n    - If the number is not divisible by either 3 or 5, then the server responds with the number\n- Bonus points if you use a Tokio client to test drive your FizzBuzz server\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsfried%2Ftokio-fizz-buzz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpsfried%2Ftokio-fizz-buzz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpsfried%2Ftokio-fizz-buzz/lists"}