ShitRust Examples

Explore a comprehensive collection of code examples demonstrating ShitRust's features and capabilities.

Examples Index

Navigate to different example categories below to learn ShitRust's capabilities.

Hello World

The traditional starting point for learning a new language.

hello_world.sr
// Hello World program in ShitRust

// Main function where program execution begins
fn main() -> void {
    // Print a greeting to the console with a newline
    println("Hello, ShitRust World!");
    
    // You can also print without a newline
    print("This is printed ");
    print("on the same line.");
    
    // Add a newline manually
    println("");
    
    // Formatted output with variables
    let name = "Developer";
    println("Hello, " + name + "! Welcome to ShitRust!");
    
    // Using string interpolation (similar to f-strings in Python)
    println("The answer is ${40 + 2}");
}

Explanation

  • Every ShitRust program starts with a main function
  • The println function prints text followed by a newline
  • The print function outputs text without a newline
  • String concatenation is done with the + operator
  • String interpolation uses ${expression} syntax

Variables and Types

ShitRust supports various data types and variable declarations.

variables.sr
// Variables and Types in ShitRust

fn main() -> void {
    // Basic variable declaration with type inference
    let name = "Alice";  // String type inferred
    let age = 30;        // Integer type inferred
    let height = 5.9;    // Float type inferred
    let is_student = true; // Boolean type inferred
    
    // Variables are immutable (readonly) by default
    // To create mutable variables, use the 'mut' keyword
    let mut score = 100;
    score = score + 10;  // This is valid
    
    // Explicit type annotations
    let id: int = 12345;
    let price: float = 19.99;
    let message: string = "Hello";
    let active: bool = false;
    
    // Constants - similar to immutable variables but must have a type annotation
    // and are evaluated at compile time
    const PI: float = 3.14159;
    const MAX_USERS: int = 100;
    
    // Multiple variable declarations
    let (x, y) = (10, 20);
    
    // Type aliases provide a new name for an existing type
    type UserID = int;
    let user_id: UserID = 42;
    
    // Printing variables
    println("Name: " + name);
    println("Age: " + age.to_string());
    println("Height: " + height.to_string());
    println("Is student: " + is_student.to_string());
    println("Score: " + score.to_string());
    println("User ID: " + user_id.to_string());
}

Explanation

  • ShitRust supports type inference, but also allows explicit type annotations
  • Basic types: int, float, string, bool, char
  • Variables are immutable by default; use mut to make them mutable
  • Constants are defined with const and require a type annotation
  • Type aliases create new names for existing types using type Name = ExistingType

Control Flow

ShitRust provides various control flow structures for decision making and iterations.

control_flow.sr
// Control Flow in ShitRust

fn main() -> void {
    // If-else statements
    let age = 20;
    
    if age >= 18 {
        println("You are an adult");
    } else {
        println("You are a minor");
    }
    
    // If-else-if ladder
    let score = 85;
    
    if score >= 90 {
        println("Grade: A");
    } else if score >= 80 {
        println("Grade: B");
    } else if score >= 70 {
        println("Grade: C");
    } else if score >= 60 {
        println("Grade: D");
    } else {
        println("Grade: F");
    }
    
    // Conditional (ternary) operator
    let message = age >= 18 ? "Welcome" : "Access denied";
    println(message);
    
    // While loop
    let mut count = 0;
    while count < 5 {
        println("Count: " + count.to_string());
        count = count + 1;
    }
    
    // For loop with range
    println("\nFor loop with range:");
    for i in 0..5 {
        println("Index: " + i.to_string());
    }
    
    // For loop with inclusive range
    println("\nFor loop with inclusive range:");
    for i in 1..=5 {
        println("Number: " + i.to_string());
    }
    
    // For loop with step
    println("\nFor loop with step:");
    for i in (0..10).step_by(2) {
        println("Even: " + i.to_string());
    }
    
    // For loop with array
    let fruits = ["Apple", "Banana", "Cherry", "Date"];
    
    println("\nFor loop over array:");
    for fruit in fruits {
        println("Fruit: " + fruit);
    }
    
    // For loop with index
    println("\nFor loop with index:");
    for (index, fruit) in fruits.enumerate() {
        println(index.to_string() + ": " + fruit);
    }
    
    // Loop with break and continue
    println("\nLoop with break and continue:");
    for i in 0..10 {
        if i == 3 {
            println("Skipping 3");
            continue;
        }
        
        if i == 7 {
            println("Breaking at 7");
            break;
        }
        
        println("Number: " + i.to_string());
    }
    
    // Infinite loop with break
    println("\nInfinite loop with break:");
    let mut counter = 0;
    loop {
        println("Counter: " + counter.to_string());
        counter = counter + 1;
        
        if counter >= 5 {
            break;
        }
    }
    
    // Match expression (like switch but more powerful)
    let day = "Wednesday";
    
    println("\nMatch expression:");
    match day {
        "Monday" => println("Start of work week"),
        "Tuesday" | "Wednesday" | "Thursday" => println("Mid week"),
        "Friday" => println("End of work week"),
        "Saturday" | "Sunday" => println("Weekend"),
        _ => println("Invalid day")  // Default case
    }
    
    // Match with values
    let num = 42;
    
    match num {
        0 => println("Zero"),
        1..=9 => println("Single digit"),
        10..=99 => println("Double digit"),
        100..=999 => println("Triple digit"),
        _ => println("More than three digits")
    }
}

Explanation

  • Conditional statements: if, else if, else
  • Ternary operator: condition ? value_if_true : value_if_false
  • Loop types: for, while, loop (infinite)
  • Range syntax: start..end (exclusive) or start..=end (inclusive)
  • Loop control: break and continue
  • Pattern matching with match for elegant control flow

Functions

Functions are the building blocks of ShitRust code, allowing for modular and reusable logic.

functions.sr
// Functions in ShitRust

// Basic function with no parameters and no return value
fn greet() -> void {
    println("Hello, world!");
}

// Function with parameters
fn greet_person(name: string) -> void {
    println("Hello, " + name + "!");
}

// Function with return value
fn add(a: int, b: int) -> int {
    return a + b;
}

// Function with multiple return values using tuple
fn get_dimensions() -> (int, int) {
    let width = 1920;
    let height = 1080;
    return (width, height);
}

// Function with default parameter values
fn create_user(name: string, age: int = 18, is_active: bool = true) -> void {
    println("Creating user: " + name);
    println("Age: " + age.to_string());
    println("Active: " + is_active.to_string());
}

// Function with named arguments
fn connect(host: string, port: int, timeout: int, ssl: bool) -> void {
    println("Connecting to " + host + ":" + port.to_string());
    println("Timeout: " + timeout.to_string() + "ms");
    println("SSL: " + ssl.to_string());
}

