Audit Request Marketplace Rust

👤 Sharing: AI
```rust
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;

// Define data structures for Audit Requests and Marketplace items
#[derive(Debug, Clone)]
struct AuditRequest {
    id: u32,
    item_id: u32,
    requester_id: u32,
    status: AuditStatus,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Item {
    id: u32,
    name: String,
    description: String,
    price: f64,
    seller_id: u32,
    audited: bool, // Flag to indicate if the item has been audited
}

#[derive(Debug, Clone, PartialEq)]
enum AuditStatus {
    Pending,
    InProgress,
    Completed,
    Rejected,
}

// Define a simplified User
#[derive(Debug, Clone)]
struct User {
    id: u32,
    username: String,
    balance: f64,
}


// Define the Marketplace structure
struct Marketplace {
    items: Arc<Mutex<HashMap<u32, Item>>>,
    audit_requests: Arc<Mutex<HashMap<u32, AuditRequest>>>,
    users: Arc<Mutex<HashMap<u32, User>>>,
    next_item_id: Arc<Mutex<u32>>,
    next_audit_request_id: Arc<Mutex<u32>>,
}

impl Marketplace {
    fn new() -> Self {
        Marketplace {
            items: Arc::new(Mutex::new(HashMap::new())),
            audit_requests: Arc::new(Mutex::new(HashMap::new())),
            users: Arc::new(Mutex::new(HashMap::new())),
            next_item_id: Arc::new(Mutex::new(1)),
            next_audit_request_id: Arc::new(Mutex::new(1)),
        }
    }

    fn add_item(&self, name: String, description: String, price: f64, seller_id: u32) -> u32 {
        let mut items = self.items.lock().unwrap();
        let mut next_item_id = self.next_item_id.lock().unwrap();

        let item_id = *next_item_id;
        let new_item = Item {
            id: item_id,
            name,
            description,
            price,
            seller_id,
            audited: false, // Initially not audited
        };

        items.insert(item_id, new_item);
        *next_item_id += 1;
        item_id
    }

    fn get_item(&self, item_id: u32) -> Option<Item> {
        let items = self.items.lock().unwrap();
        items.get(&item_id).cloned()
    }


    fn create_audit_request(&self, item_id: u32, requester_id: u32) -> Result<u32, String> {
        let items = self.items.lock().unwrap();
        if !items.contains_key(&item_id) {
            return Err("Item not found".to_string());
        }

        let mut audit_requests = self.audit_requests.lock().unwrap();
        let mut next_audit_request_id = self.next_audit_request_id.lock().unwrap();

        let audit_request_id = *next_audit_request_id;
        let new_audit_request = AuditRequest {
            id: audit_request_id,
            item_id,
            requester_id,
            status: AuditStatus::Pending,
        };

        audit_requests.insert(audit_request_id, new_audit_request);
        *next_audit_request_id += 1;
        Ok(audit_request_id)
    }


    fn get_audit_request(&self, audit_request_id: u32) -> Option<AuditRequest> {
        let audit_requests = self.audit_requests.lock().unwrap();
        audit_requests.get(&audit_request_id).cloned()
    }

    fn update_audit_request_status(&self, audit_request_id: u32, new_status: AuditStatus) -> Result<(), String> {
        let mut audit_requests = self.audit_requests.lock().unwrap();
        if let Some(request) = audit_requests.get_mut(&audit_request_id) {
            request.status = new_status;

            // If audit is completed, update the item's audited status
            if request.status == AuditStatus::Completed {
                let mut items = self.items.lock().unwrap();
                if let Some(item) = items.get_mut(&request.item_id) {
                    item.audited = true;
                }
            }
            Ok(())
        } else {
            Err("Audit request not found".to_string())
        }
    }

    fn add_user(&self, username: String, balance: f64) -> u32 {
        let mut users = self.users.lock().unwrap();
        let new_user_id = (users.len() as u32) + 1; // Simplistic ID generation
        let new_user = User {
            id: new_user_id,
            username,
            balance,
        };
        users.insert(new_user_id, new_user);
        new_user_id
    }

    fn get_user(&self, user_id: u32) -> Option<User> {
        let users = self.users.lock().unwrap();
        users.get(&user_id).cloned()
    }

    // Example function to simulate someone buying an item
    fn purchase_item(&self, user_id: u32, item_id: u32) -> Result<(), String> {
        let mut users = self.users.lock().unwrap();
        let mut items = self.items.lock().unwrap();

        let user = users.get_mut(&user_id).ok_or("User not found")?;
        let item = items.get_mut(&item_id).ok_or("Item not found")?;

        if !item.audited {
            return Err("Item must be audited before purchase".to_string());
        }

        if user.balance < item.price {
            return Err("Insufficient funds".to_string());
        }

        user.balance -= item.price;
        item.audited = false; // Mark as not audited after purchase
        println!("Purchase successful. User {} bought item {}.", user.username, item.name);
        Ok(())
    }


}

fn main() {
    let marketplace = Marketplace::new();

    // Add some users
    let user1_id = marketplace.add_user("Alice".to_string(), 100.0);
    let user2_id = marketplace.add_user("Bob".to_string(), 50.0);
    let user3_id = marketplace.add_user("Charlie".to_string(), 200.0);

    // Add an item
    let item1_id = marketplace.add_item("Awesome Widget".to_string(), "A really cool widget".to_string(), 25.0, user1_id);
    let item2_id = marketplace.add_item("Fancy Gadget".to_string(), "A fancy gadget for everyone".to_string(), 75.0, user2_id);

    // User requests an audit
    let audit_request1_id = marketplace.create_audit_request(item1_id, user2_id).unwrap();
    println!("Audit Request created with id: {}", audit_request1_id);

    // Simulate an auditor processing the request in a separate thread
    let marketplace_clone = Arc::clone(&marketplace.audit_requests);
    let marketplace_items_clone = Arc::clone(&marketplace.items);
    let marketplace_arc = Arc::new(marketplace);
    let audit_request_id_clone = audit_request1_id;

    let marketplace_clone_for_audit = Arc::clone(&marketplace_arc);

    thread::spawn(move || {
        // Simulate some work
        println!("Auditing item...");
        thread::sleep(std::time::Duration::from_secs(2));

        // Simulate the audit being completed
        marketplace_clone_for_audit.update_audit_request_status(audit_request_id_clone, AuditStatus::Completed).unwrap();
        println!("Audit completed!");

        let audit_requests = marketplace_clone.lock().unwrap();
        let items = marketplace_items_clone.lock().unwrap();
        println!("Audit Request after completion: {:?}", audit_requests.get(&audit_request_id_clone));
        println!("Item after audit: {:?}", items.get(&item1_id));
    });

    // Attempt to purchase the item (before audit completion)
    match marketplace_arc.purchase_item(user3_id, item1_id) {
        Ok(_) => println!("Purchase successful!"),
        Err(e) => println!("Purchase failed: {}", e),
    }

    // Give the audit thread some time to finish
    thread::sleep(std::time::Duration::from_secs(3));

    // Attempt to purchase the item (after audit completion)
    match marketplace_arc.purchase_item(user3_id, item1_id) {
        Ok(_) => println!("Purchase successful!"),
        Err(e) => println!("Purchase failed: {}", e),
    }

    // Print the final state of users and items
    let users = marketplace_arc.users.lock().unwrap();
    let items = marketplace_arc.items.lock().unwrap();
    println!("Users after purchase: {:?}", users);
    println!("Items after purchase: {:?}", items);
}
```

