# Step 2 — Four Core Language Ideas

You do **not** need all of Rust to build a backend. Four ideas explain roughly 90% of the code you'll read and write. Learn these and Axum, SQLx, and Tokio stop feeling like magic.

## 1. Ownership & borrowing — "who is responsible for this value?"

Every value in Rust has exactly one **owner**. You either **move** it (hand ownership away) or **borrow** it (`&` for read-only access, `&mut` for exclusive write access).

```rust
let title = String::from("Write the docs");

// Borrow: the function reads `title` but doesn't take it.
print_len(&title);
println!("still mine: {title}");   // ✅ works — we only lent it out

// Move: the function takes ownership; `title` is gone afterwards.
consume(title);
// println!("{title}");            // ❌ compile error: value moved
```

Why a backend cares: a database connection pool is created once and shared by every request handler. You don't want each handler to *own* (and try to free) the pool — they **borrow** it:

```rust
async fn list_tasks(pool: &PgPool) -> Vec<Task> { /* ... */ }
//                        ^ borrow — "lend me the pool, I'll give it back"
```

When the borrow checker complains, it's almost always saying: *"you used this after you gave it away."* The fix is usually to borrow (`&`) instead of move, or to `.clone()` when the value is cheap to copy.

> **`Arc` is how you share safely.** Shared server state (config, pools, caches) is wrapped in an `Arc<T>` (atomically reference-counted pointer). Cloning an `Arc` doesn't copy the data — it bumps a counter — so every handler can cheaply hold its own handle to the same state.

## 2. `Option` and `Result` — no null, and errors are values

Rust has **no null**. Two enums replace it:

- `Option<T>` = a value that might be absent: `Some(x)` or `None`.
- `Result<T, E>` = an operation that might fail: `Ok(x)` or `Err(e)`.

The compiler forces you to handle both arms — you cannot accidentally ignore an error or dereference "nothing."

```rust
fn find_task(id: i64, tasks: &[Task]) -> Option<&Task> {
    tasks.iter().find(|t| t.id == id)   // Some(task) or None
}

match find_task(42, &tasks) {
    Some(task) => println!("found {}", task.title),
    None => println!("no such task"),
}
```

### The `?` operator — early return on error

`?` is the workhorse of Rust backends. It means: *"if this is `Err` (or `None`), return it from the current function right now; otherwise unwrap the success value and keep going."*

```rust
async fn get_task(id: i64, pool: &PgPool) -> Result<Task, sqlx::Error> {
    let task = sqlx::query_as::<_, Task>("SELECT * FROM tasks WHERE id = $1")
        .bind(id)
        .fetch_one(pool)
        .await?;   // ← if the query errors, this function returns that error
    Ok(task)
}
```

Read `?` as "unwrap-or-bubble-up." It turns nested error checks into a clean linear pipeline. It only works when the current function returns a compatible `Result` — which is why backend handlers almost always return `Result`.

## 3. Traits — Rust's version of interfaces

A **trait** is a set of behaviors a type can implement (like an interface in other languages). Axum is built almost entirely out of two traits:

**`IntoResponse`** — "anything that can become an HTTP response." A status code, a `Json<T>`, a tuple of both, or your own error type can all implement it, so handlers can return any of them uniformly.

**Extractors** (`FromRequest` / `FromRequestParts`) — "anything that can be pulled out of a request." This is why an Axum handler can just *declare* what it needs as parameters:

```rust
async fn create_task(
    State(pool): State<PgPool>,     // pulled from shared state
    Json(body): Json<NewTask>,      // parsed from the JSON request body
) -> impl IntoResponse { /* ... */ }
```

Each parameter type knows how to build itself from the request. That's dependency injection at compile time, with zero reflection. The `#[derive(...)]` you'll see on structs is the compiler *generating* a trait implementation for you (Serde's `Serialize`/`Deserialize` work this way).

## 4. `async` / `await` — one server, thousands of connections

A Rust backend does **not** spawn a thread per request. Instead, functions marked `async` return a **future** (a paused computation), and `.await` says: *"suspend here until this I/O is ready, and let the runtime do other work meanwhile."*

```rust
// Anything touching the network or disk is async and must be awaited.
let task = get_task(42, &pool).await?;   // while this waits on Postgres,
                                          // the same thread serves other requests
```

**Tokio** is the runtime that schedules all these futures across a small thread pool. The rule of thumb:

> If it touches the **network or disk**, it's `async` and you `.await` it — DB queries, HTTP calls, file reads. CPU-only work stays synchronous.

While one request awaits the database, that OS thread progresses hundreds of others. That's how a small container serves high concurrency.

## You now have the whole toolkit

Ownership (who owns data), `Result`/`Option` + `?` (errors as values), traits (the interface mechanism behind Axum), and `async`/`await` (concurrency). Every remaining step is these four ideas applied to a real problem.

Next: **Step 3 — Project & Workspace Setup**, where we scaffold the Cargo project our Tasks API will live in.