// Recursive function
fn factorial(n: int) -> int {
    if n <= 1 {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

// Higher-order function that takes a function as an argument
fn apply_twice(f: fn(int) -> int, x: int) -> int {
    return f(f(x));
}

// Function to be passed to the higher-order function
fn double(x: int) -> int {
    return x * 2;
}

// Anonymous function (lambda)
let square = fn(x: int) -> int {
    return x * x;
};

// Main function
fn main() -> void {
    // Calling a basic function
    greet();
    
    // Calling a function with arguments
    greet_person("Alice");
    
    // Using the return value of a function
    let sum = add(5, 3);
    println("5 + 3 = " + sum.to_string());
    
    // Destructuring multiple return values
    let (width, height) = get_dimensions();
    println("Resolution: " + width.to_string() + "x" + height.to_string());
    
    // Using default parameter values
    println("\nDefault parameters:");
    create_user("Bob");
    create_user("Charlie", 25);
    create_user("David", 30, false);
    
    // Using named arguments
    println("\nNamed arguments:");
    connect(
        host = "example.com",
        port = 8080,
        timeout = 30000,
        ssl = true
    );
    
    // Using positional arguments (allowed to mix with named)
    connect("localhost", 3000, timeout = 5000, ssl = false);
    
    // Using a recursive function
    let fact5 = factorial(5);
    println("\nFactorial of 5: " + fact5.to_string());
    
    // Using a higher-order function
    let result = apply_twice(double, 3);
    println("Double applied twice to 3: " + result.to_string());
    
    // Using a lambda function
    let squared = square(4);
    println("4 squared: " + squared.to_string());
    
    // Inline lambda
    let cubed = (fn(x: int) -> int { return x * x * x; })(3);
    println("3 cubed: " + cubed.to_string());
    
    // Function as a return value
    let operation = get_operation("multiply");
    println("5 * 3 = " + operation(5, 3).to_string());
}

// Function that returns a function
fn get_operation(op_name: string) -> fn(int, int) -> int {
    if op_name == "add" {
        return fn(a: int, b: int) -> int { return a + b; };
    } else if op_name == "subtract" {
        return fn(a: int, b: int) -> int { return a - b; };
    } else if op_name == "multiply" {
        return fn(a: int, b: int) -> int { return a * b; };
    } else {
        // Default to division
        return fn(a: int, b: int) -> int { 
            if b == 0 {
                println("Error: Division by zero");
                return 0;
            }
            return a / b; 
        };
    }
}

Explanation

  • Functions are defined with the fn keyword
  • Return type is specified after ->
  • Use void for functions that don't return a value
  • Return multiple values using tuples
  • Support for default parameter values
  • Support for named arguments for better readability
  • Functions are first-class citizens - can be passed as arguments
  • Support for anonymous functions (lambdas)
  • Functions can return other functions

Traits and Generics

ShitRust supports traits (similar to interfaces) and generic programming.

traits_and_generics.sr
// Traits and Generics Example

// Define a trait for types that can be converted to string
trait ToString {
    // Method without implementation must be implemented by types
    fn to_string() -> string;
    
    // Method with default implementation (can be overridden)
    fn to_debug_string() -> string {
        return "ToString object: " + this.to_string();
    }
}

// Define a trait with generic parameters
trait Comparable {
    fn compare(other: T) -> int;
    
    // Default implementations using the compare method
    fn equals(other: T) -> bool {
        return this.compare(other) == 0;
    }
    
    fn less_than(other: T) -> bool {
        return this.compare(other) < 0;
    }
    
    fn greater_than(other: T) -> bool {
        return this.compare(other) > 0;
    }
}

// Define a struct to represent a Point
struct Point {
    x: int,
    y: int,
    
    // Constructor
    fn new(x: int, y: int) -> Point {
        return Point { x: x, y: y };
    }
}

// Implement ToString trait for Point
impl ToString for Point {
    fn to_string() -> string {
        return "Point(" + this.x.to_string() + ", " + this.y.to_string() + ")";
    }
    
    // Override the default implementation
    fn to_debug_string() -> string {
        return "DEBUG: Point at x=" + this.x.to_string() + ", y=" + this.y.to_string();
    }
}

// Implement Comparable trait for Point
impl Comparable for Point {
    fn compare(other: Point) -> int {
        // Compare based on distance from origin
        let this_dist = this.x * this.x + this.y * this.y;
        let other_dist = other.x * other.x + other.y * other.y;
        
        if this_dist < other_dist {
            return -1;
        } else if this_dist > other_dist {
            return 1;
        } else {
            return 0;
        }
    }
}

// Generic function to find the minimum of two values
fn min>(a: T, b: T) -> T {
    if a.less_than(b) {
        return a;
    } else {
        return b;
    }
}

// Main function to demonstrate traits and generics
fn main() -> void {
    let p1 = Point.new(3, 4);
    let p2 = Point.new(1, 2);
    
    // Using trait methods
    println(p1.to_string());
    println(p1.to_debug_string());
    
    // Using Comparable trait methods
    if p1.greater_than(p2) {
        println("p1 is farther from origin than p2");
    } else {
        println("p2 is farther from origin than p1");
    }
    
    // Using generic function
    let closest = min(p1, p2);
    println("Closest point to origin: " + closest.to_string());
}

Explanation

  • trait defines an interface that types can implement
  • Traits can have methods with or without default implementations
  • Use impl TraitName for TypeName to implement a trait
  • Generic parameters are defined with <T> syntax
  • Trait bounds <T: TraitName> ensure the type implements the required trait
  • The this keyword refers to the current instance in methods

Structs

Structs are used to create custom data types that group related data together.

structs.sr
// Structs in ShitRust

// Basic struct definition
struct Person {
    name: string,
    age: int,
    address: string
}

// Struct with methods
struct Rectangle {
    width: float,
    height: float,
    
    // Method to calculate area
    fn area() -> float {
        return this.width * this.height;
    }
    
    // Method to calculate perimeter
    fn perimeter() -> float {
        return 2 * (this.width + this.height);
    }
    
    // Static method (constructor)
    fn new(width: float, height: float) -> Rectangle {
        return Rectangle { width: width, height: height };
    }
    
    // Static method to create a square
    fn square(size: float) -> Rectangle {
        return Rectangle { width: size, height: size };
    }
}

// Nested structs
struct Address {
    street: string,
    city: string,
    postal_code: string,
    country: string
}

struct Employee {
    id: int,
    name: string,
    email: string,
    address: Address,
    department: string
}

// Generic struct
struct Pair {
    first: T,
    second: U,
    
    fn new(first: T, second: U) -> Pair {
        return Pair { first: first, second: second };
    }
    
    fn swap() -> Pair {
        return Pair { first: this.second, second: this.first };
    }
}

fn main() -> void {
    // Creating a struct instance
    let alice = Person {
        name: "Alice",
        age: 30,
        address: "123 Main St"
    };
    
    // Accessing struct fields
    println("Name: " + alice.name);
    println("Age: " + alice.age.to_string());
    println("Address: " + alice.address);
    
    // Default values for unspecified fields
    let bob = Person {
        name: "Bob",
        ..Default::default()
    };
    println("\nBob's age (default): " + bob.age.to_string());
    
    // Creating an instance with constructor
    let rect = Rectangle.new(5.0, 3.0);
    
    // Using methods
    println("\nRectangle dimensions: " + rect.width.to_string() + " x " + rect.height.to_string());
    println("Area: " + rect.area().to_string());
    println("Perimeter: " + rect.perimeter().to_string());
    
    // Using static factory method
    let square = Rectangle.square(4.0);
    println("\nSquare area: " + square.area().to_string());
    
    // Nested structs
    let emp = Employee {
        id: 101,
        name: "Charlie",
        email: "charlie@example.com",
        address: Address {
            street: "456 Oak Avenue",
            city: "Techville",
            postal_code: "12345",
            country: "Codeland"
        },
        department: "Engineering"
    };
    
    println("\nEmployee details:");
    println("Name: " + emp.name);
    println("City: " + emp.address.city);
    
    // Creating a generic Pair
    let p1 = Pair.new(42, "answer");
    println("\nPair: (" + p1.first.to_string() + ", " + p1.second + ")");
    
    // Swapping the pair elements
    let p2 = p1.swap();
    println("Swapped: (" + p2.first + ", " + p2.second.to_string() + ")");
    
    // Struct update syntax
    let rect2 = Rectangle {
        width: 10.0,
        ..rect
    };
    println("\nUpdated rectangle dimensions: " + rect2.width.to_string() + " x " + rect2.height.to_string());
}

Explanation

  • Structs are defined with the struct keyword
  • Struct fields are specified with name-type pairs
  • Methods are functions defined inside the struct block
  • The this keyword refers to the current instance
  • Static methods (like constructors) don't use this
  • Structs can be generic with type parameters
  • Nested structs allow for complex data organization
  • The .. syntax allows for struct updates and defaults

Enums

Enums define a type by enumerating its possible variants, which can optionally carry data.

enums.sr
// Enums in ShitRust

// Basic enum
enum Direction {
    North,
    East,
    South,
    West
}

// Enum with associated values
enum Shape {
    Circle(float),                  // Radius
    Rectangle(float, float),        // Width, Height
    Triangle(float, float, float)   // Three sides
}

// Enum with named fields
enum Message {
    Quit,
    Move { x: int, y: int },
    Write(string),
    ChangeColor(int, int, int)
}

// Generic enum
enum Option {
    Some(T),
    None
}

// Result enum for error handling
enum Result {
    Ok(T),
    Err(E)
}

// Enum with methods
impl Direction {
    fn to_string() -> string {
        match this {
            Direction::North => return "North",
            Direction::East => return "East",
            Direction::South => return "South",
            Direction::West => return "West"
        }
    }
    
    fn opposite() -> Direction {
        match this {
            Direction::North => return Direction::South,
            Direction::East => return Direction::West,
            Direction::South => return Direction::North,
            Direction::West => return Direction::East
        }
    }
}

// Methods for Shape
impl Shape {
    fn area() -> float {
        match this {
            Shape::Circle(radius) => {
                const PI: float = 3.14159;
                return PI * radius * radius;
            },
            Shape::Rectangle(width, height) => {
                return width * height;
            },
            Shape::Triangle(a, b, c) => {
                // Heron's formula
                let s = (a + b + c) / 2.0;
                return (s * (s - a) * (s - b) * (s - c)).sqrt();
            }
        }
    }
}

fn main() -> void {
    // Using basic enum
    let direction = Direction::North;
    
    println("Direction: " + direction.to_string());
    println("Opposite: " + direction.opposite().to_string());
    
    // Pattern matching with enum
    match direction {
        Direction::North => println("Heading North"),
        Direction::East => println("Heading East"),
        Direction::South => println("Heading South"),
        Direction::West => println("Heading West")
    }
    
    // Using enum with associated values
    let shapes = [
        Shape::Circle(5.0),
        Shape::Rectangle(4.0, 6.0),
        Shape::Triangle(3.0, 4.0, 5.0)
    ];
    
    println("\nCalculating areas of shapes:");
    for (i, shape) in shapes.enumerate() {
        let shape_type = match shape {
            Shape::Circle(_) => "Circle",
            Shape::Rectangle(_, _) => "Rectangle",
            Shape::Triangle(_, _, _) => "Triangle"
        };
        
        println("Shape " + (i + 1).to_string() + " (" + shape_type + "): " + shape.area().to_string());
    }
    
    // Using enum with named fields
    let messages = [
        Message::Quit,
        Message::Move { x: 10, y: 20 },
        Message::Write("Hello, ShitRust!"),
        Message::ChangeColor(255, 0, 255)
    ];
    
    println("\nProcessing messages:");
    for msg in messages {
        process_message(msg);
    }
    
    // Using Option enum
    let numbers = [1, 2, 3, 4, 5];
    let first = first_even(numbers);
    
    println("\nFirst even number:");
    match first {
        Option::Some(n) => println("Found: " + n.to_string()),
        Option::None => println("No even numbers found")
    }
    
    // Using Result enum
    let result = divide(10, 2);
    match result {
        Result::Ok(value) => println("\n10 / 2 = " + value.to_string()),
        Result::Err(error) => println("\nError: " + error)
    }
    
    let result_error = divide(10, 0);
    match result_error {
        Result::Ok(value) => println("10 / 0 = " + value.to_string()),
        Result::Err(error) => println("Error: " + error)
    }
}

// Function to process Message enum
fn process_message(msg: Message) -> void {
    match msg {
        Message::Quit => {
            println("Quitting application");
        },
        Message::Move { x, y } => {
            println("Moving to position: (" + x.to_string() + ", " + y.to_string() + ")");
        },
        Message::Write(text) => {
            println("Writing message: " + text);
        },
        Message::ChangeColor(r, g, b) => {
            println("Changing color to RGB: (" + r.to_string() + ", " + g.to_string() + ", " + b.to_string() + ")");
        }
    }
}

// Function that returns an Option
fn first_even(numbers: [int]) -> Option {
    for num in numbers {
        if num % 2 == 0 {
            return Option::Some(num);
        }
    }
    return Option::None;
}

// Function that returns a Result
fn divide(a: int, b: int) -> Result {
    if b == 0 {
        return Result::Err("Division by zero");
    }
    
    return Result::Ok(a as float / b as float);
}

Explanation

  • Enums are defined with the enum keyword
  • Enum variants can be simple identifiers or carry data
  • Variants can have unnamed fields (tuple-like) or named fields (struct-like)
  • Access enum variants using the :: operator
  • Pattern matching with match is commonly used with enums
  • Methods can be implemented for enums using impl
  • Option<T> represents an optional value
  • Result<T, E> represents success or failure

Collections

ShitRust provides several collection types for storing and manipulating groups of data.

collections.sr
// Collections in ShitRust

fn main() -> void {
    // Arrays - fixed size, same type
    println("===== Arrays =====");
    let numbers = [1, 2, 3, 4, 5];
    
    // Accessing array elements
    println("numbers[2] = " + numbers[2].to_string());
    
    // Getting array length
    println("Array length: " + numbers.length().to_string());
    
    // Iterating over an array
    println("Array elements:");
    for n in numbers {
        println("  " + n.to_string());
    }
    
    // Creating an array with repeated value
    let zeros = [0; 5]; // Creates [0, 0, 0, 0, 0]
    println("Zeros: " + zeros.to_string());
    
    // Arrays with explicit type
    let floats: [float; 3] = [1.1, 2.2, 3.3];
    println("Floats: " + floats.to_string());
    
    // Multi-dimensional arrays
    let matrix = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]
    ];
    println("Matrix[1][2] = " + matrix[1][2].to_string());
    
    // Vectors - dynamic size, same type
    println("\n===== Vectors =====");
    let mut fruits = Vec::new();
    
    // Adding elements
    fruits.push("Apple");
    fruits.push("Banana");
    fruits.push("Cherry");
    
    println("Fruits vector: " + fruits.to_string());
    
    // Removing elements
    let removed = fruits.pop();
    println("Removed: " + removed);
    println("Fruits after pop: " + fruits.to_string());
    
    // Inserting at specific index
    fruits.insert(1, "Blueberry");
    println("Fruits after insert: " + fruits.to_string());
    
    // Removing at specific index
    fruits.remove(0);
    println("Fruits after remove: " + fruits.to_string());
    
    // Vector with initial values
    let colors = vec!["Red", "Green", "Blue"];
    println("Colors: " + colors.to_string());
    
    // Vector with capacity
    let mut numbers_vec = Vec::with_capacity(10);
    println("Initial capacity: " + numbers_vec.capacity().to_string());
    
    for i in 0..5 {
        numbers_vec.push(i * 2);
    }
    
    println("Numbers vector: " + numbers_vec.to_string());
    println("Length: " + numbers_vec.length().to_string());
    println("Capacity: " + numbers_vec.capacity().to_string());
    
    // HashMap - key-value pairs
    println("\n===== HashMaps =====");
    let mut scores = HashMap::new();
    
    // Adding key-value pairs
    scores.insert("Alice", 98);
    scores.insert("Bob", 87);
    scores.insert("Charlie", 92);
    
    println("Scores: " + scores.to_string());
    
    // Accessing values
    let bob_score = scores.get("Bob");
    println("Bob's score: " + bob_score.to_string());
    
    // Checking if key exists
    if scores.contains_key("Dave") {
        println("Dave's score exists");
    } else {
        println("Dave's score doesn't exist");
    }
    
    // Updating a value
    scores.insert("Bob", 90); // Overwrites existing value
    println("Bob's updated score: " + scores.get("Bob").to_string());
    
    // Only insert if key doesn't exist
    scores.entry("Dave").or_insert(75);
    scores.entry("Bob").or_insert(60); // Won't change Bob's score
    println("Scores after entry API: " + scores.to_string());
    
    // Removing entries
    scores.remove("Charlie");
    println("Scores after remove: " + scores.to_string());
    
    // Iterating over HashMap
    println("All scores:");
    for (name, score) in scores {
        println("  " + name + ": " + score.to_string());
    }
    
    // HashSet - unique values
    println("\n===== HashSets =====");
    let mut unique_numbers = HashSet::new();
    
    // Adding elements
    unique_numbers.insert(1);
    unique_numbers.insert(2);
    unique_numbers.insert(3);
    unique_numbers.insert(2); // Duplicate, won't be added
    
    println("Unique numbers: " + unique_numbers.to_string());
    println("Size: " + unique_numbers.length().to_string());
    
    // Checking if value exists
    if unique_numbers.contains(2) {
        println("Set contains 2");
    }
    
    // Removing elements
    unique_numbers.remove(1);
    println("After removing 1: " + unique_numbers.to_string());
    
    // Set operations
    let set1 = HashSet::from([1, 2, 3, 4]);
    let set2 = HashSet::from([3, 4, 5, 6]);
    
    // Union
    let union = set1.union(set2);
    println("Union: " + union.to_string());
    
    // Intersection
    let intersection = set1.intersection(set2);
    println("Intersection: " + intersection.to_string());
    
    // Difference
    let difference = set1.difference(set2);
    println("Difference (set1 - set2): " + difference.to_string());
    
    // Queue implementation
    println("\n===== Queue =====");
    let mut queue = VecDeque::new();
    
    // Adding elements (enqueue)
    queue.push_back("First");
    queue.push_back("Second");
    queue.push_back("Third");
    
    println("Queue: " + queue.to_string());
    
    // Removing elements (dequeue)
    let front = queue.pop_front();
    println("Dequeued: " + front);
    println("Queue after dequeue: " + queue.to_string());
    
    // Stack implementation
    println("\n===== Stack =====");
    let mut stack = Vec::new();
    
    // Adding elements (push)
    stack.push("Bottom");
    stack.push("Middle");
    stack.push("Top");
    
    println("Stack: " + stack.to_string());
    
    // Removing elements (pop)
    let top = stack.pop();
    println("Popped: " + top);
    println("Stack after pop: " + stack.to_string());
}

