not_redis 0.1.0

A Redis-compatible in-memory data structure library for Rust
Documentation

not_redis

⚠️ Warning: This project was vibe-coded using OpenCode and MiniMax 2.1 Free. Code was generated by AI and may contain bugs, edge cases, or unexpected behavior. Review thoroughly before production use.


Description

not_redis is a Redis-compatible in-memory data structure library written in Rust. It provides Redis-like APIs without the networking overhead, external service dependencies, or operational complexity of running a Redis server.

Key Goals:

  • Zero-config, embeddable Redis-compatible storage
  • Thread-safe concurrent access via Tokio and DashMap
  • RESP-compatible data types and command semantics
  • No network overhead - runs in-process with your application
  • Minimal dependencies for security and simplicity

Features

  • Strings: GET, SET, DEL, EXISTS, EXPIRE, TTL, PERSIST
  • Hashes: HSET, HGET, HGETALL, HDEL
  • Lists: LPUSH, RPUSH, LLEN
  • Sets: SADD, SMEMBERS
  • Utilities: PING, ECHO, DBSIZE, FLUSHDB

Installation

[dependencies]
not_redis = "0.1"

Getting Started

use not_redis::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = Client::new();
    client.start().await;

    // String operations
    client.set("user:1:name", "Alice").await?;
    let name: String = client.get("user:1:name").await?;
    println!("Name: {}", name);

    // Hash operations
    client.hset("user:1", "email", "alice@example.com").await?;
    client.hset("user:1", "age", "30").await?;
    let email: String = client.hget("user:1", "email").await?;
    let profile: Vec<String> = client.hgetall("user:1").await?;
    println!("Email: {}", email);

    // List operations
    client.lpush("user:1:todos", "buy milk").await?;
    client.lpush("user:1:todos", "walk dog").await?;
    let count: i64 = client.llen("user:1:todos").await?;
    println!("Todos: {}", count);

    // Set operations
    client.sadd("user:1:tags", "rust").await?;
    client.sadd("user:1:tags", "developer").await?;
    let tags: Vec<String> = client.smembers("user:1:tags").await?;
    println!("Tags: {:?}", tags);

    // Expiration
    client.set("temp:key", "expires soon").await?;
    client.expire("temp:key", 60).await?;
    let ttl: i64 = client.ttl("temp:key").await?;
    println!("TTL: {} seconds", ttl);

    // Utilities
    let pong: String = client.ping().await?;
    println!("Ping: {}", pong);

    let size: i64 = client.dbsize().await?;
    println!("DB size: {}", size);

    // Cleanup
    let _: String = client.flushdb().await?;

    Ok(())
}

Async Runtime

not_redis requires a Tokio runtime. If you're using it in a non-Tokio context:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = Client::new();
    client.start().await;
    // ... your code ...
}

API Reference

Client

let mut client = Client::new();
client.start().await;
Method Description
get(key) Get value by key
set(key, value) Set key-value pair
del(key) Delete key, returns count
exists(key) Check if key exists
expire(key, seconds) Set key expiration
ttl(key) Get remaining TTL (-2=missing, -1=no expiry, >=0=seconds)
persist(key) Remove expiration, returns success
flushdb() Clear all keys

Hash Operations

Method Description
hset(key, field, value) Set hash field
hget(key, field) Get hash field
hgetall(key) Get all fields/values
hdel(key, field) Delete hash field

List Operations

Method Description
lpush(key, value) Push to list head
rpush(key, value) Push to list tail
llen(key) Get list length

Set Operations

Method Description
sadd(key, member) Add to set
smembers(key) Get all members

Utility Operations

Method Description
ping() Returns "PONG"
echo(msg) Echo message
dbsize() Number of keys

Thread Safety

not_redis uses DashMap for thread-safe concurrent access. Multiple threads can share a single Client instance.

use std::sync::Arc;
use not_redis::Client;

let client = Arc::new(Client::new());
let client_clone = client.clone();

tokio::spawn(async move {
    client_clone.set("key", "value").await.unwrap();
});

Error Handling

use not_redis::{Client, RedisError};

match client.get("nonexistent").await {
    Ok(value) => println!("Found: {}", value),
    Err(RedisError::NoSuchKey(key)) => println!("Key not found: {}", key),
    Err(RedisError::WrongType) => println!("Wrong data type"),
    Err(RedisError::ParseError) => println!("Parse error"),
    Err(e) => println!("Other error: {:?}", e),
}

Why not_redis?

Feature Redis not_redis
Setup Requires Redis server No setup needed
Network TCP/IP overhead In-process, zero-copy
Operations Requires redis-cli or client Direct API calls
Deployment Additional service Single binary

Limitations

  • No persistence (data lost on restart)
  • No networking layer
  • No clustering or replication
  • Limited command set (growing)
  • No Lua scripting
  • No pub/sub

Contributing

Issues and PRs welcome. Note: This is a vibe-coded project - expect quirks.

License

MIT