Part 1: Getting Started with Rust - Setting Up and Basic Types

Introduction

When I decided to build a WAF bypass scanner, I needed a language that was fast, safe, and had excellent async support. Python was too slow for concurrent HTTP requests, and C/C++ required too much manual memory management. Rust offered the perfect balance: performance close to C with memory safety guarantees.

This article covers setting up Rust and understanding the basic types and structures I used in simple-waf-scannerarrow-up-right.

Why Rust for a Security Tool?

My Decision Process

I evaluated several languages before choosing Rust:

Why not Python?

  • Too slow for hundreds of concurrent HTTP requests

  • GIL limits true parallelism

  • Runtime errors instead of compile-time safety

Why not Go?

  • Garbage collection pauses

  • Less control over memory

  • Weaker type system

Why Rust?

  • Zero-cost abstractions - performance without overhead

  • Memory safety without garbage collection

  • Fearless concurrency - compiler prevents data races

  • Rich type system - errors caught at compile time

  • Excellent HTTP and async libraries

Installing Rust

macOS/Linux

Windows

Download and run rustup-init.exearrow-up-right

Update Rust

Creating the Project

Initial Setup

Cargo.toml - Project Manifest

This is my actual project configuration:

Building and Running

Basic Rust Types in My Project

Primitive Types

Strings in Rust

One of Rust's initially confusing aspects:

When to use which?

  • String: When you own the data and may modify it

  • &str: When you're just reading/borrowing the string

Collections

Vectors - Dynamic Arrays

HashMaps - Key-Value Storage

Enums - Core to Rust

Simple Enums

Enums with Data

Option - Handling Null

Rust has no null. Instead, we use Option<T>:

Structs - Building Data Models

Basic Structs

Structs with Derive Macros

Derive macros explained:

  • Debug: Allows printing with {:?}

  • Clone: Enables .clone() to duplicate data

  • Serialize/Deserialize: Converts to/from JSON (from serde)

Reading JSON into Structs

Pattern Matching - Rust's Superpower

Matching Enums

Matching with Guards

Destructuring

Result Type - Error Handling

Basic Result Usage

The ? Operator

Real Example: WAF Detection Structure

Here's actual code from my project:

Common Patterns I Use

Builder Pattern

Iterator Chains

Build and Test

Creating a Simple Binary

Building

Key Takeaways

  1. Cargo manages everything: Dependencies, builds, tests, documentation

  2. Strong typing prevents bugs: Compiler catches errors before runtime

  3. Enums are powerful: Not just constants, they carry data

  4. Option/Result replace null: Explicit handling of missing/error cases

  5. Pattern matching is exhaustive: Compiler ensures all cases handled

  6. Strings have two types: String (owned) vs &str (borrowed)

  7. Derive macros save time: Auto-implement common traits

Common Beginner Mistakes I Made

String Confusion

Forgetting mut

Not Handling Results

Next in Series

In Part 2: Ownership, Borrowing, and Lifetimes, we'll dive into Rust's most unique feature: the ownership system. We'll explore how it enables memory safety without garbage collection and how I use it to share data across concurrent HTTP requests in the scanner.


Based on building simple-waf-scanner, a production security tool written in Rust and published on crates.io.

Last updated