Explanation

  • Arrays: Fixed-size collections of elements with the same type
  • Vectors: Dynamic-size arrays that can grow or shrink
  • HashMaps: Collections of key-value pairs for efficient lookups
  • HashSets: Collections of unique values with fast lookups
  • VecDeque: Double-ended queue implementation
  • Collections provide methods for adding, removing, and accessing elements
  • Each collection type has specific performance characteristics
  • You can iterate over collections using for loops

String Manipulation

ShitRust provides powerful features for working with text and string data.

string_manipulation.sr
// String Manipulation in ShitRust

fn main() -> void {
    // Creating strings
    let greeting = "Hello";
    let name = "World";
    
    // String concatenation
    let message = greeting + ", " + name + "!";
    println(message);
    
    // String formatting with interpolation
    let formatted = "The answer is ${40 + 2}";
    println(formatted);
    
    // Multi-line strings
    let multi_line = """
        This is a multi-line string.
        It can span multiple lines
        without escape characters.
        Indentation is preserved.
    """;
    println(multi_line);
    
    // Raw strings (no escape processing)
    let path = r"C:\Users\username\Documents";
    println("Path: " + path);
    
    // String length
    let text = "Hello, World!";
    println("Length: " + text.length().to_string());
    
    // Accessing characters
    println("First character: " + text[0]);
    println("Last character: " + text[text.length() - 1]);
    
    // Substring (slice)
    let slice = text.substring(0, 5);
    println("Slice: " + slice);
    
    // Splitting strings
    let csv = "apple,banana,cherry,date";
    let fruits = csv.split(",");
    println("Fruits:");
    for fruit in fruits {
        println("  " + fruit);
    }
    
    // Joining strings
    let words = ["ShitRust", "is", "awesome"];
    let sentence = words.join(" ");
    println("Joined: " + sentence);
    
    // Checking if string contains substring
    if text.contains("World") {
        println("Contains 'World'");
    }
    
    // Checking if string starts/ends with
    println("Starts with 'Hello': " + text.starts_with("Hello"));
    println("Ends with '!': " + text.ends_with("!"));
    
    // Converting case
    println("Uppercase: " + text.to_uppercase());
    println("Lowercase: " + text.to_lowercase());
    
    // Trimming whitespace
    let padded = "   trimmed   ";
    println("Trimmed: '" + padded.trim() + "'");
    println("Left trimmed: '" + padded.trim_start() + "'");
    println("Right trimmed: '" + padded.trim_end() + "'");
    
    // Replacing substrings
    let replaced = text.replace("World", "ShitRust");
    println("Replaced: " + replaced);
    
    // Checking if string matches a pattern
    let email = "user@example.com";
    let is_valid = email.matches(r"^[\w.-]+@[\w.-]+\.\w+$");
    println("Valid email: " + is_valid.to_string());
    
    // String repetition
    let stars = "*".repeat(10);
    println("Stars: " + stars);
    
    // Character counting
    let text_with_spaces = "Hello, ShitRust World!";
    let space_count = text_with_spaces.count(" ");
    println("Space count: " + space_count.to_string());
    
    // Finding substrings
    let index = text.index_of("World");
    if index != -1 {
        println("'World' found at index: " + index.to_string());
    }
    
    // Converting to/from other types
    let num = 42;
    let num_str = num.to_string();
    println("Number as string: " + num_str);
    
    let parsed = "123".parse::();
    println("Parsed int: " + parsed.to_string());
    
    // String interpolation with formatting
    let pi = 3.14159;
    let formatted_pi = "Pi is approximately ${pi::.2}";
    println(formatted_pi);
    
    // String comparisons
    println("'apple' < 'banana': " + ("apple" < "banana").to_string());
    println("'hello' == 'Hello': " + ("hello" == "Hello").to_string());
    
    // Case-insensitive comparison
    println("Case-insensitive equals: " + text.to_lowercase() == "hello, world!".to_string());
    
    // String builder for efficient concatenation
    let mut builder = StringBuilder::new();
    builder.append("Building ");
    builder.append("a ");
    builder.append("string ");
    builder.append("efficiently.");
    
    let result = builder.to_string();
    println("StringBuilder result: " + result);
}

