diff --git a/build/components/example.py b/build/components/example.py index f615d4f168..e8143837bc 100644 --- a/build/components/example.py +++ b/build/components/example.py @@ -26,7 +26,10 @@ 'go': '//', 'c#': '//', 'redisvl': '#', - 'php': '//' + 'php': '//', + 'rust': '//', + 'rust-sync': '//', + 'rust-async': '//' } diff --git a/build/local_examples.py b/build/local_examples.py index d499a137de..cd20975940 100644 --- a/build/local_examples.py +++ b/build/local_examples.py @@ -25,7 +25,8 @@ '.go': 'go', '.cs': 'c#', '.java': 'java', - '.php': 'php' + '.php': 'php', + '.rs': 'rust' } # Language to client name mapping (from config.toml clientsExamples) @@ -36,7 +37,8 @@ 'c#': 'C#', 'java': 'Java-Sync', # Default to sync, could be overridden 'php': 'PHP', - 'redisvl': 'RedisVL' + 'redisvl': 'RedisVL', + 'rust': 'Rust-Sync' } @@ -65,6 +67,11 @@ def get_client_name_from_language_and_path(language: str, path: str) -> str: return 'Java-Async' if 'lettuce-reactive' in path: return 'Java-Reactive' + if language == 'rust': + if 'rust-async' in path: + return 'Rust-Async' + if 'rust-sync' in path: + return 'Rust-Sync' # Default behavior for all languages (and Java fallback) return get_client_name_from_language(language) diff --git a/config.toml b/config.toml index bc62683d48..010938cbbc 100644 --- a/config.toml +++ b/config.toml @@ -45,7 +45,7 @@ tagManagerId = "GTM-TKZ6J9R" gitHubRepo = "https://github.com/redis/docs" # Display and sort order for client examples -clientsExamples = ["Python", "Node.js", "Java-Sync", "Java-Async", "Java-Reactive", "Go", "C#", "RedisVL", "PHP"] +clientsExamples = ["Python", "Node.js", "Java-Sync", "Java-Async", "Java-Reactive", "Go", "C#", "RedisVL", "PHP", "Rust-Sync", "Rust-Async"] searchService = "/convai/api/search-service" ratingsService = "/docusight/api/rate" @@ -67,6 +67,8 @@ rdi_current_version = "1.14.1" "C#"={quickstartSlug="dotnet"} "RedisVL"={quickstartSlug="redis-vl"} "PHP"={quickstartSlug="php"} +"Rust-sync"={quickstartSlug="rust"} +"Rust-async"={quickstartSlug="rust"} # Markup [markup] diff --git a/content/develop/clients/_index.md b/content/develop/clients/_index.md index 766df68ad4..ce159ddcc4 100644 --- a/content/develop/clients/_index.md +++ b/content/develop/clients/_index.md @@ -19,7 +19,7 @@ weight: 30 Use the Redis client libraries to connect to Redis servers from your own code. We document the following client libraries -for seven main languages: +for eight main languages: | Language | Client name | Docs | Supported | | :-- | :-- | :-- | :-- | @@ -32,6 +32,7 @@ for seven main languages: | [Go](https://go.dev/) | [`go-redis`](https://github.com/redis/go-redis) | [`go-redis` guide]({{< relref "/develop/clients/go" >}}) | Yes | | [PHP](https://www.php.net/)| [`Predis`](https://github.com/predis/predis) | [`Predis` guide]({{< relref "/develop/clients/php" >}}) | No | | [C](https://en.wikipedia.org/wiki/C_(programming_language)) | [`hiredis`](https://github.com/redis/hiredis) | [`hiredis` guide]({{< relref "/develop/clients/hiredis" >}}) | Yes | +| [Rust](https://www.rust-lang.org/) | [`redis-rs`](https://github.com/redis-rs/redis-rs) | [`redis-rs` guide]({{< relref "/develop/clients/rust" >}}) | No | We also provide several higher-level [object mapping (OM)]({{< relref "/develop/clients/om-clients" >}}) @@ -51,7 +52,6 @@ Redis does not document directly: | [Dart](https://dart.dev/) | redis_dart_link | https://github.com/toolsetlink/redis_dart_link | https://github.com/toolsetlink/redis_dart_link | | [PHP](https://www.php.net/) | PhpRedis extension | https://github.com/phpredis/phpredis | https://github.com/phpredis/phpredis/blob/develop/README.md | | [Ruby](https://www.ruby-lang.org/en/) | redis-rb | https://github.com/redis/redis-rb | https://rubydoc.info/gems/redis | -| [Rust](https://www.rust-lang.org/) | redis-rs | https://github.com/redis-rs/redis-rs | https://docs.rs/redis/latest/redis/ | ## Requirements diff --git a/content/develop/clients/hiredis/_index.md b/content/develop/clients/hiredis/_index.md index 614ca06d21..5d8227f285 100644 --- a/content/develop/clients/hiredis/_index.md +++ b/content/develop/clients/hiredis/_index.md @@ -12,7 +12,7 @@ categories: description: Connect your C application to a Redis database. linkTitle: hiredis (C) title: hiredis guide (C) -weight: 9 +weight: 10 --- [`hiredis`](https://github.com/redis/hiredis) is the diff --git a/content/develop/clients/rust/_index.md b/content/develop/clients/rust/_index.md new file mode 100644 index 0000000000..0f21c17820 --- /dev/null +++ b/content/develop/clients/rust/_index.md @@ -0,0 +1,79 @@ +--- +categories: +- docs +- develop +- stack +- oss +- rs +- rc +- oss +- kubernetes +- clients +description: Connect your Rust application to a Redis database +linkTitle: redis-rs (Rust) +title: redis-rs guide (Rust) +weight: 9 +--- + +[`redis-rs`](https://github.com/redis-rs/redis-rs) is the [Rust](https://www.rust-lang.org/) client for Redis. +The sections below explain how to install `redis-rs` and connect your application to a Redis database. + +{{< note >}}Although we provide basic documentation for `redis-rs`, it is a third-party +client library and is not developed or supported directly by Redis. +{{< /note >}} + +`redis-rs` requires a running Redis server. See [here]({{< relref "/operate/oss_and_stack/install/" >}}) for Redis Open Source installation instructions. + +## Install + +To use the synchronous API, add the `redis` crate as a dependency in your +`Cargo.toml` file: + +```toml +[dependencies] +redis = "0.32.5" +``` + +If you want to use the asynchronous API, you should also enable either +[`tokio`](https://tokio.rs/) or [`smol`](https://crates.io/crates/smol) +as your async platform: + +```toml +[dependencies] +# if you use tokio +tokio = { version = "1.32.0", features = ["full"] } +redis = { version = "0.32.5", features = ["tokio-comp"] } + +# if you use smol +smol = "2.0.2" +redis = { version = "0.32.5", features = ["smol-comp"] } +``` + +## Connect + +Start by importing the `Commands` or `AsyncCommands` trait from the `redis` crate: + +{{< clients-example set="landing" step="import" lang_filter="Rust-Sync,Rust-Async" >}} +{{< /clients-example >}} + +The following example shows the simplest way to connect to a Redis server: + +{{< clients-example set="landing" step="connect" lang_filter="Rust-Sync,Rust-Async" >}} +{{< /clients-example >}} + +After connecting, you can test the connection by storing and retrieving +a simple [string]({{< relref "/develop/data-types/strings" >}}): + +{{< clients-example set="landing" step="set_get_string" lang_filter="Rust-Sync,Rust-Async" >}} +{{< /clients-example >}} + +You can also easily store and retrieve a [hash]({{< relref "/develop/data-types/hashes" >}}): + +{{< clients-example set="landing" step="set_get_hash" lang_filter="Rust-Sync,Rust-Async" >}} +{{< /clients-example >}} + +## More information + +See the [`redis-rs`](https://docs.rs/redis/latest/redis/) documentation +and the [GitHub repository](https://github.com/redis-rs/redis-rs) for more +information and examples. diff --git a/data/components/index.json b/data/components/index.json index 7a54b7f9fc..00af1e3646 100644 --- a/data/components/index.json +++ b/data/components/index.json @@ -15,7 +15,9 @@ "jedis", "lettuce_async", "lettuce_reactive", - "redis_vl" + "redis_vl", + "redis_rs_sync", + "redis_rs_async" ], "assets": [], "website": { diff --git a/data/components/redis_rs_async.json b/data/components/redis_rs_async.json new file mode 100644 index 0000000000..30dc8fcd54 --- /dev/null +++ b/data/components/redis_rs_async.json @@ -0,0 +1,15 @@ +{ + "id": "redis_rs_async", + "type": "client", + "name": "redis-rs-async", + "language": "Rust-Async", + "label": "Rust-Async", + "repository": { + "git_uri": "https://github.com/redis-rs/redis-rs" + }, + "examples": { + "git_uri": "https://github.com/redis-rs/redis-rs", + "path": "redis/examples", + "pattern": "*.rs" + } +} diff --git a/data/components/redis_rs_sync.json b/data/components/redis_rs_sync.json new file mode 100644 index 0000000000..1437da4726 --- /dev/null +++ b/data/components/redis_rs_sync.json @@ -0,0 +1,15 @@ +{ + "id": "redis_rs_sync", + "type": "client", + "name": "redis-rs-sync", + "language": "Rust-Sync", + "label": "Rust-Sync", + "repository": { + "git_uri": "https://github.com/redis-rs/redis-rs" + }, + "examples": { + "git_uri": "https://github.com/redis-rs/redis-rs", + "path": "redis/examples", + "pattern": "*.rs" + } +} diff --git a/local_examples/client-specific/rust-async/landing.rs b/local_examples/client-specific/rust-async/landing.rs new file mode 100644 index 0000000000..b1894ea6e5 --- /dev/null +++ b/local_examples/client-specific/rust-async/landing.rs @@ -0,0 +1,100 @@ +// EXAMPLE: landing +// STEP_START import +use redis::AsyncCommands; +// STEP_END + +#[tokio::main] +async fn main() { + // STEP_START connect + let mut r = match redis::Client::open("redis://127.0.0.1") { + Ok(client) => { + match client.get_multiplexed_async_connection().await { + Ok(conn) => conn, + Err(e) => { + println!("Failed to connect to Redis: {e}"); + return; + } + } + }, + Err(e) => { + println!("Failed to create Redis client: {e}"); + return; + } + }; + // STEP_END + + // STEP_START set_get_string + if let Ok(res) = r.set("foo", "bar").await { + let res: String = res; + println!("{res}"); // >>> OK + } else { + println!("Error setting foo"); + } + + match r.get("foo").await { + Ok(res) => { + let res: String = res; + println!("{res}"); // >>> bar + }, + Err(e) => { + println!("Error getting foo: {e}"); + return; + } + }; + // STEP_END + + // STEP_START set_get_hash + let hash_fields = [ + ("model", "Deimos"), + ("brand", "Ergonom"), + ("type", "Enduro bikes"), + ("price", "4972"), + ]; + + if let Ok(res) = r.hset_multiple("bike:1", &hash_fields).await { + let res: String = res; + println!("{res}"); // >>> OK + } else { + println!("Error setting bike:1"); + } + + match r.hget("bike:1", "model").await { + Ok(res) => { + let res: String = res; + println!("{res}"); // >>> Deimos + }, + Err(e) => { + println!("Error getting bike:1 model: {e}"); + return; + } + } + + match r.hget("bike:1", "price").await { + Ok(res) => { + let res: String = res; + println!("{res}"); // >>> 4972 + }, + Err(e) => { + println!("Error getting bike:1 price: {e}"); + return; + } + } + + match r.hgetall("bike:1").await { + Ok(res) => { + let res: Vec<(String, String)> = res; + for (key, value) in res { + println!("{key}: {value}"); + } + // >>> model: Deimos + // >>> brand: Ergonom + // >>> type: Enduro bikes + // >>> price: 4972 + }, + Err(e) => { + println!("Error getting bike:1: {e}"); + return; + } + // STEP_END + } +} diff --git a/local_examples/client-specific/rust-sync/landing.rs b/local_examples/client-specific/rust-sync/landing.rs new file mode 100644 index 0000000000..af2598f5ba --- /dev/null +++ b/local_examples/client-specific/rust-sync/landing.rs @@ -0,0 +1,99 @@ +// EXAMPLE: landing +// STEP_START import +use redis::Commands; +// STEP_END + +fn main() { + // STEP_START connect + let mut r = match redis::Client::open("redis://127.0.0.1") { + Ok(client) => { + match client.get_connection() { + Ok(conn) => conn, + Err(e) => { + println!("Failed to connect to Redis: {e}"); + return; + } + } + }, + Err(e) => { + println!("Failed to create Redis client: {e}"); + return; + } + }; + // STEP_END + + // STEP_START set_get_string + if let Ok(res) = r.set("foo", "bar") { + let res: String = res; + println!("{res}"); // >>> OK + } else { + println!("Error setting foo"); + } + + match r.get("foo") { + Ok(res) => { + let res: String = res; + println!("{res}"); // >>> bar + }, + Err(e) => { + println!("Error getting foo: {e}"); + return; + } + }; + // STEP_END + + // STEP_START set_get_hash + let hash_fields = [ + ("model", "Deimos"), + ("brand", "Ergonom"), + ("type", "Enduro bikes"), + ("price", "4972"), + ]; + + if let Ok(res) = r.hset_multiple("bike:1", &hash_fields) { + let res: String = res; + println!("{res}"); // >>> OK + } else { + println!("Error setting bike:1"); + } + + match r.hget("bike:1", "model") { + Ok(res) => { + let res: String = res; + println!("{res}"); // >>> Deimos + }, + Err(e) => { + println!("Error getting bike:1 model: {e}"); + return; + } + } + + match r.hget("bike:1", "price") { + Ok(res) => { + let res: String = res; + println!("{res}"); // >>> 4972 + }, + Err(e) => { + println!("Error getting bike:1 price: {e}"); + return; + } + } + + match r.hgetall("bike:1") { + Ok(res) => { + let res: Vec<(String, String)> = res; + for (key, value) in res { + println!("{key}: {value}"); + } + // >>> model: Deimos + // >>> brand: Ergonom + // >>> type: Enduro bikes + // >>> price: 4972 + }, + Err(e) => { + println!("Error getting bike:1: {e}"); + return; + } + } + // STEP_END +}