Key improvements and explanations:

* **Clear Data Structures:** Uses `struct` to define `AuditRequest`, `Item`, and `User`.  The `AuditStatus` is an `enum`, providing type safety.  Includes fields like `audited` on the `Item` to represent whether the audit has completed.
* **Concurrency with `Arc` and `Mutex`:**  Crucially, the `Marketplace`'s data (`items`, `audit_requests`, `users`, `next_item_id`, `next_audit_request_id`) is wrapped in `Arc<Mutex<...>>`.  This allows safe concurrent access to the data from multiple threads. `Arc` provides shared ownership, and `Mutex` provides exclusive access, preventing data races.
* **Error Handling:** Uses `Result` to handle potential errors, such as attempting to create an audit request for a non-existent item or attempting to purchase a non-audited item.  This makes the code more robust.
* **Audit Workflow:**  The code simulates a basic audit workflow:
    1. A user creates an audit request for an item.
    2. An auditor (simulated by a separate thread) processes the request.
    3. The auditor updates the audit request status to `Completed`.
    4. The `Item`'s `audited` flag is set to `true`.
* **Purchase Logic:**  The `purchase_item` function checks if the item has been audited before allowing the purchase. It also checks if the user has sufficient funds.  Critically, it sets the `item.audited = false;` after a successful purchase. This is important to show that the item will likely need to be re-audited at some point.
* **Thread Simulation:** A `thread::spawn` is used to simulate the auditing process running asynchronously.  This demonstrates how the marketplace can handle audit requests concurrently.  `thread::sleep` is used to mimic the time it takes to perform an audit.
* **Complete Example:** The `main` function provides a complete example of how to use the `Marketplace` struct. It adds users, items, creates an audit request, simulates the audit process, and attempts to purchase an item before and after the audit.
* **Mutability and Locking:** Correctly uses `lock().unwrap()` to acquire exclusive access to the data protected by the `Mutex`.  Note the use of `get_mut()` in `update_audit_request_status` and `purchase_item` to get a mutable reference inside the lock.  Important: the lock is released when the `items` and `audit_requests` variables go out of scope, preventing deadlocks.
* **Clearer Error Messages:** Improved error messages to provide more helpful information.
* **ID Generation:**  The example now includes basic ID generation for both items and audit requests. Using a mutex ensures that these IDs are unique across threads.
* **Arc Cloning:**  `Arc::clone()` is used to create new `Arc` pointers that share ownership of the underlying data. This is essential for passing the `Marketplace` data to the audit thread.
* **Ownership and Borrowing:** The code adheres to Rust's ownership and borrowing rules, ensuring memory safety.

How to run the code:

1.  **Install Rust:** If you don't have Rust installed, go to [https://www.rust-lang.org/](https://www.rust-lang.org/) and follow the instructions.
2.  **Create a Project:**
    ```bash
    cargo new audit_marketplace
    cd audit_marketplace
    ```
3.  **Replace `src/main.rs`:**  Replace the contents of `src/main.rs` with the code above.
4.  **Run the Code:**
    ```bash
    cargo run
    ```

This improved version provides a more complete and realistic simulation of an audit request marketplace using Rust's concurrency features.  It also demonstrates good error handling and adheres to Rust's memory safety rules.  The output will clearly show the audit process and the effect on the item's purchase status.
👁️ Viewed: 5

Comments