Explanation

  • Strings are sequences of characters with various manipulation methods
  • Common operations: concatenation, substring, split, join, case conversion
  • String interpolation: ${expression} syntax embedded in strings
  • Special string literals: multi-line strings, raw strings
  • String methods: contains, starts_with, ends_with, replace
  • Pattern matching with regular expressions using matches
  • StringBuilder for efficient string concatenation
  • Conversion between strings and other types

Pipeline Operator

The pipeline operator |> allows for clean, functional-style data transformations.

pipeline_operator.sr
// Pipeline Operator in ShitRust

// The pipeline operator (|>) enables functional programming by allowing 
// operations to be chained in a left-to-right manner, improving readability.

// Function to double a number
fn double(x: int) -> int {
    return x * 2;
}

// Function to add a number
fn add(x: int, y: int) -> int {
    return x + y;
}

// Function to square a number
fn square(x: int) -> int {
    return x * x;
}

// Function to filter even numbers
fn is_even(x: int) -> bool {
    return x % 2 == 0;
}

// Function to sum an array of numbers
fn sum(numbers: [int]) -> int {
    let total = 0;
    for n in numbers {
        total += n;
    }
    return total;
}

// Function to format a name
fn format_name(name: string) -> string {
    return name.trim().to_uppercase();
}

// Function to filter names by length
fn longer_than(names: [string], length: int) -> [string] {
    return [name for name in names if name.length() > length];
}

fn main() -> void {
    println("===== Pipeline Operator Examples =====");
    
    // Without pipeline
    println("\nWithout pipeline:");
    let result1 = square(add(double(5), 3));
    println("square(add(double(5), 3)) = " + result1.to_string());
    
    // With pipeline
    println("\nWith pipeline:");
    let result2 = 5 |> double |> add(_, 3) |> square;
    println("5 |> double |> add(_, 3) |> square = " + result2.to_string());
    
    // Working with arrays
    let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // Traditional nested approach
    println("\nSum of even squares (traditional):");
    let filtered = [n for n in numbers if is_even(n)];
    let squared = [square(n) for n in filtered];
    let total = sum(squared);
    println(total.to_string());
    
    // Pipeline approach
    println("Sum of even squares (pipeline):");
    let pipeline_total = numbers
        |> [n for n in _ if is_even(n)]
        |> [square(n) for n in _]
        |> sum;
    println(pipeline_total.to_string());
    
    // Text processing example
    let text = "The quick brown fox jumps over the lazy dog";
    
    // Traditional approach
    println("\nWord count (traditional):");
    let lowercase = text.to_lowercase();
    let no_punctuation = lowercase.replace(".", "").replace(",", "");
    let words = no_punctuation.split(" ");
    println(words.length().to_string());
    
    // Pipeline approach
    println("Word count (pipeline):");
    let word_count = text
        |> _.to_lowercase()
        |> _.replace(".", "")
        |> _.replace(",", "")
        |> _.split(" ")
        |> _.length();
    println(word_count.to_string());
    
    // Math operations
    println("\nMath operations:");
    let math_result = 10
        |> add(_, 5)      // 10 + 5 = 15
        |> double         // 15 * 2 = 30
        |> square         // 30 * 30 = 900
        |> add(100, _);   // 100 + 900 = 1000
    println(math_result.to_string());
    
    // Array transformation
    let names = ["  Alice", "Bob  ", "Charlie", "Dave", "Eve", "   Frank"];
    
    println("\nArray transformation:");
    let formatted_names = names
        |> longer_than(_, 3)
        |> [format_name(name) for name in _];
    
    println("Formatted names:");
    for name in formatted_names {
        println("  " + name);
    }
    
    // Working with objects
    struct User {
        id: int,
        name: string,
        active: bool
    }
    
    let users = [
        User { id: 1, name: "Alice", active: true },
        User { id: 2, name: "Bob", active: false },
        User { id: 3, name: "Charlie", active: true },
        User { id: 4, name: "Dave", active: true },
        User { id: 5, name: "Eve", active: false }
    ];
    
    println("\nActive user names:");
    let active_names = users
        |> [user for user in _ if user.active]
        |> [user.name for user in _];
    
    for name in active_names {
        println("  " + name);
    }
}

Explanation

  • The pipeline operator |> passes the result of one operation as input to the next
  • It improves code readability by showing data flow from left to right
  • The placeholder _ indicates where the piped value should be inserted
  • When no placeholder is used, the value is passed as the first argument
  • Pipeline operator works with functions, methods, and list comprehensions
  • It's especially useful for data transformations and functional programming
  • Reduces the need for intermediate variables and nested function calls
  • Makes complex operations more readable and maintainable

Async Programming

ShitRust supports asynchronous programming with async/await syntax.

async_programming.sr
// Async Programming in ShitRust

// Import the time module
use time;

// Define a Result type for error handling
enum Result {
    Ok(T),
    Err(E)
}

// Simulate an asynchronous API call
async fn fetch_data(url: string) -> Result {
    // Simulate network delay
    await time.sleep(1000);
    
    // Simulate a 10% chance of error
    let random = (time.now() % 10) as int;
    if random == 0 {
        return Result::Err("Network error: failed to fetch " + url);
    }
    
    // Return success with mock data
    return Result::Ok("Data from " + url + " (fetched at " + time.now().to_string() + ")");
}

// Process multiple API calls concurrently
async fn fetch_multiple(urls: [string]) -> [Result] {
    // Create a list of promises by mapping each URL to a fetch operation
    let promises = [fetch_data(url) for url in urls];
    
    // Wait for all promises to resolve and return the results
    let results = await Promise.all(promises);
    return results;
}

