diff --git a/solutions/go/02-ping-pong/code/README.md b/solutions/go/02-ping-pong/code/README.md deleted file mode 100644 index bc674ece..00000000 --- a/solutions/go/02-ping-pong/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Go solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/server.go`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `go (1.19)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/server.go`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/go/02-ping-pong/code/app/server.go b/solutions/go/02-ping-pong/code/app/server.go deleted file mode 100644 index 59812b30..00000000 --- a/solutions/go/02-ping-pong/code/app/server.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "fmt" - "net" - "os" -) - -func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - defer conn.Close() - - buf := make([]byte, 1024) - - if _, err := conn.Read(buf); err != nil { - fmt.Println("error reading from client: ", err.Error()) - os.Exit(1) - } - - // Let's ignore the client's input for now and hardcode a response. - // We'll implement a proper Redis Protocol parser in later stages. - conn.Write([]byte("+PONG\r\n")) -} diff --git a/solutions/go/02-ping-pong/code/codecrafters.yml b/solutions/go/02-ping-pong/code/codecrafters.yml deleted file mode 100644 index b94dbc95..00000000 --- a/solutions/go/02-ping-pong/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Go version used to run your code -# on Codecrafters. -# -# Available versions: go-1.19 -language_pack: go-1.19 diff --git a/solutions/go/02-ping-pong/code/spawn_redis_server.sh b/solutions/go/02-ping-pong/code/spawn_redis_server.sh deleted file mode 100755 index 2c7df9d9..00000000 --- a/solutions/go/02-ping-pong/code/spawn_redis_server.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -set -e -tmpFile=$(mktemp) -go build -o "$tmpFile" app/*.go -exec "$tmpFile" diff --git a/solutions/go/02-ping-pong/definition.yml b/solutions/go/02-ping-pong/definition.yml deleted file mode 100644 index 75b6ff80..00000000 --- a/solutions/go/02-ping-pong/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -reviewers_details: -- name: Marcos Lilljedahl - profile_url: https://twitter.com/marcosnils - avatar_url: https://github.com/marcosnils.png - headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/15 diff --git a/solutions/go/02-ping-pong/diff/app/server.go.diff b/solutions/go/02-ping-pong/diff/app/server.go.diff deleted file mode 100644 index 25a19b38..00000000 --- a/solutions/go/02-ping-pong/diff/app/server.go.diff +++ /dev/null @@ -1,36 +0,0 @@ -@@ -1,20 +1,34 @@ - package main - - import ( - "fmt" - "net" - "os" - ) - - func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } -- _, err = l.Accept() -+ -+ conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } -+ -+ defer conn.Close() -+ -+ buf := make([]byte, 1024) -+ -+ if _, err := conn.Read(buf); err != nil { -+ fmt.Println("error reading from client: ", err.Error()) -+ os.Exit(1) -+ } -+ -+ // Let's ignore the client's input for now and hardcode a response. -+ // We'll implement a proper Redis Protocol parser in later stages. -+ conn.Write([]byte("+PONG\r\n")) - } diff --git a/solutions/go/02-ping-pong/explanation.md b/solutions/go/02-ping-pong/explanation.md deleted file mode 100644 index 74103494..00000000 --- a/solutions/go/02-ping-pong/explanation.md +++ /dev/null @@ -1,27 +0,0 @@ -Stage 2 is an exercise in reading and responding to requests with `net`. The official documentation [is here](https://pkg.go.dev/net). - -In the first stage, we were simply accepting a connection (`_`), but weren't doing anything with it. - -```go -_, err = l.Accept() -``` - -As we go further, we want to actually parse the incoming request, and respond suitably. Since we know that the -client only sends us `PING` at the moment, we can hardcode our response. - -First, we store the connection into a variable so we can read its value. - -```go -conn, err := l.Accept() -``` - -For this stage, we know that the tester _only_ sends us `PING`, so we don't have to parse the incoming data. - -As mentioned in the stage instructions, we need to encode the response as a -[RESP Simple String](https://redis.io/docs/reference/protocol-spec/#resp-simple-strings). The ideal approach is to -create a RESP encoder function — but for now, since we know that our response will always be `PONG`, we can hardcode -the response. We will create the function in the upcoming stages. - -```go -conn.Write([]byte("+PONG\r\n")) -``` diff --git a/solutions/go/03-ping-pong-multiple/code/README.md b/solutions/go/03-ping-pong-multiple/code/README.md deleted file mode 100644 index bc674ece..00000000 --- a/solutions/go/03-ping-pong-multiple/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Go solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/server.go`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `go (1.19)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/server.go`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/go/03-ping-pong-multiple/code/app/server.go b/solutions/go/03-ping-pong-multiple/code/app/server.go deleted file mode 100644 index 0eb89168..00000000 --- a/solutions/go/03-ping-pong-multiple/code/app/server.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net" - "os" -) - -func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - defer conn.Close() - - for { - buf := make([]byte, 1024) - - _, err := conn.Read(buf) - if err == io.EOF { - break - } - if err != nil { - fmt.Println("error reading from client: ", err.Error()) - os.Exit(1) - } - - // Let's ignore the client's input for now and hardcode a response. - // We'll implement a proper Redis Protocol parser in later stages. - conn.Write([]byte("+PONG\r\n")) - } -} diff --git a/solutions/go/03-ping-pong-multiple/code/codecrafters.yml b/solutions/go/03-ping-pong-multiple/code/codecrafters.yml deleted file mode 100644 index b94dbc95..00000000 --- a/solutions/go/03-ping-pong-multiple/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Go version used to run your code -# on Codecrafters. -# -# Available versions: go-1.19 -language_pack: go-1.19 diff --git a/solutions/go/03-ping-pong-multiple/code/spawn_redis_server.sh b/solutions/go/03-ping-pong-multiple/code/spawn_redis_server.sh deleted file mode 100755 index 2c7df9d9..00000000 --- a/solutions/go/03-ping-pong-multiple/code/spawn_redis_server.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -set -e -tmpFile=$(mktemp) -go build -o "$tmpFile" app/*.go -exec "$tmpFile" diff --git a/solutions/go/03-ping-pong-multiple/definition.yml b/solutions/go/03-ping-pong-multiple/definition.yml deleted file mode 100644 index 9d4826a6..00000000 --- a/solutions/go/03-ping-pong-multiple/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/16 diff --git a/solutions/go/03-ping-pong-multiple/diff/app/server.go.diff b/solutions/go/03-ping-pong-multiple/diff/app/server.go.diff deleted file mode 100644 index 61113bce..00000000 --- a/solutions/go/03-ping-pong-multiple/diff/app/server.go.diff +++ /dev/null @@ -1,50 +0,0 @@ -@@ -1,34 +1,41 @@ - package main - - import ( - "fmt" -+ "io" - "net" - "os" - ) - - func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - defer conn.Close() - -- buf := make([]byte, 1024) -+ for { -+ buf := make([]byte, 1024) - -- if _, err := conn.Read(buf); err != nil { -- fmt.Println("error reading from client: ", err.Error()) -- os.Exit(1) -+ _, err := conn.Read(buf) -+ if err == io.EOF { -+ break -+ } -+ if err != nil { -+ fmt.Println("error reading from client: ", err.Error()) -+ os.Exit(1) -+ } -+ -+ // Let's ignore the client's input for now and hardcode a response. -+ // We'll implement a proper Redis Protocol parser in later stages. -+ conn.Write([]byte("+PONG\r\n")) - } -- -- // Let's ignore the client's input for now and hardcode a response. -- // We'll implement a proper Redis Protocol parser in later stages. -- conn.Write([]byte("+PONG\r\n")) - } diff --git a/solutions/go/03-ping-pong-multiple/explanation.md b/solutions/go/03-ping-pong-multiple/explanation.md deleted file mode 100644 index 12386ff6..00000000 --- a/solutions/go/03-ping-pong-multiple/explanation.md +++ /dev/null @@ -1,29 +0,0 @@ -Stage 3 builds on our progress from Stage 2. - -Earlier, we were anticipating a single `PING` request, and were accordingly responding back with a single `PONG`. - -As an improvement, we'll now monitor for more incoming requests — and each time we get one, we'll respond back with -`PONG`, and go back to waiting for the next one. We can achieve this with a `for` loop. - -```go -for { - buf := make([]byte, 1024) - - if _, err := conn.Read(buf); err != nil { - if err == io.EOF { - break - } else { - fmt.Println("error reading from client: ", err.Error()) - os.Exit(1) - } - } - - // Let's ignore the client's input for now and hardcode a response. - // We'll implement a proper Redis Protocol parser in later stages. - conn.Write([]byte("+PONG\r\n")) -} -``` - -While this approach gets us through the stage, notice how our program is now blocked on the for loop as it waits -for incoming requests. During this time, the program cannot do anything else (including accepting connections from -other clients). We'll get around that in the next stage when we tackle concurrent requests. diff --git a/solutions/go/04-concurrent-clients/code/README.md b/solutions/go/04-concurrent-clients/code/README.md deleted file mode 100644 index bc674ece..00000000 --- a/solutions/go/04-concurrent-clients/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Go solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/server.go`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `go (1.19)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/server.go`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/go/04-concurrent-clients/code/app/server.go b/solutions/go/04-concurrent-clients/code/app/server.go deleted file mode 100644 index cd217d77..00000000 --- a/solutions/go/04-concurrent-clients/code/app/server.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net" - "os" -) - -func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - for { - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - go handleConnection(conn) - } -} - -func handleConnection(conn net.Conn) { - defer conn.Close() - - for { - buf := make([]byte, 1024) - - _, err := conn.Read(buf) - if err == io.EOF { - break - } - if err != nil { - fmt.Println("error reading from client: ", err.Error()) - os.Exit(1) - } - - // Let's ignore the client's input for now and hardcode a response. - // We'll implement a proper Redis Protocol parser in later stages. - conn.Write([]byte("+PONG\r\n")) - } -} diff --git a/solutions/go/04-concurrent-clients/code/codecrafters.yml b/solutions/go/04-concurrent-clients/code/codecrafters.yml deleted file mode 100644 index b94dbc95..00000000 --- a/solutions/go/04-concurrent-clients/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Go version used to run your code -# on Codecrafters. -# -# Available versions: go-1.19 -language_pack: go-1.19 diff --git a/solutions/go/04-concurrent-clients/code/spawn_redis_server.sh b/solutions/go/04-concurrent-clients/code/spawn_redis_server.sh deleted file mode 100755 index 2c7df9d9..00000000 --- a/solutions/go/04-concurrent-clients/code/spawn_redis_server.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -set -e -tmpFile=$(mktemp) -go build -o "$tmpFile" app/*.go -exec "$tmpFile" diff --git a/solutions/go/04-concurrent-clients/definition.yml b/solutions/go/04-concurrent-clients/definition.yml deleted file mode 100644 index 46060297..00000000 --- a/solutions/go/04-concurrent-clients/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/11 diff --git a/solutions/go/04-concurrent-clients/diff/app/server.go.diff b/solutions/go/04-concurrent-clients/diff/app/server.go.diff deleted file mode 100644 index ceccfcd7..00000000 --- a/solutions/go/04-concurrent-clients/diff/app/server.go.diff +++ /dev/null @@ -1,52 +0,0 @@ -@@ -1,41 +1,47 @@ - package main - - import ( - "fmt" - "io" - "net" - "os" - ) - - func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - -- conn, err := l.Accept() -- if err != nil { -- fmt.Println("Error accepting connection: ", err.Error()) -- os.Exit(1) -+ for { -+ conn, err := l.Accept() -+ if err != nil { -+ fmt.Println("Error accepting connection: ", err.Error()) -+ os.Exit(1) -+ } -+ -+ go handleConnection(conn) - } -+} - -+func handleConnection(conn net.Conn) { - defer conn.Close() - - for { - buf := make([]byte, 1024) - - _, err := conn.Read(buf) - if err == io.EOF { - break - } - if err != nil { - fmt.Println("error reading from client: ", err.Error()) - os.Exit(1) - } - - // Let's ignore the client's input for now and hardcode a response. - // We'll implement a proper Redis Protocol parser in later stages. - conn.Write([]byte("+PONG\r\n")) - } - } diff --git a/solutions/go/04-concurrent-clients/explanation.md b/solutions/go/04-concurrent-clients/explanation.md deleted file mode 100644 index ec66f850..00000000 --- a/solutions/go/04-concurrent-clients/explanation.md +++ /dev/null @@ -1,46 +0,0 @@ -Stage 4 is an entry into Goroutines. To get a primer, [read here](https://gobyexample.com/goroutines). - -We're now going to respond to `PING` requests from multiple clients, concurrently. - -Let's start by moving our responder into its own function. It needs a connection object as argument. - -```go -func handleConnection(conn net.Conn) { - defer conn.Close() - - for { - buf := make([]byte, 1024) - - if _, err := conn.Read(buf); err != nil { - if err == io.EOF { - break - } else { - fmt.Println("error reading from client: ", err.Error()) - os.Exit(1) - } - } - - // Let's ignore the client's input for now and hardcode a response. - // We'll implement a proper Redis Protocol parser in later stages. - conn.Write([]byte("+PONG\r\n")) - } -} -``` - -Within `main`, we'll now use a `for` to accept multiple connections. For each client connection that we accept, we'll -spawn a goroutine that handles the connection. - -Using a goroutine makes the program able to accept and handle new incoming connections in parallel, instead of -blocking the program by sequentially handling one connection at a time. - -```go -for { - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - go handleConnection(conn) -} -``` diff --git a/solutions/go/05-echo/code/README.md b/solutions/go/05-echo/code/README.md deleted file mode 100644 index bc674ece..00000000 --- a/solutions/go/05-echo/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Go solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/server.go`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `go (1.19)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/server.go`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/go/05-echo/code/app/redis_protocol.go b/solutions/go/05-echo/code/app/redis_protocol.go deleted file mode 100644 index 78ba02e6..00000000 --- a/solutions/go/05-echo/code/app/redis_protocol.go +++ /dev/null @@ -1,146 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "io" - "strconv" -) - -// Type represents a Value type -type Type byte - -const ( - SimpleString Type = '+' - BulkString Type = '$' - Array Type = '*' -) - -// Value represents the data of a valid RESP type. -type Value struct { - typ Type - bytes []byte - array []Value -} - -// String converts Value to a string. -// -// If Value cannot be converted, an empty string is returned. -func (v Value) String() string { - if v.typ == BulkString || v.typ == SimpleString { - return string(v.bytes) - } - - return "" -} - -// Array converts Value to an array. -// -// If Value cannot be converted, an empty array is returned. -func (v Value) Array() []Value { - if v.typ == Array { - return v.array - } - - return []Value{} -} - -// DecodeRESP parses a RESP message and returns a RedisValue -func DecodeRESP(byteStream *bufio.Reader) (Value, error) { - dataTypeByte, err := byteStream.ReadByte() - if err != nil { - return Value{}, err - } - - switch string(dataTypeByte) { - case "+": - return decodeSimpleString(byteStream) - case "$": - return decodeBulkString(byteStream) - case "*": - return decodeArray(byteStream) - } - - return Value{}, fmt.Errorf("invalid RESP data type byte: %s", string(dataTypeByte)) -} - -func decodeSimpleString(byteStream *bufio.Reader) (Value, error) { - readBytes, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, err - } - - return Value{ - typ: SimpleString, - bytes: readBytes, - }, nil -} - -func decodeBulkString(byteStream *bufio.Reader) (Value, error) { - readBytesForCount, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, fmt.Errorf("failed to read bulk string length: %s", err) - } - - count, err := strconv.Atoi(string(readBytesForCount)) - if err != nil { - return Value{}, fmt.Errorf("failed to parse bulk string length: %s", err) - } - - readBytes := make([]byte, count+2) - - if _, err := io.ReadFull(byteStream, readBytes); err != nil { - return Value{}, fmt.Errorf("failed to read bulk string contents: %s", err) - } - - return Value{ - typ: BulkString, - bytes: readBytes[:count], - }, nil -} - -func decodeArray(byteStream *bufio.Reader) (Value, error) { - readBytesForCount, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, fmt.Errorf("failed to read bulk string length: %s", err) - } - - count, err := strconv.Atoi(string(readBytesForCount)) - if err != nil { - return Value{}, fmt.Errorf("failed to parse bulk string length: %s", err) - } - - array := []Value{} - - for i := 1; i <= count; i++ { - value, err := DecodeRESP(byteStream) - if err != nil { - return Value{}, err - } - - array = append(array, value) - } - - return Value{ - typ: Array, - array: array, - }, nil -} - -func readUntilCRLF(byteStream *bufio.Reader) ([]byte, error) { - readBytes := []byte{} - - for { - b, err := byteStream.ReadBytes('\n') - if err != nil { - return nil, err - } - - readBytes = append(readBytes, b...) - if len(readBytes) >= 2 && readBytes[len(readBytes)-2] == '\r' { - break - } - } - - return readBytes[:len(readBytes)-2], nil -} diff --git a/solutions/go/05-echo/code/app/redis_protocol_test.go b/solutions/go/05-echo/code/app/redis_protocol_test.go deleted file mode 100644 index 0121ff74..00000000 --- a/solutions/go/05-echo/code/app/redis_protocol_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "testing" -) - -func TestDecodeSimpleString(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("+foo\r\n"))) - - if err != nil { - t.Errorf("error decoding simple string: %s", err) - } - - if value.typ != SimpleString { - t.Errorf("expected SimpleString, got %v", value.typ) - } - - if value.String() != "foo" { - t.Errorf("expected 'foo', got '%s'", value.String()) - } -} - -func TestDecodeBulkString(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("$4\r\nabcd\r\n"))) - - if err != nil { - t.Errorf("error decoding bulk string: %s", err) - } - - if value.typ != BulkString { - t.Errorf("expected BulkString, got %v", value.typ) - } - - if value.String() != "abcd" { - t.Errorf("expected 'abcd', got '%s'", value.String()) - } -} - -func TestDecodeBulkStringArray(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("*2\r\n$3\r\nGET\r\n$4\r\nthis\r\n"))) - - if err != nil { - t.Errorf("error decoding array: %s", err) - } - - if value.typ != Array { - t.Errorf("expected Array, got %v", value.typ) - } - - if value.Array()[0].String() != "GET" { - t.Errorf("expected 'GET', got '%s'", value.Array()[0].String()) - } - - if value.Array()[1].String() != "this" { - t.Errorf("expected 'this', got '%s'", value.Array()[1].String()) - } -} diff --git a/solutions/go/05-echo/code/app/server.go b/solutions/go/05-echo/code/app/server.go deleted file mode 100644 index 28d172fa..00000000 --- a/solutions/go/05-echo/code/app/server.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "bufio" - "errors" - "fmt" - "io" - "net" - "os" -) - -func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - for { - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - go handleConnection(conn) - } -} - -func handleConnection(conn net.Conn) { - defer conn.Close() - - for { - value, err := DecodeRESP(bufio.NewReader(conn)) - if errors.Is(err, io.EOF) { - break - } - if err != nil { - fmt.Println("Error decoding RESP: ", err.Error()) - return // Ignore clients that we fail to read from - } - - command := value.Array()[0].String() - args := value.Array()[1:] - - switch command { - case "ping": - conn.Write([]byte("+PONG\r\n")) - case "echo": - conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(args[0].String()), args[0].String()))) - default: - conn.Write([]byte("-ERR unknown command '" + command + "'\r\n")) - } - } -} diff --git a/solutions/go/05-echo/code/codecrafters.yml b/solutions/go/05-echo/code/codecrafters.yml deleted file mode 100644 index b94dbc95..00000000 --- a/solutions/go/05-echo/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Go version used to run your code -# on Codecrafters. -# -# Available versions: go-1.19 -language_pack: go-1.19 diff --git a/solutions/go/05-echo/code/spawn_redis_server.sh b/solutions/go/05-echo/code/spawn_redis_server.sh deleted file mode 100755 index 2c7df9d9..00000000 --- a/solutions/go/05-echo/code/spawn_redis_server.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -set -e -tmpFile=$(mktemp) -go build -o "$tmpFile" app/*.go -exec "$tmpFile" diff --git a/solutions/go/05-echo/definition.yml b/solutions/go/05-echo/definition.yml deleted file mode 100644 index 2c61d13c..00000000 --- a/solutions/go/05-echo/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/12 diff --git a/solutions/go/05-echo/diff/app/redis_protocol.go.diff b/solutions/go/05-echo/diff/app/redis_protocol.go.diff deleted file mode 100644 index 5aa741ba..00000000 --- a/solutions/go/05-echo/diff/app/redis_protocol.go.diff +++ /dev/null @@ -1,147 +0,0 @@ -@@ -0,0 +1,146 @@ -+package main -+ -+import ( -+ "bufio" -+ "fmt" -+ "io" -+ "strconv" -+) -+ -+// Type represents a Value type -+type Type byte -+ -+const ( -+ SimpleString Type = '+' -+ BulkString Type = '$' -+ Array Type = '*' -+) -+ -+// Value represents the data of a valid RESP type. -+type Value struct { -+ typ Type -+ bytes []byte -+ array []Value -+} -+ -+// String converts Value to a string. -+// -+// If Value cannot be converted, an empty string is returned. -+func (v Value) String() string { -+ if v.typ == BulkString || v.typ == SimpleString { -+ return string(v.bytes) -+ } -+ -+ return "" -+} -+ -+// Array converts Value to an array. -+// -+// If Value cannot be converted, an empty array is returned. -+func (v Value) Array() []Value { -+ if v.typ == Array { -+ return v.array -+ } -+ -+ return []Value{} -+} -+ -+// DecodeRESP parses a RESP message and returns a RedisValue -+func DecodeRESP(byteStream *bufio.Reader) (Value, error) { -+ dataTypeByte, err := byteStream.ReadByte() -+ if err != nil { -+ return Value{}, err -+ } -+ -+ switch string(dataTypeByte) { -+ case "+": -+ return decodeSimpleString(byteStream) -+ case "$": -+ return decodeBulkString(byteStream) -+ case "*": -+ return decodeArray(byteStream) -+ } -+ -+ return Value{}, fmt.Errorf("invalid RESP data type byte: %s", string(dataTypeByte)) -+} -+ -+func decodeSimpleString(byteStream *bufio.Reader) (Value, error) { -+ readBytes, err := readUntilCRLF(byteStream) -+ if err != nil { -+ return Value{}, err -+ } -+ -+ return Value{ -+ typ: SimpleString, -+ bytes: readBytes, -+ }, nil -+} -+ -+func decodeBulkString(byteStream *bufio.Reader) (Value, error) { -+ readBytesForCount, err := readUntilCRLF(byteStream) -+ if err != nil { -+ return Value{}, fmt.Errorf("failed to read bulk string length: %s", err) -+ } -+ -+ count, err := strconv.Atoi(string(readBytesForCount)) -+ if err != nil { -+ return Value{}, fmt.Errorf("failed to parse bulk string length: %s", err) -+ } -+ -+ readBytes := make([]byte, count+2) -+ -+ if _, err := io.ReadFull(byteStream, readBytes); err != nil { -+ return Value{}, fmt.Errorf("failed to read bulk string contents: %s", err) -+ } -+ -+ return Value{ -+ typ: BulkString, -+ bytes: readBytes[:count], -+ }, nil -+} -+ -+func decodeArray(byteStream *bufio.Reader) (Value, error) { -+ readBytesForCount, err := readUntilCRLF(byteStream) -+ if err != nil { -+ return Value{}, fmt.Errorf("failed to read bulk string length: %s", err) -+ } -+ -+ count, err := strconv.Atoi(string(readBytesForCount)) -+ if err != nil { -+ return Value{}, fmt.Errorf("failed to parse bulk string length: %s", err) -+ } -+ -+ array := []Value{} -+ -+ for i := 1; i <= count; i++ { -+ value, err := DecodeRESP(byteStream) -+ if err != nil { -+ return Value{}, err -+ } -+ -+ array = append(array, value) -+ } -+ -+ return Value{ -+ typ: Array, -+ array: array, -+ }, nil -+} -+ -+func readUntilCRLF(byteStream *bufio.Reader) ([]byte, error) { -+ readBytes := []byte{} -+ -+ for { -+ b, err := byteStream.ReadBytes('\n') -+ if err != nil { -+ return nil, err -+ } -+ -+ readBytes = append(readBytes, b...) -+ if len(readBytes) >= 2 && readBytes[len(readBytes)-2] == '\r' { -+ break -+ } -+ } -+ -+ return readBytes[:len(readBytes)-2], nil -+} diff --git a/solutions/go/05-echo/diff/app/redis_protocol_test.go.diff b/solutions/go/05-echo/diff/app/redis_protocol_test.go.diff deleted file mode 100644 index 4dc5731a..00000000 --- a/solutions/go/05-echo/diff/app/redis_protocol_test.go.diff +++ /dev/null @@ -1,60 +0,0 @@ -@@ -0,0 +1,59 @@ -+package main -+ -+import ( -+ "bufio" -+ "bytes" -+ "testing" -+) -+ -+func TestDecodeSimpleString(t *testing.T) { -+ value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("+foo\r\n"))) -+ -+ if err != nil { -+ t.Errorf("error decoding simple string: %s", err) -+ } -+ -+ if value.typ != SimpleString { -+ t.Errorf("expected SimpleString, got %v", value.typ) -+ } -+ -+ if value.String() != "foo" { -+ t.Errorf("expected 'foo', got '%s'", value.String()) -+ } -+} -+ -+func TestDecodeBulkString(t *testing.T) { -+ value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("$4\r\nabcd\r\n"))) -+ -+ if err != nil { -+ t.Errorf("error decoding bulk string: %s", err) -+ } -+ -+ if value.typ != BulkString { -+ t.Errorf("expected BulkString, got %v", value.typ) -+ } -+ -+ if value.String() != "abcd" { -+ t.Errorf("expected 'abcd', got '%s'", value.String()) -+ } -+} -+ -+func TestDecodeBulkStringArray(t *testing.T) { -+ value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("*2\r\n$3\r\nGET\r\n$4\r\nthis\r\n"))) -+ -+ if err != nil { -+ t.Errorf("error decoding array: %s", err) -+ } -+ -+ if value.typ != Array { -+ t.Errorf("expected Array, got %v", value.typ) -+ } -+ -+ if value.Array()[0].String() != "GET" { -+ t.Errorf("expected 'GET', got '%s'", value.Array()[0].String()) -+ } -+ -+ if value.Array()[1].String() != "this" { -+ t.Errorf("expected 'this', got '%s'", value.Array()[1].String()) -+ } -+} diff --git a/solutions/go/05-echo/diff/app/server.go.diff b/solutions/go/05-echo/diff/app/server.go.diff deleted file mode 100644 index f1ecbdb3..00000000 --- a/solutions/go/05-echo/diff/app/server.go.diff +++ /dev/null @@ -1,65 +0,0 @@ -@@ -1,47 +1,55 @@ - package main - - import ( -+ "bufio" -+ "errors" - "fmt" - "io" - "net" - "os" - ) - - func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - for { - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - go handleConnection(conn) - } - } - - func handleConnection(conn net.Conn) { - defer conn.Close() - - for { -- buf := make([]byte, 1024) -- -- _, err := conn.Read(buf) -- if err == io.EOF { -+ value, err := DecodeRESP(bufio.NewReader(conn)) -+ if errors.Is(err, io.EOF) { - break - } - if err != nil { -- fmt.Println("error reading from client: ", err.Error()) -- os.Exit(1) -+ fmt.Println("Error decoding RESP: ", err.Error()) -+ return // Ignore clients that we fail to read from - } - -- // Let's ignore the client's input for now and hardcode a response. -- // We'll implement a proper Redis Protocol parser in later stages. -- conn.Write([]byte("+PONG\r\n")) -+ command := value.Array()[0].String() -+ args := value.Array()[1:] -+ -+ switch command { -+ case "ping": -+ conn.Write([]byte("+PONG\r\n")) -+ case "echo": -+ conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(args[0].String()), args[0].String()))) -+ default: -+ conn.Write([]byte("-ERR unknown command '" + command + "'\r\n")) -+ } - } - } diff --git a/solutions/go/05-echo/explanation.md b/solutions/go/05-echo/explanation.md deleted file mode 100644 index 638a7559..00000000 --- a/solutions/go/05-echo/explanation.md +++ /dev/null @@ -1,71 +0,0 @@ -In Stage 5, we explore streams processing. - -In previous stages, the incoming client requests were always `PING`, and so we were able to hardcode our responses -as `PONG`. Adding support for `ECHO` means that we first need to determine whether the incoming request is an `ECHO` -or a `PING`. We also need to be able to read the argument provided to `ECHO`, in order to use it in the response. - -Since the entire communication follows RESP, we also need to build a decoder for parsing the incoming request, and -an encoder for delivering the response. You can review the complete implementation in the Diff tab — in this -guide we'll highlight the key areas to pay attention to. - -We'll decode and capture the request within `value`. The decoding will be handled by `DecodeRESP`, a utility -function we'll create separately. If the decoding results in an error, we capture the error and `return` to -observe other requests. - -```go -value, err := DecodeRESP(bufio.NewReader(conn)) - -if err != nil { - fmt.Println("Error decoding RESP: ", err.Error()) - return -} -``` - -We check the decoded value to see if the command was a `PING` or an `ECHO`. If `PING`, we reuse our response from -the previous stages. We'll look at `ECHO` separately. If neither, we send a -[RESP error response](https://redis.io/docs/reference/protocol-spec/#resp-errors). - -```go -command := value.Array()[0].String() -args := value.Array()[1:] - -switch command { - case "ping": - conn.Write([]byte("+PONG\r\n")) - case "echo": - // handle ECHO - default: - conn.Write([]byte("-ERR unknown command '" + command + "'\r\n")) -} -``` - -For `ECHO`, we send back the first argument as a RESP-encoded bulk string. - -```go -case "echo": -conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(args[0].String()), args[0].String()))) -``` - -In the solution for this stage, you'll find that we've created a separate utility file for functions related to -RESP. The key function in it is `DecodeRESP`. This function reads the first byte from the input and then calls other -functions as needed. - -```go -func DecodeRESP(byteStream *bufio.Reader) (Value, error) { - dataTypeByte, err := byteStream.ReadByte() - if err != nil { - return Value{}, err - } - - switch string(dataTypeByte) { - case "+": - return decodeSimpleString(byteStream) - case "$": - return decodeBulkString(byteStream) - case "*": - return decodeArray(byteStream) - } - - return Value{}, fmt.Errorf("invalid RESP data type byte: %s", string(dataTypeByte)) -} -``` diff --git a/solutions/go/06-set_get/code/README.md b/solutions/go/06-set_get/code/README.md deleted file mode 100644 index bc674ece..00000000 --- a/solutions/go/06-set_get/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Go solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/server.go`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `go (1.19)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/server.go`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/go/06-set_get/code/app/redis_protocol.go b/solutions/go/06-set_get/code/app/redis_protocol.go deleted file mode 100644 index 78ba02e6..00000000 --- a/solutions/go/06-set_get/code/app/redis_protocol.go +++ /dev/null @@ -1,146 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "io" - "strconv" -) - -// Type represents a Value type -type Type byte - -const ( - SimpleString Type = '+' - BulkString Type = '$' - Array Type = '*' -) - -// Value represents the data of a valid RESP type. -type Value struct { - typ Type - bytes []byte - array []Value -} - -// String converts Value to a string. -// -// If Value cannot be converted, an empty string is returned. -func (v Value) String() string { - if v.typ == BulkString || v.typ == SimpleString { - return string(v.bytes) - } - - return "" -} - -// Array converts Value to an array. -// -// If Value cannot be converted, an empty array is returned. -func (v Value) Array() []Value { - if v.typ == Array { - return v.array - } - - return []Value{} -} - -// DecodeRESP parses a RESP message and returns a RedisValue -func DecodeRESP(byteStream *bufio.Reader) (Value, error) { - dataTypeByte, err := byteStream.ReadByte() - if err != nil { - return Value{}, err - } - - switch string(dataTypeByte) { - case "+": - return decodeSimpleString(byteStream) - case "$": - return decodeBulkString(byteStream) - case "*": - return decodeArray(byteStream) - } - - return Value{}, fmt.Errorf("invalid RESP data type byte: %s", string(dataTypeByte)) -} - -func decodeSimpleString(byteStream *bufio.Reader) (Value, error) { - readBytes, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, err - } - - return Value{ - typ: SimpleString, - bytes: readBytes, - }, nil -} - -func decodeBulkString(byteStream *bufio.Reader) (Value, error) { - readBytesForCount, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, fmt.Errorf("failed to read bulk string length: %s", err) - } - - count, err := strconv.Atoi(string(readBytesForCount)) - if err != nil { - return Value{}, fmt.Errorf("failed to parse bulk string length: %s", err) - } - - readBytes := make([]byte, count+2) - - if _, err := io.ReadFull(byteStream, readBytes); err != nil { - return Value{}, fmt.Errorf("failed to read bulk string contents: %s", err) - } - - return Value{ - typ: BulkString, - bytes: readBytes[:count], - }, nil -} - -func decodeArray(byteStream *bufio.Reader) (Value, error) { - readBytesForCount, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, fmt.Errorf("failed to read bulk string length: %s", err) - } - - count, err := strconv.Atoi(string(readBytesForCount)) - if err != nil { - return Value{}, fmt.Errorf("failed to parse bulk string length: %s", err) - } - - array := []Value{} - - for i := 1; i <= count; i++ { - value, err := DecodeRESP(byteStream) - if err != nil { - return Value{}, err - } - - array = append(array, value) - } - - return Value{ - typ: Array, - array: array, - }, nil -} - -func readUntilCRLF(byteStream *bufio.Reader) ([]byte, error) { - readBytes := []byte{} - - for { - b, err := byteStream.ReadBytes('\n') - if err != nil { - return nil, err - } - - readBytes = append(readBytes, b...) - if len(readBytes) >= 2 && readBytes[len(readBytes)-2] == '\r' { - break - } - } - - return readBytes[:len(readBytes)-2], nil -} diff --git a/solutions/go/06-set_get/code/app/redis_protocol_test.go b/solutions/go/06-set_get/code/app/redis_protocol_test.go deleted file mode 100644 index 0121ff74..00000000 --- a/solutions/go/06-set_get/code/app/redis_protocol_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "testing" -) - -func TestDecodeSimpleString(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("+foo\r\n"))) - - if err != nil { - t.Errorf("error decoding simple string: %s", err) - } - - if value.typ != SimpleString { - t.Errorf("expected SimpleString, got %v", value.typ) - } - - if value.String() != "foo" { - t.Errorf("expected 'foo', got '%s'", value.String()) - } -} - -func TestDecodeBulkString(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("$4\r\nabcd\r\n"))) - - if err != nil { - t.Errorf("error decoding bulk string: %s", err) - } - - if value.typ != BulkString { - t.Errorf("expected BulkString, got %v", value.typ) - } - - if value.String() != "abcd" { - t.Errorf("expected 'abcd', got '%s'", value.String()) - } -} - -func TestDecodeBulkStringArray(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("*2\r\n$3\r\nGET\r\n$4\r\nthis\r\n"))) - - if err != nil { - t.Errorf("error decoding array: %s", err) - } - - if value.typ != Array { - t.Errorf("expected Array, got %v", value.typ) - } - - if value.Array()[0].String() != "GET" { - t.Errorf("expected 'GET', got '%s'", value.Array()[0].String()) - } - - if value.Array()[1].String() != "this" { - t.Errorf("expected 'this', got '%s'", value.Array()[1].String()) - } -} diff --git a/solutions/go/06-set_get/code/app/server.go b/solutions/go/06-set_get/code/app/server.go deleted file mode 100644 index 0e4e7563..00000000 --- a/solutions/go/06-set_get/code/app/server.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "bufio" - "errors" - "fmt" - "io" - "net" - "os" -) - -func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - storage := NewStorage() - - for { - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - go handleConnection(conn, storage) - } -} - -func handleConnection(conn net.Conn, storage *Storage) { - defer conn.Close() - - for { - value, err := DecodeRESP(bufio.NewReader(conn)) - if errors.Is(err, io.EOF) { - break - } - if err != nil { - fmt.Println("Error decoding RESP: ", err.Error()) - return // Ignore clients that we fail to read from - } - - command := value.Array()[0].String() - args := value.Array()[1:] - - switch command { - case "ping": - conn.Write([]byte("+PONG\r\n")) - case "echo": - conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(args[0].String()), args[0].String()))) - case "set": - storage.Set(args[0].String(), args[1].String()) - conn.Write([]byte("+OK\r\n")) - case "get": - conn.Write([]byte(fmt.Sprintf("+%s\r\n", storage.Get(args[0].String())))) - default: - conn.Write([]byte("-ERR unknown command '" + command + "'\r\n")) - } - } -} diff --git a/solutions/go/06-set_get/code/app/storage.go b/solutions/go/06-set_get/code/app/storage.go deleted file mode 100644 index c2d66ca3..00000000 --- a/solutions/go/06-set_get/code/app/storage.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -type Storage struct { - data map[string]string -} - -func NewStorage() *Storage { - return &Storage{ - data: make(map[string]string), - } -} - -func (kv *Storage) Get(key string) string { - return kv.data[key] -} - -func (kv *Storage) Set(key string, value string) { - kv.data[key] = value -} diff --git a/solutions/go/06-set_get/code/codecrafters.yml b/solutions/go/06-set_get/code/codecrafters.yml deleted file mode 100644 index b94dbc95..00000000 --- a/solutions/go/06-set_get/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Go version used to run your code -# on Codecrafters. -# -# Available versions: go-1.19 -language_pack: go-1.19 diff --git a/solutions/go/06-set_get/code/spawn_redis_server.sh b/solutions/go/06-set_get/code/spawn_redis_server.sh deleted file mode 100755 index 2c7df9d9..00000000 --- a/solutions/go/06-set_get/code/spawn_redis_server.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -set -e -tmpFile=$(mktemp) -go build -o "$tmpFile" app/*.go -exec "$tmpFile" diff --git a/solutions/go/06-set_get/definition.yml b/solutions/go/06-set_get/definition.yml deleted file mode 100644 index 78317b26..00000000 --- a/solutions/go/06-set_get/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/17 diff --git a/solutions/go/06-set_get/diff/app/server.go.diff b/solutions/go/06-set_get/diff/app/server.go.diff deleted file mode 100644 index 2665fc24..00000000 --- a/solutions/go/06-set_get/diff/app/server.go.diff +++ /dev/null @@ -1,65 +0,0 @@ -@@ -1,55 +1,62 @@ - package main - - import ( - "bufio" - "errors" - "fmt" - "io" - "net" - "os" - ) - - func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - -+ storage := NewStorage() -+ - for { - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - -- go handleConnection(conn) -+ go handleConnection(conn, storage) - } - } - --func handleConnection(conn net.Conn) { -+func handleConnection(conn net.Conn, storage *Storage) { - defer conn.Close() - - for { - value, err := DecodeRESP(bufio.NewReader(conn)) - if errors.Is(err, io.EOF) { - break - } - if err != nil { - fmt.Println("Error decoding RESP: ", err.Error()) - return // Ignore clients that we fail to read from - } - - command := value.Array()[0].String() - args := value.Array()[1:] - - switch command { - case "ping": - conn.Write([]byte("+PONG\r\n")) - case "echo": - conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(args[0].String()), args[0].String()))) -+ case "set": -+ storage.Set(args[0].String(), args[1].String()) -+ conn.Write([]byte("+OK\r\n")) -+ case "get": -+ conn.Write([]byte(fmt.Sprintf("+%s\r\n", storage.Get(args[0].String())))) - default: - conn.Write([]byte("-ERR unknown command '" + command + "'\r\n")) - } - } - } diff --git a/solutions/go/06-set_get/diff/app/storage.go.diff b/solutions/go/06-set_get/diff/app/storage.go.diff deleted file mode 100644 index c2fa5013..00000000 --- a/solutions/go/06-set_get/diff/app/storage.go.diff +++ /dev/null @@ -1,20 +0,0 @@ -@@ -0,0 +1,19 @@ -+package main -+ -+type Storage struct { -+ data map[string]string -+} -+ -+func NewStorage() *Storage { -+ return &Storage{ -+ data: make(map[string]string), -+ } -+} -+ -+func (kv *Storage) Get(key string) string { -+ return kv.data[key] -+} -+ -+func (kv *Storage) Set(key string, value string) { -+ kv.data[key] = value -+} diff --git a/solutions/go/07-expiry/code/README.md b/solutions/go/07-expiry/code/README.md deleted file mode 100644 index bc674ece..00000000 --- a/solutions/go/07-expiry/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Go solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/server.go`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `go (1.19)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/server.go`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/go/07-expiry/code/app/redis_protocol.go b/solutions/go/07-expiry/code/app/redis_protocol.go deleted file mode 100644 index 78ba02e6..00000000 --- a/solutions/go/07-expiry/code/app/redis_protocol.go +++ /dev/null @@ -1,146 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "io" - "strconv" -) - -// Type represents a Value type -type Type byte - -const ( - SimpleString Type = '+' - BulkString Type = '$' - Array Type = '*' -) - -// Value represents the data of a valid RESP type. -type Value struct { - typ Type - bytes []byte - array []Value -} - -// String converts Value to a string. -// -// If Value cannot be converted, an empty string is returned. -func (v Value) String() string { - if v.typ == BulkString || v.typ == SimpleString { - return string(v.bytes) - } - - return "" -} - -// Array converts Value to an array. -// -// If Value cannot be converted, an empty array is returned. -func (v Value) Array() []Value { - if v.typ == Array { - return v.array - } - - return []Value{} -} - -// DecodeRESP parses a RESP message and returns a RedisValue -func DecodeRESP(byteStream *bufio.Reader) (Value, error) { - dataTypeByte, err := byteStream.ReadByte() - if err != nil { - return Value{}, err - } - - switch string(dataTypeByte) { - case "+": - return decodeSimpleString(byteStream) - case "$": - return decodeBulkString(byteStream) - case "*": - return decodeArray(byteStream) - } - - return Value{}, fmt.Errorf("invalid RESP data type byte: %s", string(dataTypeByte)) -} - -func decodeSimpleString(byteStream *bufio.Reader) (Value, error) { - readBytes, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, err - } - - return Value{ - typ: SimpleString, - bytes: readBytes, - }, nil -} - -func decodeBulkString(byteStream *bufio.Reader) (Value, error) { - readBytesForCount, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, fmt.Errorf("failed to read bulk string length: %s", err) - } - - count, err := strconv.Atoi(string(readBytesForCount)) - if err != nil { - return Value{}, fmt.Errorf("failed to parse bulk string length: %s", err) - } - - readBytes := make([]byte, count+2) - - if _, err := io.ReadFull(byteStream, readBytes); err != nil { - return Value{}, fmt.Errorf("failed to read bulk string contents: %s", err) - } - - return Value{ - typ: BulkString, - bytes: readBytes[:count], - }, nil -} - -func decodeArray(byteStream *bufio.Reader) (Value, error) { - readBytesForCount, err := readUntilCRLF(byteStream) - if err != nil { - return Value{}, fmt.Errorf("failed to read bulk string length: %s", err) - } - - count, err := strconv.Atoi(string(readBytesForCount)) - if err != nil { - return Value{}, fmt.Errorf("failed to parse bulk string length: %s", err) - } - - array := []Value{} - - for i := 1; i <= count; i++ { - value, err := DecodeRESP(byteStream) - if err != nil { - return Value{}, err - } - - array = append(array, value) - } - - return Value{ - typ: Array, - array: array, - }, nil -} - -func readUntilCRLF(byteStream *bufio.Reader) ([]byte, error) { - readBytes := []byte{} - - for { - b, err := byteStream.ReadBytes('\n') - if err != nil { - return nil, err - } - - readBytes = append(readBytes, b...) - if len(readBytes) >= 2 && readBytes[len(readBytes)-2] == '\r' { - break - } - } - - return readBytes[:len(readBytes)-2], nil -} diff --git a/solutions/go/07-expiry/code/app/redis_protocol_test.go b/solutions/go/07-expiry/code/app/redis_protocol_test.go deleted file mode 100644 index 0121ff74..00000000 --- a/solutions/go/07-expiry/code/app/redis_protocol_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "testing" -) - -func TestDecodeSimpleString(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("+foo\r\n"))) - - if err != nil { - t.Errorf("error decoding simple string: %s", err) - } - - if value.typ != SimpleString { - t.Errorf("expected SimpleString, got %v", value.typ) - } - - if value.String() != "foo" { - t.Errorf("expected 'foo', got '%s'", value.String()) - } -} - -func TestDecodeBulkString(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("$4\r\nabcd\r\n"))) - - if err != nil { - t.Errorf("error decoding bulk string: %s", err) - } - - if value.typ != BulkString { - t.Errorf("expected BulkString, got %v", value.typ) - } - - if value.String() != "abcd" { - t.Errorf("expected 'abcd', got '%s'", value.String()) - } -} - -func TestDecodeBulkStringArray(t *testing.T) { - value, err := DecodeRESP(bufio.NewReader(bytes.NewBufferString("*2\r\n$3\r\nGET\r\n$4\r\nthis\r\n"))) - - if err != nil { - t.Errorf("error decoding array: %s", err) - } - - if value.typ != Array { - t.Errorf("expected Array, got %v", value.typ) - } - - if value.Array()[0].String() != "GET" { - t.Errorf("expected 'GET', got '%s'", value.Array()[0].String()) - } - - if value.Array()[1].String() != "this" { - t.Errorf("expected 'this', got '%s'", value.Array()[1].String()) - } -} diff --git a/solutions/go/07-expiry/code/app/server.go b/solutions/go/07-expiry/code/app/server.go deleted file mode 100644 index 3a65fd12..00000000 --- a/solutions/go/07-expiry/code/app/server.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "bufio" - "errors" - "fmt" - "io" - "net" - "os" - "strconv" - "time" -) - -func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - storage := NewStorage() - - for { - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - go handleConnection(conn, storage) - } -} - -func handleConnection(conn net.Conn, storage *Storage) { - defer conn.Close() - - for { - value, err := DecodeRESP(bufio.NewReader(conn)) - if errors.Is(err, io.EOF) { - break - } - if err != nil { - fmt.Println("Error decoding RESP: ", err.Error()) - return // Ignore clients that we fail to read from - } - - command := value.Array()[0].String() - args := value.Array()[1:] - - switch command { - case "ping": - conn.Write([]byte("+PONG\r\n")) - case "echo": - conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(args[0].String()), args[0].String()))) - case "set": - if len(args) > 2 { - if args[2].String() == "px" { - expiryStr := args[3].String() - expiryInMilliseconds, err := strconv.Atoi(expiryStr) - if err != nil { - conn.Write([]byte(fmt.Sprintf("-ERR PX value (%s) is not an integer\r\n", expiryStr))) - break - } - - storage.SetWithExpiry(args[0].String(), args[1].String(), time.Duration(expiryInMilliseconds)*time.Millisecond) - } else { - conn.Write([]byte(fmt.Sprintf("-ERR unknown option for set: %s\r\n", args[2].String()))) - } - } else { - storage.Set(args[0].String(), args[1].String()) - } - - conn.Write([]byte("+OK\r\n")) - case "get": - value, found := storage.Get(args[0].String()) - if found { - conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(value), value))) - } else { - conn.Write([]byte("$-1\r\n")) - } - default: - conn.Write([]byte("-ERR unknown command '" + command + "'\r\n")) - } - } -} diff --git a/solutions/go/07-expiry/code/app/storage.go b/solutions/go/07-expiry/code/app/storage.go deleted file mode 100644 index f8b5cc59..00000000 --- a/solutions/go/07-expiry/code/app/storage.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import "time" - -type Storage struct { - data map[string]ValueWithExpiry -} - -type ValueWithExpiry struct { - value string - expiresAt time.Time -} - -func (v ValueWithExpiry) IsExpired() bool { - if v.expiresAt.IsZero() { - return false - } - - return v.expiresAt.Before(time.Now()) -} - -func NewStorage() *Storage { - return &Storage{ - data: make(map[string]ValueWithExpiry), - } -} - -func (kv *Storage) Get(key string) (string, bool) { - valueWithExpiry, ok := kv.data[key] - if !ok { - return "", false - } - - if valueWithExpiry.IsExpired() { - delete(kv.data, key) - return "", false - } - - return valueWithExpiry.value, true -} - -func (kv *Storage) Set(key string, value string) { - kv.data[key] = ValueWithExpiry{value: value} -} - -func (kv *Storage) SetWithExpiry(key string, value string, expiry time.Duration) { - kv.data[key] = ValueWithExpiry{ - value: value, - expiresAt: time.Now().Add(expiry), - } -} diff --git a/solutions/go/07-expiry/code/codecrafters.yml b/solutions/go/07-expiry/code/codecrafters.yml deleted file mode 100644 index b94dbc95..00000000 --- a/solutions/go/07-expiry/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Go version used to run your code -# on Codecrafters. -# -# Available versions: go-1.19 -language_pack: go-1.19 diff --git a/solutions/go/07-expiry/code/spawn_redis_server.sh b/solutions/go/07-expiry/code/spawn_redis_server.sh deleted file mode 100755 index 2c7df9d9..00000000 --- a/solutions/go/07-expiry/code/spawn_redis_server.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -set -e -tmpFile=$(mktemp) -go build -o "$tmpFile" app/*.go -exec "$tmpFile" diff --git a/solutions/go/07-expiry/definition.yml b/solutions/go/07-expiry/definition.yml deleted file mode 100644 index 929cba2a..00000000 --- a/solutions/go/07-expiry/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/13 diff --git a/solutions/go/07-expiry/diff/app/server.go.diff b/solutions/go/07-expiry/diff/app/server.go.diff deleted file mode 100644 index bf64976d..00000000 --- a/solutions/go/07-expiry/diff/app/server.go.diff +++ /dev/null @@ -1,88 +0,0 @@ -@@ -1,62 +1,85 @@ - package main - - import ( - "bufio" - "errors" - "fmt" - "io" - "net" - "os" -+ "strconv" -+ "time" - ) - - func main() { - l, err := net.Listen("tcp", "0.0.0.0:6379") - if err != nil { - fmt.Println("Failed to bind to port 6379") - os.Exit(1) - } - - storage := NewStorage() - - for { - conn, err := l.Accept() - if err != nil { - fmt.Println("Error accepting connection: ", err.Error()) - os.Exit(1) - } - - go handleConnection(conn, storage) - } - } - - func handleConnection(conn net.Conn, storage *Storage) { - defer conn.Close() - - for { - value, err := DecodeRESP(bufio.NewReader(conn)) - if errors.Is(err, io.EOF) { - break - } - if err != nil { - fmt.Println("Error decoding RESP: ", err.Error()) - return // Ignore clients that we fail to read from - } - - command := value.Array()[0].String() - args := value.Array()[1:] - - switch command { - case "ping": - conn.Write([]byte("+PONG\r\n")) - case "echo": - conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(args[0].String()), args[0].String()))) - case "set": -- storage.Set(args[0].String(), args[1].String()) -+ if len(args) > 2 { -+ if args[2].String() == "px" { -+ expiryStr := args[3].String() -+ expiryInMilliseconds, err := strconv.Atoi(expiryStr) -+ if err != nil { -+ conn.Write([]byte(fmt.Sprintf("-ERR PX value (%s) is not an integer\r\n", expiryStr))) -+ break -+ } -+ -+ storage.SetWithExpiry(args[0].String(), args[1].String(), time.Duration(expiryInMilliseconds)*time.Millisecond) -+ } else { -+ conn.Write([]byte(fmt.Sprintf("-ERR unknown option for set: %s\r\n", args[2].String()))) -+ } -+ } else { -+ storage.Set(args[0].String(), args[1].String()) -+ } -+ - conn.Write([]byte("+OK\r\n")) - case "get": -- conn.Write([]byte(fmt.Sprintf("+%s\r\n", storage.Get(args[0].String())))) -+ value, found := storage.Get(args[0].String()) -+ if found { -+ conn.Write([]byte(fmt.Sprintf("$%d\r\n%s\r\n", len(value), value))) -+ } else { -+ conn.Write([]byte("$-1\r\n")) -+ } - default: - conn.Write([]byte("-ERR unknown command '" + command + "'\r\n")) - } - } - } diff --git a/solutions/go/07-expiry/diff/app/storage.go.diff b/solutions/go/07-expiry/diff/app/storage.go.diff deleted file mode 100644 index ab61ad26..00000000 --- a/solutions/go/07-expiry/diff/app/storage.go.diff +++ /dev/null @@ -1,57 +0,0 @@ -@@ -1,19 +1,51 @@ - package main - -+import "time" -+ - type Storage struct { -- data map[string]string -+ data map[string]ValueWithExpiry -+} -+ -+type ValueWithExpiry struct { -+ value string -+ expiresAt time.Time -+} -+ -+func (v ValueWithExpiry) IsExpired() bool { -+ if v.expiresAt.IsZero() { -+ return false -+ } -+ -+ return v.expiresAt.Before(time.Now()) - } - - func NewStorage() *Storage { - return &Storage{ -- data: make(map[string]string), -+ data: make(map[string]ValueWithExpiry), - } - } - --func (kv *Storage) Get(key string) string { -- return kv.data[key] -+func (kv *Storage) Get(key string) (string, bool) { -+ valueWithExpiry, ok := kv.data[key] -+ if !ok { -+ return "", false -+ } -+ -+ if valueWithExpiry.IsExpired() { -+ delete(kv.data, key) -+ return "", false -+ } -+ -+ return valueWithExpiry.value, true - } - - func (kv *Storage) Set(key string, value string) { -- kv.data[key] = value -+ kv.data[key] = ValueWithExpiry{value: value} -+} -+ -+func (kv *Storage) SetWithExpiry(key string, value string, expiry time.Duration) { -+ kv.data[key] = ValueWithExpiry{ -+ value: value, -+ expiresAt: time.Now().Add(expiry), -+ } - } diff --git a/solutions/javascript/02-ping-pong/code/README.md b/solutions/javascript/02-ping-pong/code/README.md deleted file mode 100644 index d2c4561b..00000000 --- a/solutions/javascript/02-ping-pong/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for JavaScript solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/main.js`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `node (16)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/main.js`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/javascript/02-ping-pong/code/app/main.js b/solutions/javascript/02-ping-pong/code/app/main.js deleted file mode 100644 index 90b22511..00000000 --- a/solutions/javascript/02-ping-pong/code/app/main.js +++ /dev/null @@ -1,9 +0,0 @@ -const net = require("net"); - -const server = net.createServer((connection) => { - connection.on("data", () => { - connection.write("+PONG\r\n"); - }); -}); - -server.listen(6379, "127.0.0.1"); diff --git a/solutions/javascript/02-ping-pong/code/codecrafters.yml b/solutions/javascript/02-ping-pong/code/codecrafters.yml deleted file mode 100644 index f8d4f722..00000000 --- a/solutions/javascript/02-ping-pong/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the JavaScript version used to run your code -# on Codecrafters. -# -# Available versions: nodejs-16 -language_pack: nodejs-16 diff --git a/solutions/javascript/02-ping-pong/code/spawn_redis_server.sh b/solutions/javascript/02-ping-pong/code/spawn_redis_server.sh deleted file mode 100755 index d030a8f1..00000000 --- a/solutions/javascript/02-ping-pong/code/spawn_redis_server.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec node app/main.js diff --git a/solutions/javascript/02-ping-pong/definition.yml b/solutions/javascript/02-ping-pong/definition.yml deleted file mode 100644 index b0bdb5aa..00000000 --- a/solutions/javascript/02-ping-pong/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/22 diff --git a/solutions/javascript/02-ping-pong/diff/app/main.js.diff b/solutions/javascript/02-ping-pong/diff/app/main.js.diff deleted file mode 100644 index bbd17001..00000000 --- a/solutions/javascript/02-ping-pong/diff/app/main.js.diff +++ /dev/null @@ -1,11 +0,0 @@ -@@ -1,7 +1,9 @@ - const net = require("net"); - - const server = net.createServer((connection) => { -- // Handle connection -+ connection.on("data", () => { -+ connection.write("+PONG\r\n"); -+ }); - }); - - server.listen(6379, "127.0.0.1"); diff --git a/solutions/javascript/02-ping-pong/explanation.md b/solutions/javascript/02-ping-pong/explanation.md deleted file mode 100644 index 0fb6e6db..00000000 --- a/solutions/javascript/02-ping-pong/explanation.md +++ /dev/null @@ -1,25 +0,0 @@ -Stage 2 is an exercise in reading and responding to requests using [net.Socket objects](https://nodejs.org/api/net.html#class-netsocket). - -In the first stage, we were simply accepting a connection but weren't reading data from it. - -As we go further, we want to actually parse the incoming request, and respond suitably. - -First, we'll add an event listener for the `data` event. - -```javascript -connection.on("data", () => { - // Respond with PONG -}); -``` - -Next, we'll send our response to the client. For this stage, we know that the tester _only_ sends us `PING`, so we don't have to -parse the incoming data. We can hardcode `PONG` as our response. - -As mentioned in the stage instructions, we need to encode the response as a -[RESP Simple String](https://redis.io/docs/reference/protocol-spec/#resp-simple-strings). The ideal approach is to -create a RESP encoder function — but for now, since we know that our response will always be `PONG`, we can hardcode -the response. We will create the function in the upcoming stages. - -```python -connection.write("+PONG\r\n"); -``` diff --git a/solutions/javascript/03-ping-pong-multiple/code/README.md b/solutions/javascript/03-ping-pong-multiple/code/README.md deleted file mode 100644 index d2c4561b..00000000 --- a/solutions/javascript/03-ping-pong-multiple/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for JavaScript solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/main.js`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `node (16)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/main.js`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/javascript/03-ping-pong-multiple/code/app/main.js b/solutions/javascript/03-ping-pong-multiple/code/app/main.js deleted file mode 100644 index 90b22511..00000000 --- a/solutions/javascript/03-ping-pong-multiple/code/app/main.js +++ /dev/null @@ -1,9 +0,0 @@ -const net = require("net"); - -const server = net.createServer((connection) => { - connection.on("data", () => { - connection.write("+PONG\r\n"); - }); -}); - -server.listen(6379, "127.0.0.1"); diff --git a/solutions/javascript/03-ping-pong-multiple/code/codecrafters.yml b/solutions/javascript/03-ping-pong-multiple/code/codecrafters.yml deleted file mode 100644 index f8d4f722..00000000 --- a/solutions/javascript/03-ping-pong-multiple/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the JavaScript version used to run your code -# on Codecrafters. -# -# Available versions: nodejs-16 -language_pack: nodejs-16 diff --git a/solutions/javascript/03-ping-pong-multiple/code/spawn_redis_server.sh b/solutions/javascript/03-ping-pong-multiple/code/spawn_redis_server.sh deleted file mode 100755 index d030a8f1..00000000 --- a/solutions/javascript/03-ping-pong-multiple/code/spawn_redis_server.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec node app/main.js diff --git a/solutions/javascript/03-ping-pong-multiple/definition.yml b/solutions/javascript/03-ping-pong-multiple/definition.yml deleted file mode 100644 index 1ac76e5f..00000000 --- a/solutions/javascript/03-ping-pong-multiple/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/23 diff --git a/solutions/javascript/03-ping-pong-multiple/explanation.md b/solutions/javascript/03-ping-pong-multiple/explanation.md deleted file mode 100644 index fd4744f3..00000000 --- a/solutions/javascript/03-ping-pong-multiple/explanation.md +++ /dev/null @@ -1,5 +0,0 @@ -In most languages, passing this stage would involve adding a loop to continuously read data and respond back with `PONG`. - -Since JavaScript's programming model is event-driven, we're able to pass the stage with zero changes! The event handler we -attached to the [`data`](https://nodejs.org/api/net.html#net_event_data) event will automatically fire again when the -client sends more commands. diff --git a/solutions/javascript/04-concurrent-clients/code/README.md b/solutions/javascript/04-concurrent-clients/code/README.md deleted file mode 100644 index d2c4561b..00000000 --- a/solutions/javascript/04-concurrent-clients/code/README.md +++ /dev/null @@ -1,34 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for JavaScript solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/main.js`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `node (16)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/main.js`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/javascript/04-concurrent-clients/code/app/main.js b/solutions/javascript/04-concurrent-clients/code/app/main.js deleted file mode 100644 index 90b22511..00000000 --- a/solutions/javascript/04-concurrent-clients/code/app/main.js +++ /dev/null @@ -1,9 +0,0 @@ -const net = require("net"); - -const server = net.createServer((connection) => { - connection.on("data", () => { - connection.write("+PONG\r\n"); - }); -}); - -server.listen(6379, "127.0.0.1"); diff --git a/solutions/javascript/04-concurrent-clients/code/codecrafters.yml b/solutions/javascript/04-concurrent-clients/code/codecrafters.yml deleted file mode 100644 index f8d4f722..00000000 --- a/solutions/javascript/04-concurrent-clients/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the JavaScript version used to run your code -# on Codecrafters. -# -# Available versions: nodejs-16 -language_pack: nodejs-16 diff --git a/solutions/javascript/04-concurrent-clients/code/spawn_redis_server.sh b/solutions/javascript/04-concurrent-clients/code/spawn_redis_server.sh deleted file mode 100755 index d030a8f1..00000000 --- a/solutions/javascript/04-concurrent-clients/code/spawn_redis_server.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec node app/main.js diff --git a/solutions/javascript/04-concurrent-clients/definition.yml b/solutions/javascript/04-concurrent-clients/definition.yml deleted file mode 100644 index c1837bbd..00000000 --- a/solutions/javascript/04-concurrent-clients/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/20 diff --git a/solutions/javascript/04-concurrent-clients/explanation.md b/solutions/javascript/04-concurrent-clients/explanation.md deleted file mode 100644 index 7ea8effb..00000000 --- a/solutions/javascript/04-concurrent-clients/explanation.md +++ /dev/null @@ -1,5 +0,0 @@ -Just like the previous stage, this one too requires zero code changes to pass! - -In most languages, passing this stage would involve spawning a thread/process to handle each client that the server -accepts. When using JavaScript we don't need to do this because the event handler we passed in to `createServer` event -will automatically fire again when the server accepts more clients. diff --git a/solutions/python/02-ping-pong/code/README.md b/solutions/python/02-ping-pong/code/README.md deleted file mode 100644 index 17b2ec10..00000000 --- a/solutions/python/02-ping-pong/code/README.md +++ /dev/null @@ -1,61 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Python solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/main.py`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `python (3.x)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/main.py`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. - -# Troubleshooting - -## module `socket` has no attribute `create_server` - -When running your server locally, you might see an error like this: - -``` -Traceback (most recent call last): - File "/.../python3.7/runpy.py", line 193, in _run_module_as_main - "__main__", mod_spec) - File "/.../python3.7/runpy.py", line 85, in _run_code - exec(code, run_globals) - File "/app/app/main.py", line 11, in - main() - File "/app/app/main.py", line 6, in main - s = socket.create_server(("localhost", 6379), reuse_port=True) -AttributeError: module 'socket' has no attribute 'create_server' -``` - -This is because `socket.create_server` was introduced in Python 3.8, and you -might be running an older version. - -You can fix this by installing Python 3.8 locally and using that. - -If you'd like to use a different version of Python, change the `language_pack` -value in `codecrafters.yml`. diff --git a/solutions/python/02-ping-pong/code/app/main.py b/solutions/python/02-ping-pong/code/app/main.py deleted file mode 100644 index 67069f71..00000000 --- a/solutions/python/02-ping-pong/code/app/main.py +++ /dev/null @@ -1,12 +0,0 @@ -import socket - - -def main(): - server_socket = socket.create_server(("localhost", 6379), reuse_port=True) - client_connection, _ = server_socket.accept() # wait for client - client_connection.recv(1024) # wait for client to send data - client_connection.send(b"+PONG\r\n") - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/solutions/python/02-ping-pong/code/codecrafters.yml b/solutions/python/02-ping-pong/code/codecrafters.yml deleted file mode 100644 index 7ff8fea5..00000000 --- a/solutions/python/02-ping-pong/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Python version used to run your code -# on Codecrafters. -# -# Available versions: python-3.11 -language_pack: python-3.11 diff --git a/solutions/python/02-ping-pong/code/spawn_redis_server.sh b/solutions/python/02-ping-pong/code/spawn_redis_server.sh deleted file mode 100755 index d7d3afd8..00000000 --- a/solutions/python/02-ping-pong/code/spawn_redis_server.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec python3 -m app.main diff --git a/solutions/python/02-ping-pong/definition.yml b/solutions/python/02-ping-pong/definition.yml deleted file mode 100644 index 7faf6d4e..00000000 --- a/solutions/python/02-ping-pong/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/28 diff --git a/solutions/python/02-ping-pong/diff/app/main.py.diff b/solutions/python/02-ping-pong/diff/app/main.py.diff deleted file mode 100644 index 0eb21886..00000000 --- a/solutions/python/02-ping-pong/diff/app/main.py.diff +++ /dev/null @@ -1,16 +0,0 @@ -@@ -1,10 +1,12 @@ - import socket - - - def main(): - server_socket = socket.create_server(("localhost", 6379), reuse_port=True) -- server_socket.accept() # wait for client -+ client_connection, _ = server_socket.accept() # wait for client -+ client_connection.recv(1024) # wait for client to send data -+ client_connection.send(b"+PONG\r\n") - - - if __name__ == "__main__": -- main() -+ main() -\ No newline at end of file diff --git a/solutions/python/02-ping-pong/explanation.md b/solutions/python/02-ping-pong/explanation.md deleted file mode 100644 index 000629cd..00000000 --- a/solutions/python/02-ping-pong/explanation.md +++ /dev/null @@ -1,34 +0,0 @@ -Stage 2 is an exercise in reading and responding to requests using a [Socket object](https://docs.python.org/3/library/socket.html#socket-objects). - -In the first stage, we were simply accepting a connection (`_`), but weren't doing anything with it. - -```python -server_socket.accept() # wait for client -``` - -As we go further, we want to actually parse the incoming request, and respond suitably. Since we know that the -client only sends us `PING` at the moment, we can hardcode our response. - -First, we store the connection into a variable so we can read its value. - -```python -client_connection, _ = server_socket.accept() # wait for client -``` - -Next, we read data from the connection. For this stage, we know that the tester _only_ sends us `PING`, so we don't have to -parse the incoming data. - -```python -client_connection.recv(1024) # wait for client to send data -``` - -Once we've read data, we need to respond back with `PONG`. - -As mentioned in the stage instructions, we need to encode the response as a -[RESP Simple String](https://redis.io/docs/reference/protocol-spec/#resp-simple-strings). The ideal approach is to -create a RESP encoder function — but for now, since we know that our response will always be `PONG`, we can hardcode -the response. We will create the function in the upcoming stages. - -```python -client_connection.send(b"+PONG\r\n") -``` diff --git a/solutions/python/03-ping-pong-multiple/code/README.md b/solutions/python/03-ping-pong-multiple/code/README.md deleted file mode 100644 index 17b2ec10..00000000 --- a/solutions/python/03-ping-pong-multiple/code/README.md +++ /dev/null @@ -1,61 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Python solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/main.py`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `python (3.x)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/main.py`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. - -# Troubleshooting - -## module `socket` has no attribute `create_server` - -When running your server locally, you might see an error like this: - -``` -Traceback (most recent call last): - File "/.../python3.7/runpy.py", line 193, in _run_module_as_main - "__main__", mod_spec) - File "/.../python3.7/runpy.py", line 85, in _run_code - exec(code, run_globals) - File "/app/app/main.py", line 11, in - main() - File "/app/app/main.py", line 6, in main - s = socket.create_server(("localhost", 6379), reuse_port=True) -AttributeError: module 'socket' has no attribute 'create_server' -``` - -This is because `socket.create_server` was introduced in Python 3.8, and you -might be running an older version. - -You can fix this by installing Python 3.8 locally and using that. - -If you'd like to use a different version of Python, change the `language_pack` -value in `codecrafters.yml`. diff --git a/solutions/python/03-ping-pong-multiple/code/app/main.py b/solutions/python/03-ping-pong-multiple/code/app/main.py deleted file mode 100644 index 39a184c6..00000000 --- a/solutions/python/03-ping-pong-multiple/code/app/main.py +++ /dev/null @@ -1,14 +0,0 @@ -import socket - - -def main(): - server_socket = socket.create_server(("localhost", 6379), reuse_port=True) - client_connection, _ = server_socket.accept() # wait for client - - while True: - client_connection.recv(1024) # wait for client to send data - client_connection.send(b"+PONG\r\n") - - -if __name__ == "__main__": - main() diff --git a/solutions/python/03-ping-pong-multiple/code/codecrafters.yml b/solutions/python/03-ping-pong-multiple/code/codecrafters.yml deleted file mode 100644 index 7ff8fea5..00000000 --- a/solutions/python/03-ping-pong-multiple/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Python version used to run your code -# on Codecrafters. -# -# Available versions: python-3.11 -language_pack: python-3.11 diff --git a/solutions/python/03-ping-pong-multiple/code/spawn_redis_server.sh b/solutions/python/03-ping-pong-multiple/code/spawn_redis_server.sh deleted file mode 100755 index d7d3afd8..00000000 --- a/solutions/python/03-ping-pong-multiple/code/spawn_redis_server.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec python3 -m app.main diff --git a/solutions/python/03-ping-pong-multiple/definition.yml b/solutions/python/03-ping-pong-multiple/definition.yml deleted file mode 100644 index 56822329..00000000 --- a/solutions/python/03-ping-pong-multiple/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/29 diff --git a/solutions/python/03-ping-pong-multiple/diff/app/main.py.diff b/solutions/python/03-ping-pong-multiple/diff/app/main.py.diff deleted file mode 100644 index e95972a1..00000000 --- a/solutions/python/03-ping-pong-multiple/diff/app/main.py.diff +++ /dev/null @@ -1,19 +0,0 @@ -@@ -1,12 +1,14 @@ - import socket - - - def main(): - server_socket = socket.create_server(("localhost", 6379), reuse_port=True) - client_connection, _ = server_socket.accept() # wait for client -- client_connection.recv(1024) # wait for client to send data -- client_connection.send(b"+PONG\r\n") -+ -+ while True: -+ client_connection.recv(1024) # wait for client to send data -+ client_connection.send(b"+PONG\r\n") - - - if __name__ == "__main__": -- main() -\ No newline at end of file -+ main() diff --git a/solutions/python/03-ping-pong-multiple/explanation.md b/solutions/python/03-ping-pong-multiple/explanation.md deleted file mode 100644 index 2d2ff51e..00000000 --- a/solutions/python/03-ping-pong-multiple/explanation.md +++ /dev/null @@ -1,17 +0,0 @@ -Stage 3 builds on our progress from Stage 2. - -Earlier, we were anticipating a single `PING` request, and were accordingly responding back with a single `PONG`. - -As an improvement, we'll now monitor for more incoming requests — and each time we get one, we'll respond back with -`PONG`, and go back to waiting for the next one. We can achieve this with a `while` loop. - - -```python -while True: - client_connection.recv(1024) # wait for client to send data - client_connection.send(b"+PONG\r\n") -``` - -While this approach gets us through the stage, notice how our program is now blocked on the for loop as it waits -for incoming requests. During this time, the program cannot do anything else (including accepting connections from -other clients). We'll get around that in the next stage when we tackle concurrent requests. diff --git a/solutions/python/04-concurrent-clients/code/README.md b/solutions/python/04-concurrent-clients/code/README.md deleted file mode 100644 index 17b2ec10..00000000 --- a/solutions/python/04-concurrent-clients/code/README.md +++ /dev/null @@ -1,61 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Python solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/main.py`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `python (3.x)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/main.py`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. - -# Troubleshooting - -## module `socket` has no attribute `create_server` - -When running your server locally, you might see an error like this: - -``` -Traceback (most recent call last): - File "/.../python3.7/runpy.py", line 193, in _run_module_as_main - "__main__", mod_spec) - File "/.../python3.7/runpy.py", line 85, in _run_code - exec(code, run_globals) - File "/app/app/main.py", line 11, in - main() - File "/app/app/main.py", line 6, in main - s = socket.create_server(("localhost", 6379), reuse_port=True) -AttributeError: module 'socket' has no attribute 'create_server' -``` - -This is because `socket.create_server` was introduced in Python 3.8, and you -might be running an older version. - -You can fix this by installing Python 3.8 locally and using that. - -If you'd like to use a different version of Python, change the `language_pack` -value in `codecrafters.yml`. diff --git a/solutions/python/04-concurrent-clients/code/app/main.py b/solutions/python/04-concurrent-clients/code/app/main.py deleted file mode 100644 index ebc4152e..00000000 --- a/solutions/python/04-concurrent-clients/code/app/main.py +++ /dev/null @@ -1,23 +0,0 @@ -import threading -import socket - - -def handle_connection(client_connection): - while True: - try: - client_connection.recv(1024) # wait for client to send data - client_connection.send(b"+PONG\r\n") - except ConnectionError: - break # Stop serving if the client connection is closed - - -def main(): - server_socket = socket.create_server(("localhost", 6379), reuse_port=True) - - while True: - client_connection, _ = server_socket.accept() # wait for client - threading.Thread(target=handle_connection, args=(client_connection,)).start() - - -if __name__ == "__main__": - main() diff --git a/solutions/python/04-concurrent-clients/code/codecrafters.yml b/solutions/python/04-concurrent-clients/code/codecrafters.yml deleted file mode 100644 index 7ff8fea5..00000000 --- a/solutions/python/04-concurrent-clients/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Python version used to run your code -# on Codecrafters. -# -# Available versions: python-3.11 -language_pack: python-3.11 diff --git a/solutions/python/04-concurrent-clients/code/spawn_redis_server.sh b/solutions/python/04-concurrent-clients/code/spawn_redis_server.sh deleted file mode 100755 index d7d3afd8..00000000 --- a/solutions/python/04-concurrent-clients/code/spawn_redis_server.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec python3 -m app.main diff --git a/solutions/python/04-concurrent-clients/definition.yml b/solutions/python/04-concurrent-clients/definition.yml deleted file mode 100644 index 9fcb9c1e..00000000 --- a/solutions/python/04-concurrent-clients/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/25 diff --git a/solutions/python/04-concurrent-clients/diff/app/main.py.diff b/solutions/python/04-concurrent-clients/diff/app/main.py.diff deleted file mode 100644 index 69127acb..00000000 --- a/solutions/python/04-concurrent-clients/diff/app/main.py.diff +++ /dev/null @@ -1,27 +0,0 @@ -@@ -1,14 +1,23 @@ -+import threading - import socket - - -+def handle_connection(client_connection): -+ while True: -+ try: -+ client_connection.recv(1024) # wait for client to send data -+ client_connection.send(b"+PONG\r\n") -+ except ConnectionError: -+ break # Stop serving if the client connection is closed -+ -+ - def main(): - server_socket = socket.create_server(("localhost", 6379), reuse_port=True) -- client_connection, _ = server_socket.accept() # wait for client - - while True: -- client_connection.recv(1024) # wait for client to send data -- client_connection.send(b"+PONG\r\n") -+ client_connection, _ = server_socket.accept() # wait for client -+ threading.Thread(target=handle_connection, args=(client_connection,)).start() - - - if __name__ == "__main__": - main() diff --git a/solutions/python/04-concurrent-clients/explanation.md b/solutions/python/04-concurrent-clients/explanation.md deleted file mode 100644 index f477c920..00000000 --- a/solutions/python/04-concurrent-clients/explanation.md +++ /dev/null @@ -1,29 +0,0 @@ -Stage 4 is an entry into using threads in Python. To get a primer, [read here](https://realpython.com/intro-to-python-threading/). - -We're now going to respond to `PING` requests from multiple clients, concurrently. - -Let's start by moving our responder into its own function. It needs a connection object as argument. - -```go -def handle_connection(client_connection): - while True: - try: - client_connection.recv(1024) # wait for client to send data - client_connection.send(b"+PONG\r\n") - except ConnectionError: - break # Stop serving if the client connection is closed -``` - -Note that we've also added some error handling so that the loop terminates if a client disconnects. - -Within `main`, we'll now use a `while` loop to accept multiple connections. For each client connection that we accept, -we'll spawn a thread that handles the connection. - -Using threads makes the program able to accept and handle new incoming connections in parallel, instead of -blocking the program by sequentially handling one connection at a time. - -```go -while True: - client_connection, _ = server_socket.accept() # wait for client - threading.Thread(target=handle_connection, args=(client_connection,)).start() -``` diff --git a/solutions/python/05-echo/code/README.md b/solutions/python/05-echo/code/README.md deleted file mode 100644 index 17b2ec10..00000000 --- a/solutions/python/05-echo/code/README.md +++ /dev/null @@ -1,61 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Python solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `app/main.py`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `python (3.x)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `app/main.py`. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. - -# Troubleshooting - -## module `socket` has no attribute `create_server` - -When running your server locally, you might see an error like this: - -``` -Traceback (most recent call last): - File "/.../python3.7/runpy.py", line 193, in _run_module_as_main - "__main__", mod_spec) - File "/.../python3.7/runpy.py", line 85, in _run_code - exec(code, run_globals) - File "/app/app/main.py", line 11, in - main() - File "/app/app/main.py", line 6, in main - s = socket.create_server(("localhost", 6379), reuse_port=True) -AttributeError: module 'socket' has no attribute 'create_server' -``` - -This is because `socket.create_server` was introduced in Python 3.8, and you -might be running an older version. - -You can fix this by installing Python 3.8 locally and using that. - -If you'd like to use a different version of Python, change the `language_pack` -value in `codecrafters.yml`. diff --git a/solutions/python/05-echo/code/app/main.py b/solutions/python/05-echo/code/app/main.py deleted file mode 100644 index 61369ddd..00000000 --- a/solutions/python/05-echo/code/app/main.py +++ /dev/null @@ -1,31 +0,0 @@ -import threading -import socket - -from .resp_decoder import RESPDecoder - - -def handle_connection(client_connection): - while True: - try: - command, *args = RESPDecoder(client_connection).decode() - - if command == b"ping": - client_connection.send(b"+PONG\r\n") - elif command == b"echo": - client_connection.send(b"$%d\r\n%b\r\n" % (len(args[0]), args[0])) - else: - client_connection.send(b"-ERR unknown command\r\n") - except ConnectionError: - break # Stop serving if the client connection is closed - - -def main(): - server_socket = socket.create_server(("localhost", 6379), reuse_port=True) - - while True: - client_connection, _ = server_socket.accept() # wait for client - threading.Thread(target=handle_connection, args=(client_connection,)).start() - - -if __name__ == "__main__": - main() diff --git a/solutions/python/05-echo/code/app/resp_decoder.py b/solutions/python/05-echo/code/app/resp_decoder.py deleted file mode 100644 index 18eea8fe..00000000 --- a/solutions/python/05-echo/code/app/resp_decoder.py +++ /dev/null @@ -1,64 +0,0 @@ -# ConnectionBuffer wraps socket.Socket and adds support for reading until a delimiter. -class ConnectionBuffer: - def __init__(self, connection): - self.connection = connection - self.buffer = b'' - - def read_until_delimiter(self, delimiter): - while delimiter not in self.buffer: - data = self.connection.recv(1024) - - if not data: # socket closed - return None - - self.buffer += data - - data_before_delimiter, delimiter, self.buffer = self.buffer.partition(delimiter) - return data_before_delimiter - - def read(self, bufsize): - if len(self.buffer) < bufsize: - data = self.connection.recv(1024) - - if not data: # socket closed - return None - - self.buffer += data - - data, self.buffer = self.buffer[:bufsize], self.buffer[bufsize:] - return data - - -class RESPDecoder: - def __init__(self, connection): - self.connection = ConnectionBuffer(connection) - - def decode(self): - data_type_byte = self.connection.read(1) - - if data_type_byte == b"+": - return self.decode_simple_string() - elif data_type_byte == b"$": - return self.decode_bulk_string() - elif data_type_byte == b"*": - return self.decode_array() - else: - raise Exception(f"Unknown data type byte: {data_type_byte}") - - def decode_simple_string(self): - return self.connection.read_until_delimiter(b"\r\n") - - def decode_bulk_string(self): - bulk_string_length = int(self.connection.read_until_delimiter(b"\r\n")) - data = self.connection.read(bulk_string_length) - assert self.connection.read_until_delimiter(b"\r\n") == b"" # delimiter should be immediately after string - return data - - def decode_array(self): - result = [] - array_length = int(self.connection.read_until_delimiter(b"\r\n")) - - for _ in range(array_length): - result.append(self.decode()) - - return result diff --git a/solutions/python/05-echo/code/codecrafters.yml b/solutions/python/05-echo/code/codecrafters.yml deleted file mode 100644 index 7ff8fea5..00000000 --- a/solutions/python/05-echo/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Python version used to run your code -# on Codecrafters. -# -# Available versions: python-3.11 -language_pack: python-3.11 diff --git a/solutions/python/05-echo/code/spawn_redis_server.sh b/solutions/python/05-echo/code/spawn_redis_server.sh deleted file mode 100755 index d7d3afd8..00000000 --- a/solutions/python/05-echo/code/spawn_redis_server.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec python3 -m app.main diff --git a/solutions/python/05-echo/definition.yml b/solutions/python/05-echo/definition.yml deleted file mode 100644 index 7c3663f8..00000000 --- a/solutions/python/05-echo/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/26 diff --git a/solutions/python/05-echo/diff/app/main.py.diff b/solutions/python/05-echo/diff/app/main.py.diff deleted file mode 100644 index 26737322..00000000 --- a/solutions/python/05-echo/diff/app/main.py.diff +++ /dev/null @@ -1,34 +0,0 @@ -@@ -1,23 +1,31 @@ - import threading - import socket - -+from .resp_decoder import RESPDecoder -+ - - def handle_connection(client_connection): - while True: - try: -- client_connection.recv(1024) # wait for client to send data -- client_connection.send(b"+PONG\r\n") -+ command, *args = RESPDecoder(client_connection).decode() -+ -+ if command == b"ping": -+ client_connection.send(b"+PONG\r\n") -+ elif command == b"echo": -+ client_connection.send(b"$%d\r\n%b\r\n" % (len(args[0]), args[0])) -+ else: -+ client_connection.send(b"-ERR unknown command\r\n") - except ConnectionError: - break # Stop serving if the client connection is closed - - - def main(): - server_socket = socket.create_server(("localhost", 6379), reuse_port=True) - - while True: - client_connection, _ = server_socket.accept() # wait for client - threading.Thread(target=handle_connection, args=(client_connection,)).start() - - - if __name__ == "__main__": - main() diff --git a/solutions/python/05-echo/diff/app/resp_decoder.py.diff b/solutions/python/05-echo/diff/app/resp_decoder.py.diff deleted file mode 100644 index 22b46743..00000000 --- a/solutions/python/05-echo/diff/app/resp_decoder.py.diff +++ /dev/null @@ -1,65 +0,0 @@ -@@ -0,0 +1,64 @@ -+# ConnectionBuffer wraps socket.Socket and adds support for reading until a delimiter. -+class ConnectionBuffer: -+ def __init__(self, connection): -+ self.connection = connection -+ self.buffer = b'' -+ -+ def read_until_delimiter(self, delimiter): -+ while delimiter not in self.buffer: -+ data = self.connection.recv(1024) -+ -+ if not data: # socket closed -+ return None -+ -+ self.buffer += data -+ -+ data_before_delimiter, delimiter, self.buffer = self.buffer.partition(delimiter) -+ return data_before_delimiter -+ -+ def read(self, bufsize): -+ if len(self.buffer) < bufsize: -+ data = self.connection.recv(1024) -+ -+ if not data: # socket closed -+ return None -+ -+ self.buffer += data -+ -+ data, self.buffer = self.buffer[:bufsize], self.buffer[bufsize:] -+ return data -+ -+ -+class RESPDecoder: -+ def __init__(self, connection): -+ self.connection = ConnectionBuffer(connection) -+ -+ def decode(self): -+ data_type_byte = self.connection.read(1) -+ -+ if data_type_byte == b"+": -+ return self.decode_simple_string() -+ elif data_type_byte == b"$": -+ return self.decode_bulk_string() -+ elif data_type_byte == b"*": -+ return self.decode_array() -+ else: -+ raise Exception(f"Unknown data type byte: {data_type_byte}") -+ -+ def decode_simple_string(self): -+ return self.connection.read_until_delimiter(b"\r\n") -+ -+ def decode_bulk_string(self): -+ bulk_string_length = int(self.connection.read_until_delimiter(b"\r\n")) -+ data = self.connection.read(bulk_string_length) -+ assert self.connection.read_until_delimiter(b"\r\n") == b"" # delimiter should be immediately after string -+ return data -+ -+ def decode_array(self): -+ result = [] -+ array_length = int(self.connection.read_until_delimiter(b"\r\n")) -+ -+ for _ in range(array_length): -+ result.append(self.decode()) -+ -+ return result diff --git a/solutions/python/05-echo/explanation.md b/solutions/python/05-echo/explanation.md deleted file mode 100644 index 9e8a693d..00000000 --- a/solutions/python/05-echo/explanation.md +++ /dev/null @@ -1,55 +0,0 @@ -In Stage 5, we explore streams processing. - -In previous stages, the incoming client requests were always `PING`, and so we were able to hardcode our responses -as `PONG`. Adding support for `ECHO` means that we first need to determine whether the incoming request is an `ECHO` -or a `PING`. We also need to be able to read the argument provided to `ECHO`, in order to use it in the response. - -Since the entire communication follows RESP, we also need to build a decoder for parsing the incoming request, and -an encoder for delivering the response. You can review the complete implementation in the Diff tab — in this -guide we'll highlight the key areas to pay attention to. - -We'll decode and capture the request within `command` & `args`. The decoding will be handled by `RESPDecoder`, a utility -class we'll create separately. - -```python -command, *args = RESPDecoder(client_connection).decode() -``` - -We check the decoded value to see if the command was a `PING` or an `ECHO`. If `PING`, we reuse our response from -the previous stages. We'll look at `ECHO` separately. If neither, we send a -[RESP error response](https://redis.io/docs/reference/protocol-spec/#resp-errors). - -```python -if command == b"ping": - client_connection.send(b"+PONG\r\n") -elif command == b"echo": - // Handle ECHO - pass -else: - client_connection.send(b"-ERR unknown command\r\n") -``` - -For `ECHO`, we send back the first argument as a RESP-encoded bulk string. - -```python -elif command == b"echo": - client_connection.send(b"$%d\r\n%b\r\n" % (len(args[0]), args[0])) -``` - -In the solution for this stage, you'll find that we've created a separate utility file for functions related to -RESP. The key function in it is `decode()`. This function reads the first byte from the input and then calls other -functions as needed. - -```python -def decode(self): - data_type_byte = self.connection.read(1) - - if data_type_byte == b"+": - return self.decode_simple_string() - elif data_type_byte == b"$": - return self.decode_bulk_string() - elif data_type_byte == b"*": - return self.decode_array() - else: - raise Exception(f"Unknown data type byte: {data_type_byte}") -``` diff --git a/solutions/rust/02-ping-pong/code/.gitignore b/solutions/rust/02-ping-pong/code/.gitignore deleted file mode 100644 index 73fab072..00000000 --- a/solutions/rust/02-ping-pong/code/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb diff --git a/solutions/rust/02-ping-pong/code/Cargo.lock b/solutions/rust/02-ping-pong/code/Cargo.lock deleted file mode 100644 index e337d056..00000000 --- a/solutions/rust/02-ping-pong/code/Cargo.lock +++ /dev/null @@ -1,351 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91f1f46651137be86f3a2b9a8359f9ab421d04d941c62b5982e1ca21113adf9" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -dependencies = [ - "libc", -] - -[[package]] -name = "libc" -version = "0.2.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redis-starter-rust" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "thiserror", - "tokio", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "signal-hook-registry" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "thiserror" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/solutions/rust/02-ping-pong/code/Cargo.toml b/solutions/rust/02-ping-pong/code/Cargo.toml deleted file mode 100644 index 157cbb7f..00000000 --- a/solutions/rust/02-ping-pong/code/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[package] -name = "redis-starter-rust" -version = "0.1.0" -authors = ["Codecrafters "] -edition = "2021" - -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[dependencies] -anyhow = "1.0.59" # error handling -bytes = "1.3.0" # helps manage buffers -thiserror = "1.0.32" # error handling -tokio = { version = "1.23.0", features = ["full"] } # async networking diff --git a/solutions/rust/02-ping-pong/code/README.md b/solutions/rust/02-ping-pong/code/README.md deleted file mode 100644 index bc38e7b7..00000000 --- a/solutions/rust/02-ping-pong/code/README.md +++ /dev/null @@ -1,35 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Rust solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `src/main.rs`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `cargo (1.54)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `src/main.rs`. This command compiles your Rust project, so it might be - slow the first time you run it. Subsequent runs will be fast. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/rust/02-ping-pong/code/codecrafters.yml b/solutions/rust/02-ping-pong/code/codecrafters.yml deleted file mode 100644 index 5adf6b91..00000000 --- a/solutions/rust/02-ping-pong/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Rust version used to run your code -# on Codecrafters. -# -# Available versions: rust-1.70 -language_pack: rust-1.70 diff --git a/solutions/rust/02-ping-pong/code/spawn_redis_server.sh b/solutions/rust/02-ping-pong/code/spawn_redis_server.sh deleted file mode 100755 index daf001a9..00000000 --- a/solutions/rust/02-ping-pong/code/spawn_redis_server.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec cargo run \ - --quiet \ - --release \ - --target-dir=/tmp/codecrafters-redis-target \ - --manifest-path $(dirname $0)/Cargo.toml "$@" diff --git a/solutions/rust/02-ping-pong/code/src/main.rs b/solutions/rust/02-ping-pong/code/src/main.rs deleted file mode 100644 index aa381a49..00000000 --- a/solutions/rust/02-ping-pong/code/src/main.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::io::{Read, Write}; -use std::net::TcpListener; - -fn main() { - let listener = TcpListener::bind("127.0.0.1:6379").unwrap(); - - for stream in listener.incoming() { - match stream { - Ok(mut stream) => { - println!("accepted new connection"); - - // Wait for the client to send us a message but ignore the content for now - let mut buf = [0; 512]; - stream.read(&mut buf).unwrap(); - - stream.write("+PONG\r\n".as_bytes()).unwrap(); - } - Err(e) => { - println!("error: {}", e); - } - } - } -} diff --git a/solutions/rust/02-ping-pong/definition.yml b/solutions/rust/02-ping-pong/definition.yml deleted file mode 100644 index 3d3297fc..00000000 --- a/solutions/rust/02-ping-pong/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -reviewers_details: -- name: Juan Campa - profile_url: https://twitter.com/juancampa - avatar_url: https://github.com/juancampa.png - headline: Chromium Hacker @ Mighty -pull_request_url: https://github.com/codecrafters-io/build-your-own-redis/pull/47 diff --git a/solutions/rust/02-ping-pong/diff/src/main.rs.diff b/solutions/rust/02-ping-pong/diff/src/main.rs.diff deleted file mode 100644 index 44e1d6b4..00000000 --- a/solutions/rust/02-ping-pong/diff/src/main.rs.diff +++ /dev/null @@ -1,25 +0,0 @@ -@@ -1,16 +1,23 @@ -+use std::io::{Read, Write}; - use std::net::TcpListener; - - fn main() { - let listener = TcpListener::bind("127.0.0.1:6379").unwrap(); - - for stream in listener.incoming() { - match stream { -- Ok(_stream) => { -+ Ok(mut stream) => { - println!("accepted new connection"); -+ -+ // Wait for the client to send us a message but ignore the content for now -+ let mut buf = [0; 512]; -+ stream.read(&mut buf).unwrap(); -+ -+ stream.write("+PONG\r\n".as_bytes()).unwrap(); - } - Err(e) => { - println!("error: {}", e); - } - } - } - } diff --git a/solutions/rust/02-ping-pong/explanation.md b/solutions/rust/02-ping-pong/explanation.md deleted file mode 100644 index d8df5e83..00000000 --- a/solutions/rust/02-ping-pong/explanation.md +++ /dev/null @@ -1,36 +0,0 @@ -Stage 2 is an exercise in reading and responding to requests with `TcpStream`. The official documentation [is here](https://doc.rust-lang.org/std/net/struct.TcpStream.html). - -In the first stage, we were just printing a message when a client connected and ignoring the TCP connection (`_stream`). - -```rust -Ok(_stream) => { - println!("accepted new connection"); -} -``` - -As we go further, we want to actually parse the incoming request, and respond suitably. Since we know that the -client only sends us `PING` at the moment, we can hardcode our response. - -First, we stop ignoring the connection and make it mutable so that we can write to it. - -```rust -Ok(mut stream) => { - println!("accepted new connection"); -} -``` - -For this stage, we know that the tester _only_ sends us `PING`, so we don't have to parse the incoming data. We should read it though, so that we wait for the client to send a message before we respond. To do that we create a buffer to hold the incoming message and read into it - -```rust -let mut buf = [0; 512]; -stream.read(&mut buf).unwrap(); -``` - -As mentioned in the stage instructions, we need to encode the response as a -[RESP Simple String](https://redis.io/docs/reference/protocol-spec/#resp-simple-strings). The ideal approach is to -create a RESP encoder function — but for now, since we know that our response will always be `PONG`, we can hardcode -the response. We will create the function in the upcoming stages. - -```rust -stream.write("+PONG\r\n".as_bytes()).unwrap(); -``` diff --git a/solutions/rust/03-ping-pong-multiple/code/.gitignore b/solutions/rust/03-ping-pong-multiple/code/.gitignore deleted file mode 100644 index 73fab072..00000000 --- a/solutions/rust/03-ping-pong-multiple/code/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb diff --git a/solutions/rust/03-ping-pong-multiple/code/Cargo.lock b/solutions/rust/03-ping-pong-multiple/code/Cargo.lock deleted file mode 100644 index e337d056..00000000 --- a/solutions/rust/03-ping-pong-multiple/code/Cargo.lock +++ /dev/null @@ -1,351 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91f1f46651137be86f3a2b9a8359f9ab421d04d941c62b5982e1ca21113adf9" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -dependencies = [ - "libc", -] - -[[package]] -name = "libc" -version = "0.2.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redis-starter-rust" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "thiserror", - "tokio", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "signal-hook-registry" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "thiserror" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/solutions/rust/03-ping-pong-multiple/code/Cargo.toml b/solutions/rust/03-ping-pong-multiple/code/Cargo.toml deleted file mode 100644 index 157cbb7f..00000000 --- a/solutions/rust/03-ping-pong-multiple/code/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[package] -name = "redis-starter-rust" -version = "0.1.0" -authors = ["Codecrafters "] -edition = "2021" - -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[dependencies] -anyhow = "1.0.59" # error handling -bytes = "1.3.0" # helps manage buffers -thiserror = "1.0.32" # error handling -tokio = { version = "1.23.0", features = ["full"] } # async networking diff --git a/solutions/rust/03-ping-pong-multiple/code/README.md b/solutions/rust/03-ping-pong-multiple/code/README.md deleted file mode 100644 index bc38e7b7..00000000 --- a/solutions/rust/03-ping-pong-multiple/code/README.md +++ /dev/null @@ -1,35 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Rust solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `src/main.rs`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `cargo (1.54)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `src/main.rs`. This command compiles your Rust project, so it might be - slow the first time you run it. Subsequent runs will be fast. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/rust/03-ping-pong-multiple/code/codecrafters.yml b/solutions/rust/03-ping-pong-multiple/code/codecrafters.yml deleted file mode 100644 index 5adf6b91..00000000 --- a/solutions/rust/03-ping-pong-multiple/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Rust version used to run your code -# on Codecrafters. -# -# Available versions: rust-1.70 -language_pack: rust-1.70 diff --git a/solutions/rust/03-ping-pong-multiple/code/spawn_redis_server.sh b/solutions/rust/03-ping-pong-multiple/code/spawn_redis_server.sh deleted file mode 100755 index daf001a9..00000000 --- a/solutions/rust/03-ping-pong-multiple/code/spawn_redis_server.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec cargo run \ - --quiet \ - --release \ - --target-dir=/tmp/codecrafters-redis-target \ - --manifest-path $(dirname $0)/Cargo.toml "$@" diff --git a/solutions/rust/03-ping-pong-multiple/code/src/main.rs b/solutions/rust/03-ping-pong-multiple/code/src/main.rs deleted file mode 100644 index da762746..00000000 --- a/solutions/rust/03-ping-pong-multiple/code/src/main.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::io::{Read, Write}; -use std::net::TcpListener; - -fn main() { - let listener = TcpListener::bind("127.0.0.1:6379").unwrap(); - - for stream in listener.incoming() { - match stream { - Ok(mut stream) => { - println!("accepted new connection"); - - let mut buf = [0; 512]; - - loop { - // Wait for the client to send us a message but ignore the content for now - let bytes_read = stream.read(&mut buf).unwrap(); - if bytes_read == 0 { - println!("client closed the connection"); - break; - } - - stream.write("+PONG\r\n".as_bytes()).unwrap(); - } - } - Err(e) => { - println!("error: {}", e); - } - } - } -} diff --git a/solutions/rust/03-ping-pong-multiple/definition.yml b/solutions/rust/03-ping-pong-multiple/definition.yml deleted file mode 100755 index 6b505942..00000000 --- a/solutions/rust/03-ping-pong-multiple/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -#pull_request_url: "https://github.com/codecrafters-io/build-your-own-/pull/" diff --git a/solutions/rust/03-ping-pong-multiple/diff/src/main.rs.diff b/solutions/rust/03-ping-pong-multiple/diff/src/main.rs.diff deleted file mode 100644 index 4c2adcad..00000000 --- a/solutions/rust/03-ping-pong-multiple/diff/src/main.rs.diff +++ /dev/null @@ -1,34 +0,0 @@ -@@ -1,23 +1,30 @@ - use std::io::{Read, Write}; - use std::net::TcpListener; - - fn main() { - let listener = TcpListener::bind("127.0.0.1:6379").unwrap(); - - for stream in listener.incoming() { - match stream { - Ok(mut stream) => { - println!("accepted new connection"); - -- // Wait for the client to send us a message but ignore the content for now - let mut buf = [0; 512]; -- stream.read(&mut buf).unwrap(); - -- stream.write("+PONG\r\n".as_bytes()).unwrap(); -+ loop { -+ // Wait for the client to send us a message but ignore the content for now -+ let bytes_read = stream.read(&mut buf).unwrap(); -+ if bytes_read == 0 { -+ println!("client closed the connection"); -+ break; -+ } -+ -+ stream.write("+PONG\r\n".as_bytes()).unwrap(); -+ } - } - Err(e) => { - println!("error: {}", e); - } - } - } - } diff --git a/solutions/rust/03-ping-pong-multiple/explanation.md b/solutions/rust/03-ping-pong-multiple/explanation.md deleted file mode 100644 index 981af411..00000000 --- a/solutions/rust/03-ping-pong-multiple/explanation.md +++ /dev/null @@ -1,25 +0,0 @@ -Stage 3 builds on our progress from Stage 2. - -Earlier, we were anticipating a single `PING` request, and were accordingly responding back with a single `PONG`. - -As an improvement, we'll now monitor for more incoming requests — and each time we get one, we'll respond back with -`PONG`, and go back to waiting for the next one. We can achieve this with an infinite `loop`. - -```rust -let mut buf = [0; 512]; - -loop { - // Wait for the client to send us a message but ignore the content for now - let bytes_read = stream.read(&mut buf).unwrap(); - if bytes_read == 0 { - println!("client closed the connection"); - break; - } - - stream.write("+PONG\r\n".as_bytes()).unwrap(); -} -``` - -While this approach gets us through the stage, notice how our program is now blocked on the for loop as it waits -for incoming requests. During this time, the program cannot do anything else (including accepting connections from -other clients). We'll get around that in the next stage when we tackle concurrent requests. diff --git a/solutions/rust/04-concurrent-clients/code/.gitignore b/solutions/rust/04-concurrent-clients/code/.gitignore deleted file mode 100644 index 73fab072..00000000 --- a/solutions/rust/04-concurrent-clients/code/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb diff --git a/solutions/rust/04-concurrent-clients/code/Cargo.lock b/solutions/rust/04-concurrent-clients/code/Cargo.lock deleted file mode 100644 index e337d056..00000000 --- a/solutions/rust/04-concurrent-clients/code/Cargo.lock +++ /dev/null @@ -1,351 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91f1f46651137be86f3a2b9a8359f9ab421d04d941c62b5982e1ca21113adf9" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -dependencies = [ - "libc", -] - -[[package]] -name = "libc" -version = "0.2.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redis-starter-rust" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "thiserror", - "tokio", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "signal-hook-registry" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "thiserror" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/solutions/rust/04-concurrent-clients/code/Cargo.toml b/solutions/rust/04-concurrent-clients/code/Cargo.toml deleted file mode 100644 index 157cbb7f..00000000 --- a/solutions/rust/04-concurrent-clients/code/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[package] -name = "redis-starter-rust" -version = "0.1.0" -authors = ["Codecrafters "] -edition = "2021" - -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[dependencies] -anyhow = "1.0.59" # error handling -bytes = "1.3.0" # helps manage buffers -thiserror = "1.0.32" # error handling -tokio = { version = "1.23.0", features = ["full"] } # async networking diff --git a/solutions/rust/04-concurrent-clients/code/README.md b/solutions/rust/04-concurrent-clients/code/README.md deleted file mode 100644 index bc38e7b7..00000000 --- a/solutions/rust/04-concurrent-clients/code/README.md +++ /dev/null @@ -1,35 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Rust solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `src/main.rs`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `cargo (1.54)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `src/main.rs`. This command compiles your Rust project, so it might be - slow the first time you run it. Subsequent runs will be fast. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/rust/04-concurrent-clients/code/codecrafters.yml b/solutions/rust/04-concurrent-clients/code/codecrafters.yml deleted file mode 100644 index 5adf6b91..00000000 --- a/solutions/rust/04-concurrent-clients/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Rust version used to run your code -# on Codecrafters. -# -# Available versions: rust-1.70 -language_pack: rust-1.70 diff --git a/solutions/rust/04-concurrent-clients/code/spawn_redis_server.sh b/solutions/rust/04-concurrent-clients/code/spawn_redis_server.sh deleted file mode 100755 index daf001a9..00000000 --- a/solutions/rust/04-concurrent-clients/code/spawn_redis_server.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec cargo run \ - --quiet \ - --release \ - --target-dir=/tmp/codecrafters-redis-target \ - --manifest-path $(dirname $0)/Cargo.toml "$@" diff --git a/solutions/rust/04-concurrent-clients/code/src/main.rs b/solutions/rust/04-concurrent-clients/code/src/main.rs deleted file mode 100644 index 131f1efc..00000000 --- a/solutions/rust/04-concurrent-clients/code/src/main.rs +++ /dev/null @@ -1,41 +0,0 @@ -use anyhow::Result; -use bytes::BytesMut; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::{TcpListener, TcpStream}; - -#[tokio::main] -async fn main() -> Result<()> { - let listener = TcpListener::bind("127.0.0.1:6379").await?; - - loop { - let incoming = listener.accept().await; - match incoming { - Ok((stream, _)) => { - println!("accepted new connection"); - tokio::spawn(async move { - handle_connection(stream).await.unwrap(); - }); - } - Err(e) => { - println!("error: {}", e); - } - } - } -} - -async fn handle_connection(mut stream: TcpStream) -> Result<()> { - let mut buf = BytesMut::with_capacity(512); - - loop { - // Wait for the client to send us a message but ignore the content for now - let bytes_read = stream.read_buf(&mut buf).await?; - if bytes_read == 0 { - println!("client closed the connection"); - break; - } - - stream.write("+PONG\r\n".as_bytes()).await?; - } - - Ok(()) -} diff --git a/solutions/rust/04-concurrent-clients/definition.yml b/solutions/rust/04-concurrent-clients/definition.yml deleted file mode 100755 index 6b505942..00000000 --- a/solutions/rust/04-concurrent-clients/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -#pull_request_url: "https://github.com/codecrafters-io/build-your-own-/pull/" diff --git a/solutions/rust/04-concurrent-clients/diff/src/main.rs.diff b/solutions/rust/04-concurrent-clients/diff/src/main.rs.diff deleted file mode 100644 index 1d245bf2..00000000 --- a/solutions/rust/04-concurrent-clients/diff/src/main.rs.diff +++ /dev/null @@ -1,62 +0,0 @@ -@@ -1,30 +1,41 @@ --use std::io::{Read, Write}; --use std::net::TcpListener; -+use anyhow::Result; -+use bytes::BytesMut; -+use tokio::io::{AsyncReadExt, AsyncWriteExt}; -+use tokio::net::{TcpListener, TcpStream}; - --fn main() { -- let listener = TcpListener::bind("127.0.0.1:6379").unwrap(); -+#[tokio::main] -+async fn main() -> Result<()> { -+ let listener = TcpListener::bind("127.0.0.1:6379").await?; - -- for stream in listener.incoming() { -- match stream { -- Ok(mut stream) => { -+ loop { -+ let incoming = listener.accept().await; -+ match incoming { -+ Ok((stream, _)) => { - println!("accepted new connection"); -- -- let mut buf = [0; 512]; -- -- loop { -- // Wait for the client to send us a message but ignore the content for now -- let bytes_read = stream.read(&mut buf).unwrap(); -- if bytes_read == 0 { -- println!("client closed the connection"); -- break; -- } -- -- stream.write("+PONG\r\n".as_bytes()).unwrap(); -- } -+ tokio::spawn(async move { -+ handle_connection(stream).await.unwrap(); -+ }); - } - Err(e) => { - println!("error: {}", e); - } - } - } - } -+ -+async fn handle_connection(mut stream: TcpStream) -> Result<()> { -+ let mut buf = BytesMut::with_capacity(512); -+ -+ loop { -+ // Wait for the client to send us a message but ignore the content for now -+ let bytes_read = stream.read_buf(&mut buf).await?; -+ if bytes_read == 0 { -+ println!("client closed the connection"); -+ break; -+ } -+ -+ stream.write("+PONG\r\n".as_bytes()).await?; -+ } -+ -+ Ok(()) -+} diff --git a/solutions/rust/04-concurrent-clients/explanation.md b/solutions/rust/04-concurrent-clients/explanation.md deleted file mode 100644 index 3d89899e..00000000 --- a/solutions/rust/04-concurrent-clients/explanation.md +++ /dev/null @@ -1,61 +0,0 @@ -Stage 4 requires switching to Tokio so that we can handle multiple clients concurrently. There is an official tutorial for Tokio [to get you started](https://tokio.rs/tokio/tutorial). - -Let's start by moving our responder into its own function. It needs a `TcpStream` as an argument. - -```rust -async fn handle_connection(stream: &mut TcpStream) -> Result<()> { - let mut buf = [0; 512]; - - loop { - // Wait for the client to send us a message but ignore the content for now - let bytes_read = stream.read(&mut buf).await?; - if bytes_read == 0 { - println!("client closed the connection"); - break; - } - - stream.write("+PONG\r\n".as_bytes()).await?; - } - - Ok(()) -} -``` - -Notice that the `handle_connection` function is marked as `async` and the `read`/`write` calls are `await`ed. These changes allow Tokio to suspend and resume our connection handler at the right times, and do work on tasks for other clients while ours is suspended. - -We need to annotate the `main` function with `#[tokio::main]` to let Tokio start a runtime before our main function does any work. - -```rust -#[tokio::main] -async fn main() -> Result<()> { - // ... -} -``` - -Within `main`, we'll now use a `loop` to accept multiple connections. For each client connection that we accept, we'll -spawn a task that handles the connection. - -```rust -#[tokio::main] -async fn main() -> Result<()> { - let mut listener = TcpListener::bind("127.0.0.1:6379").await?; - - loop { - let incoming = listener.accept().await; - match incoming { - Ok((mut stream, _)) => { - println!("accepted new connection"); - tokio::spawn(async move { - handle_connection(&mut stream).await.unwrap(); - }); - } - Err(e) => { - println!("error: {}", e); - } - } - } -} -``` - -Using a tokio task, with `tokio::spawn`, makes the program able to accept and handle new incoming connections in parallel, instead of -blocking the program by sequentially handling one connection at a time. diff --git a/solutions/rust/05-echo/code/.gitignore b/solutions/rust/05-echo/code/.gitignore deleted file mode 100644 index 73fab072..00000000 --- a/solutions/rust/05-echo/code/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb diff --git a/solutions/rust/05-echo/code/Cargo.lock b/solutions/rust/05-echo/code/Cargo.lock deleted file mode 100644 index e337d056..00000000 --- a/solutions/rust/05-echo/code/Cargo.lock +++ /dev/null @@ -1,351 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91f1f46651137be86f3a2b9a8359f9ab421d04d941c62b5982e1ca21113adf9" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -dependencies = [ - "libc", -] - -[[package]] -name = "libc" -version = "0.2.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redis-starter-rust" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "thiserror", - "tokio", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "signal-hook-registry" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "thiserror" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/solutions/rust/05-echo/code/Cargo.toml b/solutions/rust/05-echo/code/Cargo.toml deleted file mode 100644 index 157cbb7f..00000000 --- a/solutions/rust/05-echo/code/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[package] -name = "redis-starter-rust" -version = "0.1.0" -authors = ["Codecrafters "] -edition = "2021" - -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[dependencies] -anyhow = "1.0.59" # error handling -bytes = "1.3.0" # helps manage buffers -thiserror = "1.0.32" # error handling -tokio = { version = "1.23.0", features = ["full"] } # async networking diff --git a/solutions/rust/05-echo/code/README.md b/solutions/rust/05-echo/code/README.md deleted file mode 100644 index bc38e7b7..00000000 --- a/solutions/rust/05-echo/code/README.md +++ /dev/null @@ -1,35 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Rust solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `src/main.rs`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `cargo (1.54)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `src/main.rs`. This command compiles your Rust project, so it might be - slow the first time you run it. Subsequent runs will be fast. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/rust/05-echo/code/codecrafters.yml b/solutions/rust/05-echo/code/codecrafters.yml deleted file mode 100644 index 5adf6b91..00000000 --- a/solutions/rust/05-echo/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Rust version used to run your code -# on Codecrafters. -# -# Available versions: rust-1.70 -language_pack: rust-1.70 diff --git a/solutions/rust/05-echo/code/spawn_redis_server.sh b/solutions/rust/05-echo/code/spawn_redis_server.sh deleted file mode 100755 index daf001a9..00000000 --- a/solutions/rust/05-echo/code/spawn_redis_server.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec cargo run \ - --quiet \ - --release \ - --target-dir=/tmp/codecrafters-redis-target \ - --manifest-path $(dirname $0)/Cargo.toml "$@" diff --git a/solutions/rust/05-echo/code/src/main.rs b/solutions/rust/05-echo/code/src/main.rs deleted file mode 100644 index cb7c3380..00000000 --- a/solutions/rust/05-echo/code/src/main.rs +++ /dev/null @@ -1,48 +0,0 @@ -use anyhow::Result; -use resp::Value::{Error, SimpleString}; -use tokio::net::{TcpListener, TcpStream}; - -mod resp; - -#[tokio::main] -async fn main() -> Result<()> { - let listener = TcpListener::bind("127.0.0.1:6379").await?; - - loop { - let incoming = listener.accept().await; - match incoming { - Ok((stream, _)) => { - println!("accepted new connection"); - tokio::spawn(async move { - handle_connection(stream).await.unwrap(); - }); - } - Err(e) => { - println!("error: {}", e); - } - } - } -} - -async fn handle_connection(stream: TcpStream) -> Result<()> { - let mut conn = resp::RespConnection::new(stream); - - loop { - let value = conn.read_value().await?; - - if let Some(value) = value { - let (command, args) = value.to_command()?; - let response = match command.to_ascii_lowercase().as_ref() { - "ping" => SimpleString("PONG".to_string()), - "echo" => args.first().unwrap().clone(), - _ => Error(format!("command not implemented: {}", command)), - }; - - conn.write_value(response).await?; - } else { - break; - } - } - - Ok(()) -} diff --git a/solutions/rust/05-echo/code/src/resp.rs b/solutions/rust/05-echo/code/src/resp.rs deleted file mode 100644 index 895eb38a..00000000 --- a/solutions/rust/05-echo/code/src/resp.rs +++ /dev/null @@ -1,167 +0,0 @@ -use anyhow::{Error, Result}; -use bytes::BytesMut; -use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpStream}; - -const CARRIAGE_RETURN: u8 = '\r' as u8; -const NEWLINE: u8 = '\n' as u8; - -#[derive(Eq, PartialEq, Clone, Debug)] -pub enum Value { - /// For Simple Strings the first byte of the reply is "+". - SimpleString(String), - /// For Errors the first byte of the reply is "-". - Error(String), - /// For Bulk Strings the first byte of the reply is "$". - BulkString(String), - /// For Arrays the first byte of the reply is "*". - Array(Vec), -} - -impl Value { - pub fn to_command(&self) -> Result<(String, Vec)> { - match self { - Value::Array(items) => { - return Ok(( - items.first().unwrap().unwrap_bulk(), - items.clone().into_iter().skip(1).collect(), - )); - } - _ => Err(Error::msg("not an array")), - } - } - - fn unwrap_bulk(&self) -> String { - match self { - Value::BulkString(str) => str.clone(), - _ => panic!("not a bulk string"), - } - } - - pub fn encode(self) -> String { - match &self { - Value::SimpleString(s) => format!("+{}\r\n", s.as_str()), - Value::Error(msg) => format!("-{}\r\n", msg.as_str()), - Value::BulkString(s) => format!("${}\r\n{}\r\n", s.chars().count(), s), - // The other cases are not required - _ => panic!("value encode not implemented for: {:?}", self), - } - } -} - -pub struct RespConnection { - stream: TcpStream, - buffer: BytesMut, -} - -impl RespConnection { - pub fn new(stream: TcpStream) -> Self { - return RespConnection { - stream, - buffer: BytesMut::with_capacity(512), - }; - } - - pub async fn read_value(&mut self) -> Result> { - loop { - let bytes_read = self.stream.read_buf(&mut self.buffer).await?; - - // Connection closed - if bytes_read == 0 { - return Ok(None); - } - - if let Some((value, _)) = parse_message(self.buffer.split())? { - return Ok(Some(value)); - } - } - } - - pub async fn write_value(&mut self, value: Value) -> Result<()> { - self.stream.write(value.encode().as_bytes()).await?; - - Ok(()) - } -} - -fn parse_message(buffer: BytesMut) -> Result> { - match buffer[0] as char { - '+' => decode_simple_string(buffer), - '*' => decode_array(buffer), - '$' => decode_bulk_string(buffer), - _ => Err(Error::msg("unrecognised message type")), - } -} - -fn decode_simple_string(buffer: BytesMut) -> Result> { - if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let str = parse_string(line)?; - - Ok(Some((Value::SimpleString(str), len + 1))) - } else { - Ok(None) - } -} - -fn decode_array(buffer: BytesMut) -> Result> { - let (array_length, mut bytes_consumed) = - if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let array_length = parse_integer(line)?; - - (array_length, len + 1) - } else { - return Ok(None); - }; - - let mut items: Vec = Vec::new(); - for _ in 0..array_length { - if let Some((v, len)) = parse_message(BytesMut::from(&buffer[bytes_consumed..]))? { - items.push(v); - bytes_consumed += len - } else { - return Ok(None); - } - } - - return Ok(Some((Value::Array(items), bytes_consumed))); -} - -fn decode_bulk_string(buffer: BytesMut) -> Result> { - let (bulk_length, bytes_consumed) = if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let bulk_length = parse_integer(line)?; - - (bulk_length, len + 1) - } else { - return Ok(None); - }; - - let end_of_bulk = bytes_consumed + (bulk_length as usize); - let end_of_bulk_line = end_of_bulk + 2; - - return if end_of_bulk_line <= buffer.len() { - Ok(Some(( - Value::BulkString(parse_string(&buffer[bytes_consumed..end_of_bulk])?), - end_of_bulk_line, - ))) - } else { - Ok(None) - }; -} - -fn read_until_crlf(buffer: &[u8]) -> Option<(&[u8], usize)> { - for i in 1..buffer.len() { - if buffer[i - 1] == CARRIAGE_RETURN && buffer[i] == NEWLINE { - return Some((&buffer[0..(i - 1)], i + 1)); - } - } - - return None; -} - -fn parse_string(bytes: &[u8]) -> Result { - String::from_utf8(bytes.to_vec()).map_err(|_| Error::msg("Could not parse string")) -} - -fn parse_integer(bytes: &[u8]) -> Result { - let str_integer = parse_string(bytes)?; - (str_integer.parse::()).map_err(|_| Error::msg("Could not parse integer")) -} diff --git a/solutions/rust/05-echo/definition.yml b/solutions/rust/05-echo/definition.yml deleted file mode 100755 index 6b505942..00000000 --- a/solutions/rust/05-echo/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -#pull_request_url: "https://github.com/codecrafters-io/build-your-own-/pull/" diff --git a/solutions/rust/05-echo/diff/src/main.rs.diff b/solutions/rust/05-echo/diff/src/main.rs.diff deleted file mode 100644 index 29e72716..00000000 --- a/solutions/rust/05-echo/diff/src/main.rs.diff +++ /dev/null @@ -1,59 +0,0 @@ -@@ -1,41 +1,48 @@ - use anyhow::Result; --use bytes::BytesMut; --use tokio::io::{AsyncReadExt, AsyncWriteExt}; -+use resp::Value::{Error, SimpleString}; - use tokio::net::{TcpListener, TcpStream}; - -+mod resp; -+ - #[tokio::main] - async fn main() -> Result<()> { - let listener = TcpListener::bind("127.0.0.1:6379").await?; - - loop { - let incoming = listener.accept().await; - match incoming { - Ok((stream, _)) => { - println!("accepted new connection"); - tokio::spawn(async move { - handle_connection(stream).await.unwrap(); - }); - } - Err(e) => { - println!("error: {}", e); - } - } - } - } - --async fn handle_connection(mut stream: TcpStream) -> Result<()> { -- let mut buf = BytesMut::with_capacity(512); -+async fn handle_connection(stream: TcpStream) -> Result<()> { -+ let mut conn = resp::RespConnection::new(stream); - - loop { -- // Wait for the client to send us a message but ignore the content for now -- let bytes_read = stream.read_buf(&mut buf).await?; -- if bytes_read == 0 { -- println!("client closed the connection"); -+ let value = conn.read_value().await?; -+ -+ if let Some(value) = value { -+ let (command, args) = value.to_command()?; -+ let response = match command.to_ascii_lowercase().as_ref() { -+ "ping" => SimpleString("PONG".to_string()), -+ "echo" => args.first().unwrap().clone(), -+ _ => Error(format!("command not implemented: {}", command)), -+ }; -+ -+ conn.write_value(response).await?; -+ } else { - break; - } -- -- stream.write("+PONG\r\n".as_bytes()).await?; - } - - Ok(()) - } diff --git a/solutions/rust/05-echo/diff/src/resp.rs.diff b/solutions/rust/05-echo/diff/src/resp.rs.diff deleted file mode 100644 index afc626c9..00000000 --- a/solutions/rust/05-echo/diff/src/resp.rs.diff +++ /dev/null @@ -1,168 +0,0 @@ -@@ -0,0 +1,167 @@ -+use anyhow::{Error, Result}; -+use bytes::BytesMut; -+use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpStream}; -+ -+const CARRIAGE_RETURN: u8 = '\r' as u8; -+const NEWLINE: u8 = '\n' as u8; -+ -+#[derive(Eq, PartialEq, Clone, Debug)] -+pub enum Value { -+ /// For Simple Strings the first byte of the reply is "+". -+ SimpleString(String), -+ /// For Errors the first byte of the reply is "-". -+ Error(String), -+ /// For Bulk Strings the first byte of the reply is "$". -+ BulkString(String), -+ /// For Arrays the first byte of the reply is "*". -+ Array(Vec), -+} -+ -+impl Value { -+ pub fn to_command(&self) -> Result<(String, Vec)> { -+ match self { -+ Value::Array(items) => { -+ return Ok(( -+ items.first().unwrap().unwrap_bulk(), -+ items.clone().into_iter().skip(1).collect(), -+ )); -+ } -+ _ => Err(Error::msg("not an array")), -+ } -+ } -+ -+ fn unwrap_bulk(&self) -> String { -+ match self { -+ Value::BulkString(str) => str.clone(), -+ _ => panic!("not a bulk string"), -+ } -+ } -+ -+ pub fn encode(self) -> String { -+ match &self { -+ Value::SimpleString(s) => format!("+{}\r\n", s.as_str()), -+ Value::Error(msg) => format!("-{}\r\n", msg.as_str()), -+ Value::BulkString(s) => format!("${}\r\n{}\r\n", s.chars().count(), s), -+ // The other cases are not required -+ _ => panic!("value encode not implemented for: {:?}", self), -+ } -+ } -+} -+ -+pub struct RespConnection { -+ stream: TcpStream, -+ buffer: BytesMut, -+} -+ -+impl RespConnection { -+ pub fn new(stream: TcpStream) -> Self { -+ return RespConnection { -+ stream, -+ buffer: BytesMut::with_capacity(512), -+ }; -+ } -+ -+ pub async fn read_value(&mut self) -> Result> { -+ loop { -+ let bytes_read = self.stream.read_buf(&mut self.buffer).await?; -+ -+ // Connection closed -+ if bytes_read == 0 { -+ return Ok(None); -+ } -+ -+ if let Some((value, _)) = parse_message(self.buffer.split())? { -+ return Ok(Some(value)); -+ } -+ } -+ } -+ -+ pub async fn write_value(&mut self, value: Value) -> Result<()> { -+ self.stream.write(value.encode().as_bytes()).await?; -+ -+ Ok(()) -+ } -+} -+ -+fn parse_message(buffer: BytesMut) -> Result> { -+ match buffer[0] as char { -+ '+' => decode_simple_string(buffer), -+ '*' => decode_array(buffer), -+ '$' => decode_bulk_string(buffer), -+ _ => Err(Error::msg("unrecognised message type")), -+ } -+} -+ -+fn decode_simple_string(buffer: BytesMut) -> Result> { -+ if let Some((line, len)) = read_until_crlf(&buffer[1..]) { -+ let str = parse_string(line)?; -+ -+ Ok(Some((Value::SimpleString(str), len + 1))) -+ } else { -+ Ok(None) -+ } -+} -+ -+fn decode_array(buffer: BytesMut) -> Result> { -+ let (array_length, mut bytes_consumed) = -+ if let Some((line, len)) = read_until_crlf(&buffer[1..]) { -+ let array_length = parse_integer(line)?; -+ -+ (array_length, len + 1) -+ } else { -+ return Ok(None); -+ }; -+ -+ let mut items: Vec = Vec::new(); -+ for _ in 0..array_length { -+ if let Some((v, len)) = parse_message(BytesMut::from(&buffer[bytes_consumed..]))? { -+ items.push(v); -+ bytes_consumed += len -+ } else { -+ return Ok(None); -+ } -+ } -+ -+ return Ok(Some((Value::Array(items), bytes_consumed))); -+} -+ -+fn decode_bulk_string(buffer: BytesMut) -> Result> { -+ let (bulk_length, bytes_consumed) = if let Some((line, len)) = read_until_crlf(&buffer[1..]) { -+ let bulk_length = parse_integer(line)?; -+ -+ (bulk_length, len + 1) -+ } else { -+ return Ok(None); -+ }; -+ -+ let end_of_bulk = bytes_consumed + (bulk_length as usize); -+ let end_of_bulk_line = end_of_bulk + 2; -+ -+ return if end_of_bulk_line <= buffer.len() { -+ Ok(Some(( -+ Value::BulkString(parse_string(&buffer[bytes_consumed..end_of_bulk])?), -+ end_of_bulk_line, -+ ))) -+ } else { -+ Ok(None) -+ }; -+} -+ -+fn read_until_crlf(buffer: &[u8]) -> Option<(&[u8], usize)> { -+ for i in 1..buffer.len() { -+ if buffer[i - 1] == CARRIAGE_RETURN && buffer[i] == NEWLINE { -+ return Some((&buffer[0..(i - 1)], i + 1)); -+ } -+ } -+ -+ return None; -+} -+ -+fn parse_string(bytes: &[u8]) -> Result { -+ String::from_utf8(bytes.to_vec()).map_err(|_| Error::msg("Could not parse string")) -+} -+ -+fn parse_integer(bytes: &[u8]) -> Result { -+ let str_integer = parse_string(bytes)?; -+ (str_integer.parse::()).map_err(|_| Error::msg("Could not parse integer")) -+} diff --git a/solutions/rust/05-echo/explanation.md b/solutions/rust/05-echo/explanation.md deleted file mode 100644 index 465281bb..00000000 --- a/solutions/rust/05-echo/explanation.md +++ /dev/null @@ -1,62 +0,0 @@ -In Stage 5, we explore streams processing. - -In previous stages, the incoming client requests were always `PING`, and so we were able to hardcode our responses -as `PONG`. Adding support for `ECHO` means that we first need to determine whether the incoming request is an `ECHO` -or a `PING`. We also need to be able to read the argument provided to `ECHO`, in order to use it in the response. - -Since the entire communication follows RESP, we also need to build a decoder for parsing the incoming request, and -an encoder for delivering the response. You can review the complete implementation in the Diff tab — in this -guide we'll highlight the key areas to pay attention to. - -There is a new module called `resp` which provides a `RespConnection`. This new struct handles the reading and -writing of messages from the TCP stream. Internally it reads from the socket until a complete input has been -received then gives us back the value so that we can decide what to do. The `handle_connection` function now becomes - - -```rust -async fn handle_connection(stream: TcpStream) -> Result<()> { - let mut conn = resp::RespConnection::new(stream); - - loop { - let value = conn.read_value().await?; - - // TODO check the value and respond - } - - Ok(()) -} -``` - -We assume that the incoming message will be represented as a `Value::Array` and use a utility function to get the -head of the array, the command, and tail of it, the arguments. We check the command to see if it was a `PING` or an `ECHO`. -If `PING`, we reuse our response from the previous stages. If `ECHO` we send back the first argument we received. -Otherwise, send back an error message. - -```rust -if let Some(value) = value { - let (command, args) = value.to_command()?; - let response = match command.to_ascii_lowercase().as_ref() { - "ping" => resp::Value::String("PONG".to_string()), - "echo" => args.first().unwrap().clone(), - _ => resp::Value::Error(format!("command not implemented: {}", command)) - }; - - conn.write_value(response).await?; -} else { - break; -} -``` - -You should review the `resp` module as needed but the key function is `parse_message`. This function reads the first byte from the input and then calls other functions as needed. - -```rust -fn parse_message(buffer: BytesMut) -> Result> { - match buffer[0] as char { - '+' => decode_simple_string(buffer), - '*' => decode_array(buffer), - '$' => decode_bulk_string(buffer), - _ => { - return Err(Error::msg("unrecognised message type")); - } - } -} -``` diff --git a/solutions/rust/06-set_get/code/.gitignore b/solutions/rust/06-set_get/code/.gitignore deleted file mode 100644 index 73fab072..00000000 --- a/solutions/rust/06-set_get/code/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb diff --git a/solutions/rust/06-set_get/code/Cargo.lock b/solutions/rust/06-set_get/code/Cargo.lock deleted file mode 100644 index e337d056..00000000 --- a/solutions/rust/06-set_get/code/Cargo.lock +++ /dev/null @@ -1,351 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91f1f46651137be86f3a2b9a8359f9ab421d04d941c62b5982e1ca21113adf9" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -dependencies = [ - "libc", -] - -[[package]] -name = "libc" -version = "0.2.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redis-starter-rust" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "thiserror", - "tokio", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "signal-hook-registry" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "thiserror" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/solutions/rust/06-set_get/code/Cargo.toml b/solutions/rust/06-set_get/code/Cargo.toml deleted file mode 100644 index 157cbb7f..00000000 --- a/solutions/rust/06-set_get/code/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[package] -name = "redis-starter-rust" -version = "0.1.0" -authors = ["Codecrafters "] -edition = "2021" - -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[dependencies] -anyhow = "1.0.59" # error handling -bytes = "1.3.0" # helps manage buffers -thiserror = "1.0.32" # error handling -tokio = { version = "1.23.0", features = ["full"] } # async networking diff --git a/solutions/rust/06-set_get/code/README.md b/solutions/rust/06-set_get/code/README.md deleted file mode 100644 index bc38e7b7..00000000 --- a/solutions/rust/06-set_get/code/README.md +++ /dev/null @@ -1,35 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Rust solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `src/main.rs`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `cargo (1.54)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `src/main.rs`. This command compiles your Rust project, so it might be - slow the first time you run it. Subsequent runs will be fast. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/rust/06-set_get/code/codecrafters.yml b/solutions/rust/06-set_get/code/codecrafters.yml deleted file mode 100644 index 5adf6b91..00000000 --- a/solutions/rust/06-set_get/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Rust version used to run your code -# on Codecrafters. -# -# Available versions: rust-1.70 -language_pack: rust-1.70 diff --git a/solutions/rust/06-set_get/code/spawn_redis_server.sh b/solutions/rust/06-set_get/code/spawn_redis_server.sh deleted file mode 100755 index daf001a9..00000000 --- a/solutions/rust/06-set_get/code/spawn_redis_server.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec cargo run \ - --quiet \ - --release \ - --target-dir=/tmp/codecrafters-redis-target \ - --manifest-path $(dirname $0)/Cargo.toml "$@" diff --git a/solutions/rust/06-set_get/code/src/main.rs b/solutions/rust/06-set_get/code/src/main.rs deleted file mode 100644 index eb5503fa..00000000 --- a/solutions/rust/06-set_get/code/src/main.rs +++ /dev/null @@ -1,75 +0,0 @@ -use anyhow::Result; -use resp::Value::{BulkString, Error, Null, SimpleString}; -use std::sync::{Arc, Mutex}; -use store::Store; -use tokio::net::{TcpListener, TcpStream}; - -mod resp; -mod store; - -#[tokio::main] -async fn main() -> Result<()> { - let listener = TcpListener::bind("127.0.0.1:6379").await?; - - let main_store = Arc::new(Mutex::new(Store::new())); - - loop { - let incoming = listener.accept().await; - let client_store = main_store.clone(); - match incoming { - Ok((stream, _)) => { - println!("accepted new connection"); - tokio::spawn(async move { - handle_connection(stream, client_store).await.unwrap(); - }); - } - Err(e) => { - println!("error: {}", e); - } - } - } -} - -async fn handle_connection(stream: TcpStream, client_store: Arc>) -> Result<()> { - let mut conn = resp::RespConnection::new(stream); - - loop { - let value = conn.read_value().await?; - - if let Some(value) = value { - let (command, args) = value.to_command()?; - let response = match command.to_ascii_lowercase().as_ref() { - "ping" => SimpleString("PONG".to_string()), - "echo" => args.first().unwrap().clone(), - "get" => { - if let Some(BulkString(key)) = args.get(0) { - if let Some(value) = client_store.lock().unwrap().get(key.clone()) { - SimpleString(value) - } else { - Null - } - } else { - Error("Get requires one argument".to_string()) - } - } - "set" => { - if let (Some(BulkString(key)), Some(BulkString(value))) = - (args.get(0), args.get(1)) - { - client_store.lock().unwrap().set(key.clone(), value.clone()); - SimpleString("OK".to_string()) - } else { - Error("Set requires two arguments".to_string()) - } - } - _ => Error(format!("command not implemented: {}", command)), - }; - - conn.write_value(response).await?; - } else { - break; - } - } - - Ok(()) -} diff --git a/solutions/rust/06-set_get/code/src/resp.rs b/solutions/rust/06-set_get/code/src/resp.rs deleted file mode 100644 index 9c12fe97..00000000 --- a/solutions/rust/06-set_get/code/src/resp.rs +++ /dev/null @@ -1,170 +0,0 @@ -use anyhow::{Error, Result}; -use bytes::BytesMut; -use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpStream}; - -const CARRIAGE_RETURN: u8 = '\r' as u8; -const NEWLINE: u8 = '\n' as u8; - -#[derive(Eq, PartialEq, Clone, Debug)] -pub enum Value { - /// Null bulk reply, `$-1\r\n` - Null, - /// For Simple Strings the first byte of the reply is "+". - SimpleString(String), - /// For Errors the first byte of the reply is "-". - Error(String), - /// For Bulk Strings the first byte of the reply is "$". - BulkString(String), - /// For Arrays the first byte of the reply is "*". - Array(Vec), -} - -impl Value { - pub fn to_command(&self) -> Result<(String, Vec)> { - match self { - Value::Array(items) => { - return Ok(( - items.first().unwrap().unwrap_bulk(), - items.clone().into_iter().skip(1).collect(), - )); - } - _ => Err(Error::msg("not an array")), - } - } - - fn unwrap_bulk(&self) -> String { - match self { - Value::BulkString(str) => str.clone(), - _ => panic!("not a bulk string"), - } - } - - pub fn encode(self) -> String { - match &self { - Value::Null => "$-1\r\n".to_string(), - Value::SimpleString(s) => format!("+{}\r\n", s.as_str()), - Value::Error(msg) => format!("-{}\r\n", msg.as_str()), - Value::BulkString(s) => format!("${}\r\n{}\r\n", s.chars().count(), s), - // The other cases are not required - _ => panic!("value encode not implemented for: {:?}", self), - } - } -} - -pub struct RespConnection { - stream: TcpStream, - buffer: BytesMut, -} - -impl RespConnection { - pub fn new(stream: TcpStream) -> Self { - return RespConnection { - stream, - buffer: BytesMut::with_capacity(512), - }; - } - - pub async fn read_value(&mut self) -> Result> { - loop { - let bytes_read = self.stream.read_buf(&mut self.buffer).await?; - - // Connection closed - if bytes_read == 0 { - return Ok(None); - } - - if let Some((value, _)) = parse_message(self.buffer.split())? { - return Ok(Some(value)); - } - } - } - - pub async fn write_value(&mut self, value: Value) -> Result<()> { - self.stream.write(value.encode().as_bytes()).await?; - - Ok(()) - } -} - -fn parse_message(buffer: BytesMut) -> Result> { - match buffer[0] as char { - '+' => decode_simple_string(buffer), - '*' => decode_array(buffer), - '$' => decode_bulk_string(buffer), - _ => Err(Error::msg("unrecognised message type")), - } -} - -fn decode_simple_string(buffer: BytesMut) -> Result> { - if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let str = parse_string(line)?; - - Ok(Some((Value::SimpleString(str), len + 1))) - } else { - Ok(None) - } -} - -fn decode_array(buffer: BytesMut) -> Result> { - let (array_length, mut bytes_consumed) = - if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let array_length = parse_integer(line)?; - - (array_length, len + 1) - } else { - return Ok(None); - }; - - let mut items: Vec = Vec::new(); - for _ in 0..array_length { - if let Some((v, len)) = parse_message(BytesMut::from(&buffer[bytes_consumed..]))? { - items.push(v); - bytes_consumed += len - } else { - return Ok(None); - } - } - - return Ok(Some((Value::Array(items), bytes_consumed))); -} - -fn decode_bulk_string(buffer: BytesMut) -> Result> { - let (bulk_length, bytes_consumed) = if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let bulk_length = parse_integer(line)?; - - (bulk_length, len + 1) - } else { - return Ok(None); - }; - - let end_of_bulk = bytes_consumed + (bulk_length as usize); - let end_of_bulk_line = end_of_bulk + 2; - - return if end_of_bulk_line <= buffer.len() { - Ok(Some(( - Value::BulkString(parse_string(&buffer[bytes_consumed..end_of_bulk])?), - end_of_bulk_line, - ))) - } else { - Ok(None) - }; -} - -fn read_until_crlf(buffer: &[u8]) -> Option<(&[u8], usize)> { - for i in 1..buffer.len() { - if buffer[i - 1] == CARRIAGE_RETURN && buffer[i] == NEWLINE { - return Some((&buffer[0..(i - 1)], i + 1)); - } - } - - return None; -} - -fn parse_string(bytes: &[u8]) -> Result { - String::from_utf8(bytes.to_vec()).map_err(|_| Error::msg("Could not parse string")) -} - -fn parse_integer(bytes: &[u8]) -> Result { - let str_integer = parse_string(bytes)?; - (str_integer.parse::()).map_err(|_| Error::msg("Could not parse integer")) -} diff --git a/solutions/rust/06-set_get/code/src/store.rs b/solutions/rust/06-set_get/code/src/store.rs deleted file mode 100644 index 8236279a..00000000 --- a/solutions/rust/06-set_get/code/src/store.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::collections::HashMap; - -pub struct Store { - data: HashMap, -} - -impl Store { - pub fn new() -> Self { - Store { - data: HashMap::new(), - } - } - - pub fn set(&mut self, key: String, value: String) { - self.data.insert(key, value); - } - - pub fn get(&mut self, key: String) -> Option { - self.data.get(key.as_str()).cloned() - } -} diff --git a/solutions/rust/06-set_get/definition.yml b/solutions/rust/06-set_get/definition.yml deleted file mode 100755 index 6b505942..00000000 --- a/solutions/rust/06-set_get/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -#pull_request_url: "https://github.com/codecrafters-io/build-your-own-/pull/" diff --git a/solutions/rust/06-set_get/diff/src/main.rs.diff b/solutions/rust/06-set_get/diff/src/main.rs.diff deleted file mode 100644 index ac72ce08..00000000 --- a/solutions/rust/06-set_get/diff/src/main.rs.diff +++ /dev/null @@ -1,79 +0,0 @@ -@@ -1,48 +1,75 @@ - use anyhow::Result; --use resp::Value::{Error, SimpleString}; -+use resp::Value::{BulkString, Error, Null, SimpleString}; -+use std::sync::{Arc, Mutex}; -+use store::Store; - use tokio::net::{TcpListener, TcpStream}; - - mod resp; -+mod store; - - #[tokio::main] - async fn main() -> Result<()> { - let listener = TcpListener::bind("127.0.0.1:6379").await?; - -+ let main_store = Arc::new(Mutex::new(Store::new())); -+ - loop { - let incoming = listener.accept().await; -+ let client_store = main_store.clone(); - match incoming { - Ok((stream, _)) => { - println!("accepted new connection"); - tokio::spawn(async move { -- handle_connection(stream).await.unwrap(); -+ handle_connection(stream, client_store).await.unwrap(); - }); - } - Err(e) => { - println!("error: {}", e); - } - } - } - } - --async fn handle_connection(stream: TcpStream) -> Result<()> { -+async fn handle_connection(stream: TcpStream, client_store: Arc>) -> Result<()> { - let mut conn = resp::RespConnection::new(stream); - - loop { - let value = conn.read_value().await?; - - if let Some(value) = value { - let (command, args) = value.to_command()?; - let response = match command.to_ascii_lowercase().as_ref() { - "ping" => SimpleString("PONG".to_string()), - "echo" => args.first().unwrap().clone(), -+ "get" => { -+ if let Some(BulkString(key)) = args.get(0) { -+ if let Some(value) = client_store.lock().unwrap().get(key.clone()) { -+ SimpleString(value) -+ } else { -+ Null -+ } -+ } else { -+ Error("Get requires one argument".to_string()) -+ } -+ } -+ "set" => { -+ if let (Some(BulkString(key)), Some(BulkString(value))) = -+ (args.get(0), args.get(1)) -+ { -+ client_store.lock().unwrap().set(key.clone(), value.clone()); -+ SimpleString("OK".to_string()) -+ } else { -+ Error("Set requires two arguments".to_string()) -+ } -+ } - _ => Error(format!("command not implemented: {}", command)), - }; - - conn.write_value(response).await?; - } else { - break; - } - } - - Ok(()) - } diff --git a/solutions/rust/06-set_get/diff/src/resp.rs.diff b/solutions/rust/06-set_get/diff/src/resp.rs.diff deleted file mode 100644 index f8bd021c..00000000 --- a/solutions/rust/06-set_get/diff/src/resp.rs.diff +++ /dev/null @@ -1,70 +0,0 @@ -@@ -1,66 +1,69 @@ - use anyhow::{Error, Result}; - use bytes::BytesMut; - use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpStream}; - - const CARRIAGE_RETURN: u8 = '\r' as u8; - const NEWLINE: u8 = '\n' as u8; - - #[derive(Eq, PartialEq, Clone, Debug)] - pub enum Value { -+ /// Null bulk reply, `$-1\r\n` -+ Null, - /// For Simple Strings the first byte of the reply is "+". - SimpleString(String), - /// For Errors the first byte of the reply is "-". - Error(String), - /// For Bulk Strings the first byte of the reply is "$". - BulkString(String), - /// For Arrays the first byte of the reply is "*". - Array(Vec), - } - - impl Value { - pub fn to_command(&self) -> Result<(String, Vec)> { - match self { - Value::Array(items) => { - return Ok(( - items.first().unwrap().unwrap_bulk(), - items.clone().into_iter().skip(1).collect(), - )); - } - _ => Err(Error::msg("not an array")), - } - } - - fn unwrap_bulk(&self) -> String { - match self { - Value::BulkString(str) => str.clone(), - _ => panic!("not a bulk string"), - } - } - - pub fn encode(self) -> String { - match &self { -+ Value::Null => "$-1\r\n".to_string(), - Value::SimpleString(s) => format!("+{}\r\n", s.as_str()), - Value::Error(msg) => format!("-{}\r\n", msg.as_str()), - Value::BulkString(s) => format!("${}\r\n{}\r\n", s.chars().count(), s), - // The other cases are not required - _ => panic!("value encode not implemented for: {:?}", self), - } - } - } - - pub struct RespConnection { - stream: TcpStream, - buffer: BytesMut, - } - - impl RespConnection { - pub fn new(stream: TcpStream) -> Self { - return RespConnection { - stream, - buffer: BytesMut::with_capacity(512), - }; - } - - pub async fn read_value(&mut self) -> Result> { - loop { - let bytes_read = self.stream.read_buf(&mut self.buffer).await?; diff --git a/solutions/rust/06-set_get/diff/src/store.rs.diff b/solutions/rust/06-set_get/diff/src/store.rs.diff deleted file mode 100644 index 05c026ed..00000000 --- a/solutions/rust/06-set_get/diff/src/store.rs.diff +++ /dev/null @@ -1,22 +0,0 @@ -@@ -0,0 +1,21 @@ -+use std::collections::HashMap; -+ -+pub struct Store { -+ data: HashMap, -+} -+ -+impl Store { -+ pub fn new() -> Self { -+ Store { -+ data: HashMap::new(), -+ } -+ } -+ -+ pub fn set(&mut self, key: String, value: String) { -+ self.data.insert(key, value); -+ } -+ -+ pub fn get(&mut self, key: String) -> Option { -+ self.data.get(key.as_str()).cloned() -+ } -+} diff --git a/solutions/rust/06-set_get/explanation.md b/solutions/rust/06-set_get/explanation.md deleted file mode 100644 index b1e46692..00000000 --- a/solutions/rust/06-set_get/explanation.md +++ /dev/null @@ -1,55 +0,0 @@ -In Stage 6, we add in-memory storage. - -Now that we can handle arguments, we can implement the `get ` and `set ` commands. - -There is a new module called `store` which contains the in-memory store. Start by defining a `Store` struct, which is -just a wrapper around a `HashMap` for now. - -```rust -use std::collections::HashMap; - -pub struct Store { - data: HashMap -} -``` - -Then we can add an implementation for the `Store` - -```rust -impl Store { - pub fn new() -> Self { - Store { - data: HashMap::new(), - } - } - - pub fn set(&mut self, key: String, value: String) { - self.data.insert(key, value); - } - - pub fn get(&mut self, key: String) -> Option { - self.data.get(key.as_str()).cloned() - } -} -``` - -Again, we're hiding the implementation of the underlying `HashMap` but defining an abstraction now will let us extend -the behaviour later, when we need to add expiring keys in the next section. - -Now let's add the `Store` to the server. Because we want to have a single instance of the store the all clients can use, -we need a way to safely share it between Tokio tasks we will use an `Arc` which is a reference counted pointer. You can -find the documentation here. To make sure only one task at a time accesses the `Store` we also need to wrap it in a -Mutex. This comes together as - -```rust -let main_store = Arc::new(Mutex::new(Store::new())); -``` - -Then the store can be passed to each task by increasing the reference count, which is inherent to the `clone`, and -moving the new reference. - -```rust -let client_store = main_store.clone(); -``` - -Finally, we have all the pieces and can update the command processing. Check `main.rs` to see these changes. diff --git a/solutions/rust/07-expiry/code/.gitignore b/solutions/rust/07-expiry/code/.gitignore deleted file mode 100644 index 73fab072..00000000 --- a/solutions/rust/07-expiry/code/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb diff --git a/solutions/rust/07-expiry/code/Cargo.lock b/solutions/rust/07-expiry/code/Cargo.lock deleted file mode 100644 index e337d056..00000000 --- a/solutions/rust/07-expiry/code/Cargo.lock +++ /dev/null @@ -1,351 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91f1f46651137be86f3a2b9a8359f9ab421d04d941c62b5982e1ca21113adf9" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" -dependencies = [ - "libc", -] - -[[package]] -name = "libc" -version = "0.2.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "mio" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redis-starter-rust" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "thiserror", - "tokio", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "signal-hook-registry" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "syn" -version = "1.0.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "thiserror" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/solutions/rust/07-expiry/code/Cargo.toml b/solutions/rust/07-expiry/code/Cargo.toml deleted file mode 100644 index 157cbb7f..00000000 --- a/solutions/rust/07-expiry/code/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[package] -name = "redis-starter-rust" -version = "0.1.0" -authors = ["Codecrafters "] -edition = "2021" - -# DON'T EDIT THIS! -# -# Codecrafters relies on this file being intact to run tests successfully. Any changes -# here will not reflect when CodeCrafters tests your code, and might even cause build -# failures. -# -# DON'T EDIT THIS! -[dependencies] -anyhow = "1.0.59" # error handling -bytes = "1.3.0" # helps manage buffers -thiserror = "1.0.32" # error handling -tokio = { version = "1.23.0", features = ["full"] } # async networking diff --git a/solutions/rust/07-expiry/code/README.md b/solutions/rust/07-expiry/code/README.md deleted file mode 100644 index bc38e7b7..00000000 --- a/solutions/rust/07-expiry/code/README.md +++ /dev/null @@ -1,35 +0,0 @@ -![progress-banner](https://codecrafters.io/landing/images/default_progress_banners/redis.png) - -This is a starting point for Rust solutions to the -["Build Your Own Redis" Challenge](https://codecrafters.io/challenges/redis). - -In this challenge, you'll build a toy Redis clone that's capable of handling -basic commands like `PING`, `SET` and `GET`. Along the way we'll learn about -event loops, the Redis protocol and more. - -**Note**: If you're viewing this repo on GitHub, head over to -[codecrafters.io](https://codecrafters.io) to try the challenge. - -# Passing the first stage - -The entry point for your Redis implementation is in `src/main.rs`. Study and -uncomment the relevant code, and push your changes to pass the first stage: - -```sh -git add . -git commit -m "pass 1st stage" # any msg -git push origin master -``` - -That's all! - -# Stage 2 & beyond - -Note: This section is for stages 2 and beyond. - -1. Ensure you have `cargo (1.54)` installed locally -1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented - in `src/main.rs`. This command compiles your Rust project, so it might be - slow the first time you run it. Subsequent runs will be fast. -1. Commit your changes and run `git push origin master` to submit your solution - to CodeCrafters. Test output will be streamed to your terminal. diff --git a/solutions/rust/07-expiry/code/codecrafters.yml b/solutions/rust/07-expiry/code/codecrafters.yml deleted file mode 100644 index 5adf6b91..00000000 --- a/solutions/rust/07-expiry/code/codecrafters.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Set this to true if you want debug logs. -# -# These can be VERY verbose, so we suggest turning them off -# unless you really need them. -debug: false - -# Use this to change the Rust version used to run your code -# on Codecrafters. -# -# Available versions: rust-1.70 -language_pack: rust-1.70 diff --git a/solutions/rust/07-expiry/code/spawn_redis_server.sh b/solutions/rust/07-expiry/code/spawn_redis_server.sh deleted file mode 100755 index daf001a9..00000000 --- a/solutions/rust/07-expiry/code/spawn_redis_server.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# -# DON'T EDIT THIS! -# -# CodeCrafters uses this file to test your code. Don't make any changes here! -# -# DON'T EDIT THIS! -exec cargo run \ - --quiet \ - --release \ - --target-dir=/tmp/codecrafters-redis-target \ - --manifest-path $(dirname $0)/Cargo.toml "$@" diff --git a/solutions/rust/07-expiry/code/src/main.rs b/solutions/rust/07-expiry/code/src/main.rs deleted file mode 100644 index dc246e08..00000000 --- a/solutions/rust/07-expiry/code/src/main.rs +++ /dev/null @@ -1,86 +0,0 @@ -use anyhow::Result; -use resp::Value::{BulkString, Error, Null, SimpleString}; -use std::sync::{Arc, Mutex}; -use store::Store; -use tokio::net::{TcpListener, TcpStream}; - -mod resp; -mod store; - -#[tokio::main] -async fn main() -> Result<()> { - let listener = TcpListener::bind("127.0.0.1:6379").await?; - - let main_store = Arc::new(Mutex::new(Store::new())); - - loop { - let incoming = listener.accept().await; - let client_store = main_store.clone(); - match incoming { - Ok((stream, _)) => { - println!("accepted new connection"); - tokio::spawn(async move { - handle_connection(stream, client_store).await.unwrap(); - }); - } - Err(e) => { - println!("error: {}", e); - } - } - } -} - -async fn handle_connection(stream: TcpStream, client_store: Arc>) -> Result<()> { - let mut conn = resp::RespConnection::new(stream); - - loop { - let value = conn.read_value().await?; - - if let Some(value) = value { - let (command, args) = value.to_command()?; - let response = match command.to_ascii_lowercase().as_ref() { - "ping" => SimpleString("PONG".to_string()), - "echo" => args.first().unwrap().clone(), - "get" => { - if let Some(BulkString(key)) = args.get(0) { - if let Some(value) = client_store.lock().unwrap().get(key.clone()) { - SimpleString(value) - } else { - Null - } - } else { - Error("Get requires one argument".to_string()) - } - } - "set" => { - if let (Some(BulkString(key)), Some(BulkString(value))) = - (args.get(0), args.get(1)) - { - if let (Some(BulkString(_)), Some(BulkString(amount))) = - (args.get(2), args.get(3)) - { - client_store.lock().unwrap().set_with_expiry( - key.clone(), - value.clone(), - amount.parse::()?, - ); - } else { - client_store.lock().unwrap().set(key.clone(), value.clone()); - } - - SimpleString("OK".to_string()) - } else { - Error("Set requires two or four arguments".to_string()) - } - } - _ => Error(format!("command not implemented: {}", command)), - }; - - conn.write_value(response).await?; - } else { - break; - } - } - - Ok(()) -} diff --git a/solutions/rust/07-expiry/code/src/resp.rs b/solutions/rust/07-expiry/code/src/resp.rs deleted file mode 100644 index 9c12fe97..00000000 --- a/solutions/rust/07-expiry/code/src/resp.rs +++ /dev/null @@ -1,170 +0,0 @@ -use anyhow::{Error, Result}; -use bytes::BytesMut; -use tokio::{io::AsyncReadExt, io::AsyncWriteExt, net::TcpStream}; - -const CARRIAGE_RETURN: u8 = '\r' as u8; -const NEWLINE: u8 = '\n' as u8; - -#[derive(Eq, PartialEq, Clone, Debug)] -pub enum Value { - /// Null bulk reply, `$-1\r\n` - Null, - /// For Simple Strings the first byte of the reply is "+". - SimpleString(String), - /// For Errors the first byte of the reply is "-". - Error(String), - /// For Bulk Strings the first byte of the reply is "$". - BulkString(String), - /// For Arrays the first byte of the reply is "*". - Array(Vec), -} - -impl Value { - pub fn to_command(&self) -> Result<(String, Vec)> { - match self { - Value::Array(items) => { - return Ok(( - items.first().unwrap().unwrap_bulk(), - items.clone().into_iter().skip(1).collect(), - )); - } - _ => Err(Error::msg("not an array")), - } - } - - fn unwrap_bulk(&self) -> String { - match self { - Value::BulkString(str) => str.clone(), - _ => panic!("not a bulk string"), - } - } - - pub fn encode(self) -> String { - match &self { - Value::Null => "$-1\r\n".to_string(), - Value::SimpleString(s) => format!("+{}\r\n", s.as_str()), - Value::Error(msg) => format!("-{}\r\n", msg.as_str()), - Value::BulkString(s) => format!("${}\r\n{}\r\n", s.chars().count(), s), - // The other cases are not required - _ => panic!("value encode not implemented for: {:?}", self), - } - } -} - -pub struct RespConnection { - stream: TcpStream, - buffer: BytesMut, -} - -impl RespConnection { - pub fn new(stream: TcpStream) -> Self { - return RespConnection { - stream, - buffer: BytesMut::with_capacity(512), - }; - } - - pub async fn read_value(&mut self) -> Result> { - loop { - let bytes_read = self.stream.read_buf(&mut self.buffer).await?; - - // Connection closed - if bytes_read == 0 { - return Ok(None); - } - - if let Some((value, _)) = parse_message(self.buffer.split())? { - return Ok(Some(value)); - } - } - } - - pub async fn write_value(&mut self, value: Value) -> Result<()> { - self.stream.write(value.encode().as_bytes()).await?; - - Ok(()) - } -} - -fn parse_message(buffer: BytesMut) -> Result> { - match buffer[0] as char { - '+' => decode_simple_string(buffer), - '*' => decode_array(buffer), - '$' => decode_bulk_string(buffer), - _ => Err(Error::msg("unrecognised message type")), - } -} - -fn decode_simple_string(buffer: BytesMut) -> Result> { - if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let str = parse_string(line)?; - - Ok(Some((Value::SimpleString(str), len + 1))) - } else { - Ok(None) - } -} - -fn decode_array(buffer: BytesMut) -> Result> { - let (array_length, mut bytes_consumed) = - if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let array_length = parse_integer(line)?; - - (array_length, len + 1) - } else { - return Ok(None); - }; - - let mut items: Vec = Vec::new(); - for _ in 0..array_length { - if let Some((v, len)) = parse_message(BytesMut::from(&buffer[bytes_consumed..]))? { - items.push(v); - bytes_consumed += len - } else { - return Ok(None); - } - } - - return Ok(Some((Value::Array(items), bytes_consumed))); -} - -fn decode_bulk_string(buffer: BytesMut) -> Result> { - let (bulk_length, bytes_consumed) = if let Some((line, len)) = read_until_crlf(&buffer[1..]) { - let bulk_length = parse_integer(line)?; - - (bulk_length, len + 1) - } else { - return Ok(None); - }; - - let end_of_bulk = bytes_consumed + (bulk_length as usize); - let end_of_bulk_line = end_of_bulk + 2; - - return if end_of_bulk_line <= buffer.len() { - Ok(Some(( - Value::BulkString(parse_string(&buffer[bytes_consumed..end_of_bulk])?), - end_of_bulk_line, - ))) - } else { - Ok(None) - }; -} - -fn read_until_crlf(buffer: &[u8]) -> Option<(&[u8], usize)> { - for i in 1..buffer.len() { - if buffer[i - 1] == CARRIAGE_RETURN && buffer[i] == NEWLINE { - return Some((&buffer[0..(i - 1)], i + 1)); - } - } - - return None; -} - -fn parse_string(bytes: &[u8]) -> Result { - String::from_utf8(bytes.to_vec()).map_err(|_| Error::msg("Could not parse string")) -} - -fn parse_integer(bytes: &[u8]) -> Result { - let str_integer = parse_string(bytes)?; - (str_integer.parse::()).map_err(|_| Error::msg("Could not parse integer")) -} diff --git a/solutions/rust/07-expiry/code/src/store.rs b/solutions/rust/07-expiry/code/src/store.rs deleted file mode 100644 index e55b09b5..00000000 --- a/solutions/rust/07-expiry/code/src/store.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::collections::HashMap; -use std::time::{Duration, Instant}; - -pub struct Store { - data: HashMap, -} - -struct Entry { - t: Option, - value: String, -} - -impl Store { - pub fn new() -> Self { - Store { - data: HashMap::new(), - } - } - - pub fn set(&mut self, key: String, value: String) { - let entry = Entry { t: None, value }; - self.data.insert(key, entry); - } - - pub fn set_with_expiry(&mut self, key: String, value: String, expiry_ms: u64) { - let entry = Entry { - t: Some(Instant::now() + Duration::from_millis(expiry_ms)), - value, - }; - self.data.insert(key, entry); - } - - pub fn get(&mut self, key: String) -> Option { - match self.data.get(key.as_str()) { - Some(entry) => { - // Lazily expire keys as they are requested - if let Some(t) = &entry.t { - if Instant::now() > t.clone() { - self.data.remove(key.as_str()); - return None; - } - } - - Some(entry.value.clone()) - } - None => None, - } - } -} diff --git a/solutions/rust/07-expiry/definition.yml b/solutions/rust/07-expiry/definition.yml deleted file mode 100755 index 6b505942..00000000 --- a/solutions/rust/07-expiry/definition.yml +++ /dev/null @@ -1,11 +0,0 @@ -author_details: - name: Paul Kuruvilla - profile_url: https://github.com/rohitpaulk - avatar_url: https://github.com/rohitpaulk.png - headline: CTO, CodeCrafters -#reviewers_details: -#- name: Marcos Lilljedahl -# profile_url: https://www.docker.com/captains/marcos-lilljedahl/ -# avatar_url: https://github.com/marcosnils.png -# headline: Docker Contributor -#pull_request_url: "https://github.com/codecrafters-io/build-your-own-/pull/" diff --git a/solutions/rust/07-expiry/diff/src/main.rs.diff b/solutions/rust/07-expiry/diff/src/main.rs.diff deleted file mode 100644 index 06c8218b..00000000 --- a/solutions/rust/07-expiry/diff/src/main.rs.diff +++ /dev/null @@ -1,56 +0,0 @@ -@@ -34,42 +34,53 @@ - let mut conn = resp::RespConnection::new(stream); - - loop { - let value = conn.read_value().await?; - - if let Some(value) = value { - let (command, args) = value.to_command()?; - let response = match command.to_ascii_lowercase().as_ref() { - "ping" => SimpleString("PONG".to_string()), - "echo" => args.first().unwrap().clone(), - "get" => { - if let Some(BulkString(key)) = args.get(0) { - if let Some(value) = client_store.lock().unwrap().get(key.clone()) { - SimpleString(value) - } else { - Null - } - } else { - Error("Get requires one argument".to_string()) - } - } - "set" => { - if let (Some(BulkString(key)), Some(BulkString(value))) = - (args.get(0), args.get(1)) - { -- client_store.lock().unwrap().set(key.clone(), value.clone()); -+ if let (Some(BulkString(_)), Some(BulkString(amount))) = -+ (args.get(2), args.get(3)) -+ { -+ client_store.lock().unwrap().set_with_expiry( -+ key.clone(), -+ value.clone(), -+ amount.parse::()?, -+ ); -+ } else { -+ client_store.lock().unwrap().set(key.clone(), value.clone()); -+ } -+ - SimpleString("OK".to_string()) - } else { -- Error("Set requires two arguments".to_string()) -+ Error("Set requires two or four arguments".to_string()) - } - } - _ => Error(format!("command not implemented: {}", command)), - }; - - conn.write_value(response).await?; - } else { - break; - } - } - - Ok(()) - } diff --git a/solutions/rust/07-expiry/diff/src/store.rs.diff b/solutions/rust/07-expiry/diff/src/store.rs.diff deleted file mode 100644 index 44880a00..00000000 --- a/solutions/rust/07-expiry/diff/src/store.rs.diff +++ /dev/null @@ -1,53 +0,0 @@ -@@ -1,21 +1,49 @@ - use std::collections::HashMap; -+use std::time::{Duration, Instant}; - - pub struct Store { -- data: HashMap, -+ data: HashMap, -+} -+ -+struct Entry { -+ t: Option, -+ value: String, - } - - impl Store { - pub fn new() -> Self { - Store { - data: HashMap::new(), - } - } - - pub fn set(&mut self, key: String, value: String) { -- self.data.insert(key, value); -+ let entry = Entry { t: None, value }; -+ self.data.insert(key, entry); -+ } -+ -+ pub fn set_with_expiry(&mut self, key: String, value: String, expiry_ms: u64) { -+ let entry = Entry { -+ t: Some(Instant::now() + Duration::from_millis(expiry_ms)), -+ value, -+ }; -+ self.data.insert(key, entry); - } - - pub fn get(&mut self, key: String) -> Option { -- self.data.get(key.as_str()).cloned() -+ match self.data.get(key.as_str()) { -+ Some(entry) => { -+ // Lazily expire keys as they are requested -+ if let Some(t) = &entry.t { -+ if Instant::now() > t.clone() { -+ self.data.remove(key.as_str()); -+ return None; -+ } -+ } -+ -+ Some(entry.value.clone()) -+ } -+ None => None, -+ } - } - } diff --git a/solutions/rust/07-expiry/explanation.md b/solutions/rust/07-expiry/explanation.md deleted file mode 100644 index 99debbb6..00000000 --- a/solutions/rust/07-expiry/explanation.md +++ /dev/null @@ -1,59 +0,0 @@ -In the final stage we're going to add expiring keys. - -This is a Redis feature that allows the server to take responsibility for removing keys after a specified -amount of time. The `set` command with expiry takes the form `set px