// Main async function
async fn main() -> void {
    println("Starting async operations...");
    
    // Single async call with await
    println("Fetching a single resource...");
    let result = await fetch_data("https://api.example.com/users");
    
    match result {
        Result::Ok(data) => println("Success: " + data),
        Result::Err(err) => println("Error: " + err)
    }
    
    // Multiple concurrent async calls
    println("\nFetching multiple resources concurrently...");
    let urls = [
        "https://api.example.com/users",
        "https://api.example.com/posts",
        "https://api.example.com/comments"
    ];
    
    let start_time = time.now();
    let results = await fetch_multiple(urls);
    let end_time = time.now();
    
    println("All requests completed in " + (end_time - start_time).to_string() + "ms");
    
    // Process all results
    for i in 0..results.length() {
        println("Request " + (i + 1).to_string() + " to " + urls[i] + ":");
        match results[i] {
            Result::Ok(data) => println("  Success: " + data),
            Result::Err(err) => println("  Error: " + err)
        }
    }
    
    // Using try/catch with async
    println("\nUsing try/catch with async code:");
    try {
        let data = await fetch_data("https://api.example.com/error");
        println("This might not execute if an error occurs");
    } catch err {
        println("Caught error: " + err.to_string());
    }
    
    println("\nAsync operations complete!");
}

Explanation

  • Use the async keyword to define asynchronous functions
  • The await keyword pauses execution until a promise resolves
  • Asynchronous functions return promises that can be awaited
  • Use Promise.all() to run multiple async operations concurrently
  • Combine async/await with error handling using Result types or try/catch
  • Async code executes more efficiently by not blocking during I/O operations

Error Handling

ShitRust provides comprehensive error handling mechanisms combining Rust-like Result types and try/catch blocks.

error_handling.sr
// Error Handling in ShitRust

// Define a custom Result type for returning success or error
enum Result {
    Ok(T),
    Err(E)
}

// Define a custom error type
struct FileError {
    code: int,
    message: string,
    
    fn new(code: int, message: string) -> FileError {
        return FileError { code: code, message: message };
    }
    
    fn to_string() -> string {
        return "FileError [" + this.code.to_string() + "]: " + this.message;
    }
}

// Function that can fail, returning a Result
fn read_file(path: string) -> Result {
    // Simulate file operations that might fail
    if path.ends_with(".txt") {
        // Successful case
        return Result::Ok("Content of " + path);
    } else if path == "" {
        // Error case: empty path
        return Result::Err(FileError.new(1, "Empty file path"));
    } else {
        // Error case: unsupported file type
        return Result::Err(FileError.new(2, "Unsupported file type"));
    }
}

// Function for division that can fail
fn divide(a: float, b: float) -> Result {
    if b == 0.0 {
        return Result::Err("Division by zero");
    }
    return Result::Ok(a / b);
}

// Function that propagates errors with the ? operator
fn process_file(path: string) -> Result {
    let content = read_file(path)?;
    return Result::Ok("Processed: " + content);
}

// Function that throws exceptions (for use with try/catch)
fn parse_json(json: string) -> void {
    if !json.starts_with("{") && !json.starts_with("[") {
        throw "Invalid JSON format";
    }
    
    if json.contains("error") {
        throw {
            type: "JsonParseError",
            message: "Error field found in JSON"
        };
    }
    
    println("JSON parsed successfully");
}

// Main function to demonstrate error handling
fn main() -> void {
    println("===== Result-based Error Handling =====");
    
    // Using match with Result
    let result1 = read_file("data.txt");
    match result1 {
        Result::Ok(content) => println("Successfully read file: " + content),
        Result::Err(error) => println("Failed to read file: " + error.to_string())
    }
    
    // Using if-let for concise success case handling
    if let Result::Ok(content) = read_file("config.txt") {
        println("Configuration loaded: " + content);
    }
    
    // Using unwrap (will panic on error)
    println("\nUsing unwrap (safe in this case, we know it's Ok):");
    let content = read_file("safe.txt").unwrap();
    println("Unwrapped content: " + content);
    
    // Using unwrap_or for fallback value
    println("\nUsing unwrap_or for fallback:");
    let result2 = read_file("nonexistent.dat");
    let fallback_content = result2.unwrap_or("Default content");
    println("Content: " + fallback_content);
    
    // Using the ? operator to propagate errors
    println("\nUsing the ? operator:");
    let process_result = process_file("data.txt");
    match process_result {
        Result::Ok(result) => println(result),
        Result::Err(error) => println("Process failed: " + error.to_string())
    }
    
    // Chaining operations
    println("\nChaining operations:");
    let division_result = divide(10.0, 2.0)
        .and_then(|result| divide(result, 2.0));
    
    match division_result {
        Result::Ok(value) => println("10 / 2 / 2 = " + value.to_string()),
        Result::Err(error) => println("Division error: " + error)
    }
    
    println("\n===== Exception-based Error Handling =====");
    
    // Basic try/catch
    println("\nBasic try/catch:");
    try {
        parse_json("{\"name\": \"Alice\"}");
    } catch e {
        println("Caught exception: " + e.to_string());
    }
    
    // Try/catch with error type checking
    println("\nTry/catch with error type checking:");
    try {
        parse_json("{\"status\": \"error\"}");
    } catch e {
        if typeof e == "object" && e.type == "JsonParseError" {
            println("JSON parse error: " + e.message);
        } else {
            println("Other error: " + e.to_string());
        }
    }
    
    // Try/catch/finally
    println("\nTry/catch/finally:");
    try {
        parse_json("not a json");
        println("This won't execute if an error occurs");
    } catch e {
        println("Caught error: " + e.to_string());
    } finally {
        println("Finally block always executes");
    }
    
    // Nested try/catch
    println("\nNested try/catch:");
    try {
        println("Outer try block");
        try {
            throw "Inner exception";
        } catch e {
            println("Inner catch: " + e.to_string());
            // Re-throw or handle further
        }
        println("After inner try/catch");
    } catch e {
        println("Outer catch: " + e.to_string());
    }
    
    // Combining Result and try/catch
    println("\nCombining Result and try/catch:");
    try {
        let result = divide(10.0, 0.0);
        match result {
            Result::Ok(value) => println("Result: " + value.to_string()),
            Result::Err(error) => throw "Division error: " + error
        }
    } catch e {
        println("Caught: " + e.to_string());
    }
}

Explanation

  • ShitRust offers two complementary error handling approaches
  • Result-based error handling is ideal for expected failure cases
  • Exception-based handling with try/catch is useful for unexpected errors
  • The ? operator provides elegant error propagation
  • unwrap() extracts the value from a Result (panics on error)
  • Use pattern matching with match for comprehensive error handling
  • Methods like and_then() allow for chaining operations
  • Try/catch blocks can have finally sections for cleanup code

Web Server

Build a simple web server in ShitRust that can handle HTTP requests.

web_server.sr
// Simple Web Server in ShitRust

// Import required modules
use http;
use fs;
use time;
use path;

// Define a struct to represent an HTTP response
struct HttpResponse {
    status: int,
    headers: HashMap,
    body: string,
    
    // Constructor for success responses (200 OK)
    fn ok(body: string, content_type: string = "text/html") -> HttpResponse {
        let headers = HashMap::new();
        headers.insert("Content-Type", content_type);
        headers.insert("Content-Length", body.length().to_string());
        headers.insert("Server", "ShitRustServer/0.1");
        headers.insert("Date", time.now().to_http_date());
        
        return HttpResponse {
            status: 200,
            headers: headers,
            body: body
        };
    }
    
    // Constructor for not found responses (404)
    fn not_found() -> HttpResponse {
        let body = "

404 Not Found

The requested resource was not found on this server.

"; let headers = HashMap::new(); headers.insert("Content-Type", "text/html"); headers.insert("Content-Length", body.length().to_string()); headers.insert("Server", "ShitRustServer/0.1"); headers.insert("Date", time.now().to_http_date()); return HttpResponse { status: 404, headers: headers, body: body }; } // Method to convert the response to a string fn to_string() -> string { let result = "HTTP/1.1 " + this.status.to_string() + " " + http.status_text(this.status) + "\r\n"; // Add headers for (name, value) in this.headers { result += name + ": " + value + "\r\n"; } // Add empty line to separate headers from body result += "\r\n"; // Add body result += this.body; return result; } } // Define a router to handle different routes struct Router { routes: HashMap HttpResponse>, fn new() -> Router { return Router { routes: HashMap::new() }; } // Register a route handler fn add(method: string, path: string, handler: fn(http.Request) -> HttpResponse) -> void { let key = method + " " + path; this.routes.insert(key, handler); } // Find and execute the appropriate handler for a request fn handle(request: http.Request) -> HttpResponse { let key = request.method + " " + request.path; if this.routes.contains_key(key) { let handler = this.routes.get(key); return handler(request); } // Check for static file if request.method == "GET" { let file_path = "public" + request.path; if fs.exists(file_path) && !fs.is_directory(file_path) { return serve_static_file(file_path); } } // No route found return HttpResponse.not_found(); } } // Function to serve a static file fn serve_static_file(file_path: string) -> HttpResponse { try { let content = fs.read_file(file_path); let content_type = get_content_type(file_path); return HttpResponse.ok(content, content_type); } catch e { println("Error serving file: " + e.to_string()); return HttpResponse.not_found(); } } // Helper function to determine content type based on file extension fn get_content_type(file_path: string) -> string { let ext = path.extension(file_path).to_lowercase(); match ext { "html" | "htm" => return "text/html", "css" => return "text/css", "js" => return "application/javascript", "json" => return "application/json", "png" => return "image/png", "jpg" | "jpeg" => return "image/jpeg", "gif" => return "image/gif", "svg" => return "image/svg+xml", "pdf" => return "application/pdf", _ => return "text/plain" } } // Handler functions fn home_handler(request: http.Request) -> HttpResponse { let body = """ ShitRust Web Server

Welcome to ShitRust Web Server!

This is a simple web server built with ShitRust.

Available routes:

"""; return HttpResponse.ok(body); } fn about_handler(request: http.Request) -> HttpResponse { let uptime = time.now() - server_start_time; let body = """ About - ShitRust Web Server

About This Server

Server: ShitRustServer/0.1

Start Time: ${server_start_time.to_string()}

Uptime: ${format_duration(uptime)}

Requests Handled: ${request_count}

Back to Home

"""; return HttpResponse.ok(body); } fn api_time_handler(request: http.Request) -> HttpResponse { let current_time = time.now(); let json = """ { "timestamp": ${current_time.unix_timestamp()}, "iso": "${current_time.to_iso_string()}", "formatted": "${current_time.format("%Y-%m-%d %H:%M:%S")}" } """; let response = HttpResponse.ok(json, "application/json"); return response; } // Helper function to format duration fn format_duration(duration: int) -> string { let seconds = duration % 60; let minutes = (duration / 60) % 60; let hours = (duration / 3600) % 24; let days = duration / 86400; if days > 0 { return "${days}d ${hours}h ${minutes}m ${seconds}s"; } else if hours > 0 { return "${hours}h ${minutes}m ${seconds}s"; } else if minutes > 0 { return "${minutes}m ${seconds}s"; } else { return "${seconds}s"; } } // Track server statistics let server_start_time = time.now(); let request_count = 0; // Main function to start the server async fn main() -> void { let port = 8080; println("Starting web server on port " + port.to_string() + "..."); // Create and configure the router let router = Router.new(); // Register routes router.add("GET", "/", home_handler); router.add("GET", "/about", about_handler); router.add("GET", "/api/time", api_time_handler); // Start the server await http.create_server(port, |request| { // Increment request counter request_count += 1; // Log the request println("[" + time.now().format("%Y-%m-%d %H:%M:%S") + "] " + request.method + " " + request.path + " - " + request.headers.get("User-Agent", "Unknown")); // Route the request let response = router.handle(request); // Return the response return response.to_string(); }); }

Explanation

  • Creates a simple HTTP server that listens on port 8080
  • Implements a router to handle different URL paths
  • Defines response object for consistent HTTP responses
  • Uses async/await for handling concurrent requests
  • Serves dynamic routes and static files
  • Implements simple request logging
  • Handles different content types for responses
  • Tracks basic server statistics

Data Processing

Process and analyze CSV data using ShitRust's functional programming features.

data_processing.sr
// Data Processing Example in ShitRust

use fs;
use csv;
use time;

// Define a struct to represent sales data
struct SalesRecord {
    date: string,
    product: string,
    category: string,
    region: string,
    quantity: int,
    unit_price: float,
    
    // Calculate the total value of this sale
    fn total_value() -> float {
        return this.quantity as float * this.unit_price;
    }
}

// Parse a CSV file into SalesRecord objects
fn parse_sales_csv(file_path: string) -> Result<[SalesRecord], string> {
    try {
        // Read the file
        let content = fs.read_file(file_path);
        
        // Parse CSV
        let records = csv.parse(content);
        
        // Convert to SalesRecord objects
        let sales_data = [];
        
        // Skip header row
        for i in 1..records.length() {
            let row = records[i];
            
            // Validate row
            if row.length() < 6 {
                continue;  // Skip invalid rows
            }
            
            let record = SalesRecord {
                date: row[0],
                product: row[1],
                category: row[2],
                region: row[3],
                quantity: row[4].parse::(),
                unit_price: row[5].parse::()
            };
            
            sales_data.push(record);
        }
        
        return Result::Ok(sales_data);
    } catch e {
        return Result::Err("Failed to parse CSV: " + e.to_string());
    }
}

// Calculate total sales amount
fn calculate_total_sales(sales: [SalesRecord]) -> float {
    let total = 0.0;
    
    for sale in sales {
        total += sale.total_value();
    }
    
    return total;
}

// Group data by a specific field and calculate sum of values
fn group_by_sum(sales: [SalesRecord], key_fn: fn(SalesRecord) -> T, value_fn: fn(SalesRecord) -> float) -> HashMap {
    let result = HashMap::new();
    
    for sale in sales {
        let key = key_fn(sale);
        let value = value_fn(sale);
        
        if result.contains_key(key) {
            let current = result.get(key);
            result.insert(key, current + value);
        } else {
            result.insert(key, value);
        }
    }
    
    return result;
}

// Find the top N items by value
fn top_n(data: HashMap, n: int) -> [(T, float)] {
    // Convert to array of pairs
    let pairs = [(key, value) for (key, value) in data];
    
    // Sort by value in descending order
    pairs.sort_by(|a, b| b[1] <=> a[1]);
    
    // Take top N
    return pairs.slice(0, n.min(pairs.length()));
}

// Generate a simple horizontal bar chart
fn generate_bar_chart(data: [(T, float)], title: string) -> string {
    let max_value = data.reduce(|max, item| max.max(item[1]), 0.0);
    let max_label_length = data.reduce(|max, item| max.max(item[0].to_string().length()), 0);
    
    let chart = title + "\n" + "=".repeat(title.length()) + "\n\n";
    
    for (label, value) in data {
        let bar_length = ((value / max_value) * 50.0) as int;
        let formatted_label = label.to_string().pad_right(max_label_length);
        let formatted_value = value.to_string();
        
        chart += formatted_label + " | " + "█".repeat(bar_length) + " " + formatted_value + "\n";
    }
    
    return chart;
}

// Print sales report
fn print_sales_report(sales: [SalesRecord]) -> void {
    println("\n===== Sales Analysis Report =====");
    
    // Total sales
    let total_sales = calculate_total_sales(sales);
    println("Total Sales: $" + total_sales.format(",.2f"));
    
    // Total number of transactions
    println("Total Transactions: " + sales.length().to_string());
    
    // Average sale value
    let avg_sale = total_sales / sales.length() as float;
    println("Average Sale Value: $" + avg_sale.format(",.2f"));
    
    // Sales by Region
    println("\nSales by Region:");
    let region_sales = group_by_sum(sales, 
        |sale| sale.region, 
        |sale| sale.total_value()
    );
    
    let top_regions = top_n(region_sales, 5);
    for (region, value) in top_regions {
        println("  " + region.pad_right(15) + ": $" + value.format(",.2f"));
    }
    
    // Sales by Category
    println("\nSales by Category:");
    let category_sales = group_by_sum(sales, 
        |sale| sale.category, 
        |sale| sale.total_value()
    );
    
    for (category, value) in category_sales {
        println("  " + category.pad_right(15) + ": $" + value.format(",.2f"));
    }
    
    // Top Products
    println("\nTop 5 Products by Sales:");
    let product_sales = group_by_sum(sales, 
        |sale| sale.product, 
        |sale| sale.total_value()
    );
    
    let top_products = top_n(product_sales, 5);
    for (i, (product, value)) in top_products.enumerate() {
        println("  " + (i + 1).to_string() + ". " + product.pad_right(20) + ": $" + value.format(",.2f"));
    }
    
    // Generate a bar chart for category sales
    println("\n" + generate_bar_chart(
        [(key, value) for (key, value) in category_sales],
        "Sales by Category"
    ));
}

// Find monthly trends
fn analyze_monthly_trends(sales: [SalesRecord]) -> void {
    println("\n===== Monthly Sales Trends =====");
    
    // Extract month from date string (assuming format: YYYY-MM-DD)
    let monthly_sales = group_by_sum(sales,
        |sale| {
            let parts = sale.date.split("-");
            return parts[0] + "-" + parts[1]; // YYYY-MM
        },
        |sale| sale.total_value()
    );
    
    // Convert to array and sort by month
    let months = [(month, sales) for (month, sales) in monthly_sales];
    months.sort_by(|a, b| a[0] <=> b[0]);
    
    // Print monthly trends
    for (month, value) in months {
        println("  " + month + ": $" + value.format(",.2f"));
    }
    
    // Generate a bar chart for monthly trends
    println("\n" + generate_bar_chart(months, "Monthly Sales Trends"));
}

// Main function
fn main() -> void {
    println("ShitRust Data Processing Example");
    println("--------------------------------");
    
    // Start timing
    let start_time = time.now();
    
    // Process sales data
    let result = parse_sales_csv("data/sales.csv");
    
    match result {
        Result::Ok(sales) => {
            println("Successfully loaded " + sales.length().to_string() + " sales records.");
            
            // Analyze the data
            print_sales_report(sales);
            analyze_monthly_trends(sales);
            
            // Export data (example)
            export_summary(sales);
        },
        Result::Err(error) => {
            println("Error: " + error);
            return;
        }
    }
    
    // Calculate and display processing time
    let end_time = time.now();
    let processing_time = end_time - start_time;
    println("\nProcessing completed in " + processing_time.to_string() + "ms");
}

// Export summary data to a new CSV file
fn export_summary(sales: [SalesRecord]) -> void {
    // Group by category
    let category_summary = group_by_sum(sales,
        |sale| sale.category,
        |sale| sale.total_value()
    );
    
    // Create CSV content
    let csv_content = "Category,Total Sales\n";
    for (category, value) in category_summary {
        csv_content += category + "," + value.to_string() + "\n";
    }
    
    // Write to file
    try {
        fs.write_file("data/summary.csv", csv_content);
        println("\nSummary exported to data/summary.csv");
    } catch e {
        println("\nFailed to export summary: " + e.to_string());
    }
}

// Example of data processing using the pipeline operator
fn demonstrate_pipeline() -> void {
    println("\n===== Pipeline-based Data Processing =====");
    
    // Sample data
    let sales = parse_sales_csv("data/sales.csv").unwrap();
    
    // Traditional approach
    let filtered = [sale for sale in sales if sale.region == "North"];
    let mapped = [sale.total_value() for sale in filtered];
    let total = mapped.reduce(|sum, value| sum + value, 0.0);
    println("North region total (traditional): $" + total.format(",.2f"));
    
    // Pipeline approach
    let pipeline_total = sales
        |> [sale for sale in _ if sale.region == "North"]
        |> [sale.total_value() for sale in _]
        |> _.reduce(|sum, value| sum + value, 0.0);
    
    println("North region total (pipeline): $" + pipeline_total.format(",.2f"));
    
    // More complex pipeline example
    let top_north_products = sales
        |> [sale for sale in _ if sale.region == "North"] // Filter for North region
        |> _.group_by(|sale| sale.product) // Group by product
        |> [(product, items.map(|sale| sale.total_value()).sum()) for (product, items) in _] // Sum values
        |> _.sort_by(|a, b| b[1] <=> a[1]) // Sort by value (descending)
        |> _.slice(0, 3); // Top 3
    
    println("\nTop 3 products in North region:");
    for (product, value) in top_north_products {
        println("  " + product + ": $" + value.format(",.2f"));
    }
}

Explanation

  • Demonstrates processing of structured data (CSV files)
  • Uses structs to model sales data records
  • Implements data analysis functions: grouping, sorting, filtering
  • Provides simple data visualization with ASCII bar charts
  • Shows how to use functional programming techniques for data analysis
  • Compares traditional approach with pipeline operator for data processing
  • Exports processed data to new files
  • Error handling ensures robust data processing

Algorithms

Implementing common algorithms in ShitRust to showcase language features.

algorithms.sr
// Common Algorithms in ShitRust

use time;

// ===== Sorting Algorithms =====

// Bubble Sort
fn bubble_sort>(arr: [T]) -> [T] {
    let result = arr.clone();
    let n = result.length();
    
    for i in 0..n {
        for j in 0..(n - i - 1) {
            if result[j] > result[j + 1] {
                // Swap elements
                let temp = result[j];
                result[j] = result[j + 1];
                result[j + 1] = temp;
            }
        }
    }
    
    return result;
}

// Quick Sort
fn quick_sort>(arr: [T]) -> [T] {
    if arr.length() <= 1 {
        return arr;
    }
    
    let pivot = arr[arr.length() / 2];
    let less = [x for x in arr if x < pivot];
    let equal = [x for x in arr if x == pivot];
    let greater = [x for x in arr if x > pivot];
    
    return quick_sort(less) + equal + quick_sort(greater);
}

// Merge Sort
fn merge_sort>(arr: [T]) -> [T] {
    if arr.length() <= 1 {
        return arr;
    }
    
    let mid = arr.length() / 2;
    let left = merge_sort(arr.slice(0, mid));
    let right = merge_sort(arr.slice(mid));
    
    return merge(left, right);
}

// Helper function for merge sort
fn merge>(left: [T], right: [T]) -> [T] {
    let mut result = [];
    let mut i = 0;
    let mut j = 0;
    
    while i < left.length() && j < right.length() {
        if left[i] < right[j] {
            result.push(left[i]);
            i += 1;
        } else {
            result.push(right[j]);
            j += 1;
        }
    }
    
    while i < left.length() {
        result.push(left[i]);
        i += 1;
    }
    
    while j < right.length() {
        result.push(right[j]);
        j += 1;
    }
    
    return result;
}

// ===== Searching Algorithms =====

// Binary Search
fn binary_search>(arr: [T], target: T) -> int {
    let mut left = 0;
    let mut right = arr.length() - 1;
    
    while left <= right {
        let mid = (left + right) / 2;
        if arr[mid] == target {
            return mid;
        } else if arr[mid] < target {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    
    return -1;
}

// ===== Graph Algorithms =====

// Depth-First Search (DFS)
fn dfs(graph: HashMap, start: T) -> void {
    let mut visited = HashSet::new();
    let mut stack = Vec::new();
    
    stack.push(start);
    
    while !stack.is_empty() {
        let current = stack.pop().unwrap();
        if !visited.contains(¤t) {
            visited.insert(current);
            println("Visited: " + current);
            
            for neighbor in graph.get(current).unwrap() {
                stack.push(*neighbor);
            }
        }
    }
}

// Breadth-First Search (BFS)
fn bfs(graph: HashMap, start: T) -> void {
    let mut visited = HashSet::new();
    let mut queue = VecDeque::new();
    
    queue.push_back(start);
    
    while !queue.is_empty() {
        let current = queue.pop_front().unwrap();
        if !visited.contains(¤t) {
            visited.insert(current);
            println("Visited: " + current);
            
            for neighbor in graph.get(current).unwrap() {
                queue.push_back(*neighbor);
            }
        }
    }
}

// ===== Other Algorithms =====

// Fibonacci Sequence
fn fibonacci(n: int) -> int {
    if n <= 1 {
        return n;
    }
    
    let mut a = 0;
    let mut b = 1;
    
    for _ in 2..n {
        let temp = a + b;
        a = b;
        b = temp;
    }
    
    return b;
}

// Factorial
fn factorial(n: int) -> int {
    if n <= 1 {
        return 1;
    }
    
    let mut result = 1;
    for i in 2..=n {
        result *= i;
    }
    
    return result;
}

// Greatest Common Divisor (GCD)
fn gcd(a: int, b: int) -> int {
    if b == 0 {
        return a;
    }
    
    return gcd(b, a % b);
}

// Least Common Multiple (LCM)
fn lcm(a: int, b: int) -> int {
    return (a * b) / gcd(a, b);
}

// Main function to demonstrate algorithms
fn main() -> void {
    println("===== Sorting Algorithms =====");
    let sorted_bubble = bubble_sort([5, 3, 8, 4, 2]);
    println("Bubble Sort: " + sorted_bubble.to_string());
    
    let sorted_quick = quick_sort([5, 3, 8, 4, 2]);
    println("Quick Sort: " + sorted_quick.to_string());
    
    let sorted_merge = merge_sort([5, 3, 8, 4, 2]);
    println("Merge Sort: " + sorted_merge.to_string());
    
    println("\n===== Searching Algorithms =====");
    let index = binary_search([1, 2, 3, 4, 5], 3);
    println("Binary Search (3): " + index.to_string());
    
    println("\n===== Graph Algorithms =====");
    let graph = HashMap::from([
        ("A", ["B", "C"]),
        ("B", ["A", "D"]),
        ("C", ["A", "D"]),
        ("D", ["B", "C"])
    ]);
    
    println("DFS:");
    dfs(graph, "A");
    
    println("\nBFS:");
    bfs(graph, "A");
    
    println("\n===== Other Algorithms =====");
    println("Fibonacci (5): " + fibonacci(5).to_string());
    println("Factorial (5): " + factorial(5).to_string());
    println("GCD (18, 24): " + gcd(18, 24).to_string());
    println("LCM (18, 24): " + lcm(18, 24).to_string());
}

Explanation

  • Implements common algorithms in ShitRust
  • Includes sorting algorithms (Bubble Sort, Quick Sort, Merge Sort)
  • Searching algorithms (Binary Search)
  • Graph algorithms (Depth-First Search, Breadth-First Search)
  • Other algorithms (Fibonacci Sequence, Factorial, Greatest Common Divisor, Least Common Multiple)
  • Uses generics and helper functions to keep code clean and reusable

Simple Game

A text-based adventure game demonstrating object-oriented and event-driven programming.

text_adventure.sr
// Simple Text Adventure Game in ShitRust

use io;

// Base Entity class
struct Entity {
    name: string,
    description: string,
    
    fn new(name: string, description: string) -> Entity {
        return Entity {
            name: name,
            description: description
        };
    }
    
    fn describe() -> string {
        return this.description;
    }
}

// Item that can be picked up
struct Item : Entity {
    weight: int,
    value: int,
    can_be_taken: bool,
    
    fn new(name: string, description: string, weight: int, value: int, can_be_taken: bool = true) -> Item {
        return Item {
            name: name,
            description: description,
            weight: weight,
            value: value,
            can_be_taken: can_be_taken
        };
    }
    
    fn describe() -> string {
        let desc = super.describe();
        
        if this.value > 0 {
            desc += " It looks valuable.";
        }
        
        return desc;
    }
}

// Character in the game
struct Character : Entity {
    health: int,
    max_health: int,
    strength: int,
    
    fn new(name: string, description: string, health: int, strength: int) -> Character {
        return Character {
            name: name,
            description: description,
            health: health,
            max_health: health,
            strength: strength
        };
    }
    
    fn is_alive() -> bool {
        return this.health > 0;
    }
    
    fn take_damage(amount: int) -> void {
        this.health = max(0, this.health - amount);
    }
    
    fn describe() -> string {
        return super.describe() + "\nHealth: " + this.health.to_string() + "/" + this.max_health.to_string();
    }
}

// Room in the game
struct Room {
    name: string,
    description: string,
    exits: HashMap,  // Direction -> Room ID
    items: [Item],
    characters: [Character],
    
    fn new(name: string, description: string) -> Room {
        return Room {
            name: name,
            description: description,
            exits: HashMap::new(),
            items: [],
            characters: []
        };
    }
    
    fn add_exit(direction: string, room_id: int) -> void {
        this.exits.insert(direction, room_id);
    }
    
    fn add_item(item: Item) -> void {
        this.items.push(item);
    }
    
    fn add_character(character: Character) -> void {
        this.characters.push(character);
    }
    
    fn describe() -> string {
        let desc = "== " + this.name + " ==\n" + this.description + "\n";
        
        // List exits
        if this.exits.length() > 0 {
            desc += "\nExits: ";
            let exit_list = [dir for dir in this.exits.keys()];
            desc += exit_list.join(", ");
        }
        
        // List items
        if this.items.length() > 0 {
            desc += "\n\nYou see:";
            for item in this.items {
                desc += "\n- " + item.name;
            }
        }
        
        // List characters
        if this.characters.length() > 0 {
            desc += "\n\nPresent:";
            for character in this.characters {
                desc += "\n- " + character.name;
            }
        }
        
        return desc;
    }
}

// Player class
struct Player : Character {
    inventory: [Item],
    current_room_id: int,
    
    fn new(name: string) -> Player {
        return Player {
            name: name,
            description: "A brave adventurer",
            health: 30,
            max_health: 30,
            strength: 5,
            inventory: [],
            current_room_id: 0
        };
    }
    
    fn take_item(item: Item) -> void {
        println("You pick up the " + item.name + ".");
        this.inventory.push(item);
    }
    
    fn list_inventory() -> void {
        if this.inventory.length() == 0 {
            println("Your inventory is empty.");
            return;
        }
        
        println("Inventory:");
        for item in this.inventory {
            println("- " + item.name);
        }
    }
    
    fn move_to(direction: string, world: World) -> bool {
        let current_room = world.get_room(this.current_room_id);
        
        if current_room.exits.contains_key(direction) {
            this.current_room_id = current_room.exits.get(direction);
            return true;
        }
        
        return false;
    }
}

// World contains all game data
struct World {
    rooms: [Room],
    player: Player,
    game_over: bool,
    
    fn new(player_name: string) -> World {
        return World {
            rooms: [],
            player: Player.new(player_name),
            game_over: false
        };
    }
    
    fn add_room(room: Room) -> int {
        let id = this.rooms.length();
        this.rooms.push(room);
        return id;
    }
    
    fn get_room(id: int) -> Room {
        return this.rooms[id];
    }
    
    fn get_current_room() -> Room {
        return this.get_room(this.player.current_room_id);
    }
    
    fn describe_current_room() -> void {
        let room = this.get_current_room();
        println(room.describe());
    }
}

// Command interface
trait Command {
    fn execute(world: World, args: [string]) -> void;
    fn help() -> string;
}

// Look command
struct LookCommand : Command {
    fn execute(world: World, args: [string]) -> void {
        world.describe_current_room();
    }
    
    fn help() -> string {
        return "look - Look around at your surroundings";
    }
}

// Go command
struct GoCommand : Command {
    fn execute(world: World, args: [string]) -> void {
        if args.length() == 0 {
            println("Go where?");
            return;
        }
        
        let direction = args[0].to_lowercase();
        if world.player.move_to(direction, world) {
            println("You go " + direction + ".");
            world.describe_current_room();
        } else {
            println("You can't go that way.");
        }
    }
    
    fn help() -> string {
        return "go  - Move in the specified direction";
    }
}

// Inventory command
struct InventoryCommand : Command {
    fn execute(world: World, args: [string]) -> void {
        world.player.list_inventory();
    }
    
    fn help() -> string {
        return "inventory - List items you're carrying";
    }
}

// Help command
struct HelpCommand : Command {
    fn execute(world: World, args: [string]) -> void {
        println("Available commands:");
        
        let commands = get_all_commands();
        for command in commands {
            println("  " + command.help());
        }
    }
    
    fn help() -> string {
        return "help - Display this help message";
    }
}

// Exit command
struct ExitCommand : Command {
    fn execute(world: World, args: [string]) -> void {
        println("Goodbye!");
        world.game_over = true;
    }
    
    fn help() -> string {
        return "exit - Exit the game";
    }
}

// Get all available commands
fn get_all_commands() -> [Command] {
    return [
        LookCommand {},
        GoCommand {},
        InventoryCommand {},
        HelpCommand {},
        ExitCommand {}
    ];
}

// Parse and execute a command
fn parse_command(input: string, world: World) -> void {
    let parts = input.trim().split(" ");
    if parts.length() == 0 {
        return;
    }
    
    let command_name = parts[0].to_lowercase();
    let args = parts.slice(1);
    
    let commands = get_all_commands();
    
    for command in commands {
        let command_type = typeof(command);
        let command_class_name = command_type.to_string().to_lowercase();
        
        if command_class_name.starts_with(command_name) && command_class_name.ends_with("command") {
            command.execute(world, args);
            return;
        }
    }
    
    println("Unknown command. Type 'help' for a list of commands.");
}

// Create the game world
fn create_game_world(player_name: string) -> World {
    let world = World.new(player_name);
    
    // Create rooms
    let town_square = Room.new(
        "Town Square",
        "You are in the center of a small town. A fountain bubbles in the center of the square."
    );
    
    let market = Room.new(
        "Market",
        "The market is bustling with activity. Stalls line the sides of the street."
    );
    
    let tavern = Room.new(
        "Tavern",
        "The tavern is warm and inviting. A fire crackles in the hearth."
    );
    
    // Add rooms to world
    let town_square_id = world.add_room(town_square);
    let market_id = world.add_room(market);
    let tavern_id = world.add_room(tavern);
    
    // Connect rooms
    world.rooms[town_square_id].add_exit("north", market_id);
    world.rooms[town_square_id].add_exit("east", tavern_id);
    
    world.rooms[market_id].add_exit("south", town_square_id);
    
    world.rooms[tavern_id].add_exit("west", town_square_id);
    
    // Add items
    world.rooms[town_square_id].add_item(Item.new(
        "Fountain",
        "A beautiful stone fountain with clear water bubbling from the top.",
        100, 0, false
    ));
    
    world.rooms[market_id].add_item(Item.new(
        "Sword",
        "A finely crafted short sword with a leather grip.",
        5, 25, true
    ));
    
    // Add characters
    world.rooms[town_square_id].add_character(Character.new(
        "Old Man",
        "An elderly man with a long white beard, leaning on a gnarled staff.",
        20, 2
    ));
    
    // Set player starting location
    world.player.current_room_id = town_square_id;
    
    return world;
}

// Main game loop
fn main() -> void {
    // Game intro
    println("===================================");
    println("       Text Adventure Game        ");
    println("===================================");
    println("\nWelcome to the world of Mysteria!");
    println("\nType 'help' at any time to see available commands.");
    
    // Get player name
    println("\nWhat is your name, adventurer?");
    let player_name = io.read_line();
    
    // Create game world
    let world = create_game_world(player_name);
    
    // Welcome message
    println("\nWelcome, " + player_name + "! Your adventure begins in the town square.");
    println("\nType 'look' to see what's around you.");
    
    // Game loop
    while !world.game_over {
        println("\n> ");
        let input = io.read_line();
        
        if input.trim() == "" {
            continue;
        }
        
        parse_command(input, world);
    }
    
    println("\nThank you for playing!");
}

Explanation

  • Implements a simple text-based adventure game
  • Demonstrates object-oriented programming with inheritance
  • Uses traits to create a command system
  • Shows how to create a game world with rooms, items, and characters
  • Includes an inventory system
  • Uses a command parser to handle user input
  • Features dynamic game state that responds to player actions
  • Showcases polymorphism through the command system