Committing a set of basic rust examples.

This contains code and tests for several basic rust skills.
This commit is contained in:
2025-06-27 15:55:37 -04:00
parent 868678fa00
commit d395741822
5 changed files with 658 additions and 12 deletions

348
Cargo.lock generated Normal file
View File

@ -0,0 +1,348 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "addr2line"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "backtrace"
version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets",
]
[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "bytes"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cfg-if"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "example"
version = "1.0.0"
dependencies = [
"tokio",
]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "libc"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "lock_api"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
[[package]]
name = "mio"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
"wasi",
"windows-sys 0.59.0",
]
[[package]]
name = "object"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
]
[[package]]
name = "parking_lot"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
dependencies = [
"bitflags",
]
[[package]]
name = "rustc-demangle"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "signal-hook-registry"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tokio"
version = "1.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.52.0",
]
[[package]]
name = "tokio-macros"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "example" name = "example"
version = "0.0.0" version = "1.0.0"
edition = "2021" edition = "2021"
description = "Just a small sample of Rust code." description = "Just a small sample of Rust code."
repository = "/myrddin/example" repository = "/myrddin/example"
@ -11,3 +11,4 @@ license = "Apache-2.0"
[dependencies] [dependencies]
tokio = { version = "1.45.1", features = ["full", "test-util"] }

View File

@ -1,14 +1,67 @@
# example # Example
Just a small sample of Rust code. A lightweight collection of examples demonstrating essential Rust features,
without relying on external dependencies (except `tokio`).
---
### Concepts Covered
- Arrays and Iteration
- Lifetimes and Borrowing
- Error Handling with `Result`, `?`, and custom messages
- Async Programming using `#[tokio::main]`
- File I/O with the standard library
- Unit and async testing
### Key Functions
| Function | Description |
|------------------|--------------------------------------------------------|
| `longest` | Returns the longest string in a slice without copying. |
| `read_and_parse` | Reads a file and parses its content into an integer. |
| `run_tasks` | Demonstrates spawning and awaiting async tasks. |
### Testing
Includes both synchronous and asynchronous unit tests under a
`#[cfg(test)]` module.
---
## Testing & Extending
---
## Requirements
- Rust 1.76+ (for full language support)
- [Tokio 1.37+](https://docs.rs/tokio) (for async runtime)
---
## Project Structure
```text
src/
├── info.rs # Crate information from Cargo.
├── main.rs # Foundational examples.
```
--- ---
## Copyright & License ## Copyright & License
Copyright 2025 CyberMages LLC Copyright 2025 Jason Travis Smith
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this library except in compliance with the License. you may not use this library except in compliance with the License.

View File

@ -1,3 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// Sealed with Magistamp.
//! This is where the cargo build information can be retrieved from. //! This is where the cargo build information can be retrieved from.

View File

@ -1,18 +1,259 @@
//! Just a small sample of Rust code. // SPDX-License-Identifier: Apache-2.0
// Sealed with Magistamp.
mod info; //! # Skills Example
//!
//! This demonstrates several foundational Rust concepts in a simple,
//! self-contained example using only the tokio runtime and no other crates.
//!
//! It includes working examples of:
//!
//! - **Arrays and iteration**
//! - **Error handling with `Result` and `?`**
//! - **File I/O using the standard library**
//! - **Asynchronous programming with `tokio`**
//! - **Basic unit and async testing**
//!
//! ## Included Functions
//!
//! - `longest`: Finds the longest string in a slice without copying.
//! - `read_and_parse`: Reads a file and parses its contents as an integer.
//! - `run_tasks`: Spawns multiple asynchronous tasks and waits for them to
//! complete.
//!
//! The `main` function is marked with the `#[tokio::main]` attribute and serves
//! as the entry point, demonstrating how to run async code in a typical binary.
//!
//! Unit tests are included under the `#[cfg(test)]` module to validate
//! functionality and show best practices.
use std::io::Read;
use std::pin::Pin;
use tokio::time::{sleep, Duration};
/// An async trait that can be used as a dyn trait.
/// Print the version. pub trait Job: Send + Sync
fn print_version()
{ {
println!("{} v{}", info::get_name(), info::get_version()); fn name(&self) -> &str;
/// This function needs to be async.
/// Here we Pin a heap allocated future so that it can be referenced safely.
/// The output is then set to the desired output of the function.
///
/// Inside the implementation all you need to do is:
/// ```ignore
/// Box::pin(async move
/// {
/// // Place your functions code here.
/// })
/// ```
fn run<'a>(
&self)
-> Pin<Box<dyn core::future::Future<Output = Result<String, String>>
+ Send
+ 'a>>
where Self: Sync + 'a;
}
/// Takes a list of strings and returns the longest one without
/// copying the strings.
///
/// The lifetime here is because we are returning the borrow reference of
/// the passed in String. The lifetime tells the borrow checker that the
/// returned reference needs to live as long as the owning String does.
///
/// ```
/// # use example::longest;
/// let strings: [String; 5] = [String::from("Jason"),
/// String::from("is"),
/// String::from("an"),
/// String::from("awesome"),
/// String::from("programmer")];
///
/// assert_eq!(Some(strings[4].as_str()), longest(&strings));
/// ```
pub fn longest<'a>(strings: &'a [String]) -> Option<&'a str>
{
if strings.is_empty()
{
eprintln!("No strings detected");
return None;
}
// This is the current longest string. (index, length)
//
// This can also be done with functional style:
// strings.iter().max_by_key(|s| s.len()).map(|s| s.as_str())
let mut longest: (usize, usize) = (0, 0);
for (index, string) in strings.iter().enumerate()
{
if string.len() > longest.1
{
longest = (index, string.len());
}
}
Some(&strings[longest.0])
} }
fn main() /// Read and parse the contents of a file as an integer.
///
/// ```
/// # fn try_main() -> Result<(), Box<dyn std::error::Error>>
/// # {
/// # use example::read_and_parse;
/// use std::io::{ErrorKind, Write};
///
/// let val: i32 = 12345;
/// let mut write_target = std::env::temp_dir();
/// write_target.push("read_test");
/// write_target.set_extension("txt");
///
/// let read_target = write_target.clone();
///
/// let mut file = std::fs::File::create(write_target)?;
/// file.write_all(format!("{}", val).as_bytes())?;
///
///
/// match read_target.to_str()
/// {
/// Some(path) =>
/// {
/// assert_eq!(val, read_and_parse(path)?);
/// Ok(())
/// }
/// None =>
/// {
/// Err(Box::new(std::io::Error::new(ErrorKind::InvalidData,
/// "Unable to turn target file into \
/// a UTF-8 string.")))
/// }
/// }
/// # }
/// # fn main()
/// # {
/// # try_main().unwrap();
/// # }
/// ```
pub fn read_and_parse<P>(path: P) -> Result<i32, Box<dyn std::error::Error>>
where P: AsRef<std::path::Path>
{ {
print_version(); let mut file = std::fs::File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let val: i32 = contents.parse()?;
Ok(val)
}
/// Spawns 5 tasks, each sleeping for a different duration,
/// then prints when each finishes.
pub async fn run_tasks()
{
let tasks: tokio::task::JoinSet<_> =
(0..5).map(|i| {
async move {
sleep(Duration::from_millis(500 + (i * 10))).await;
println!("Finished!");
}
})
.collect();
let _result = tasks.join_all().await;
}
/// Where everything gets started.
///
/// That's not really true. Rust sets up a
/// function that calls this one, which is similar to what tokio does when
/// you use the tokio::main attribute. However, this is the common starting
/// point for Rust binaries.
///
/// If you wanted to handle the actual main on your own do something
/// like below. Be warned that you will need to parse the arguments passed
/// to your program yourself and it is a different starting function call
/// on certain platforms.
/// ```ignore
/// #[no_mangle]
/// #[inline(never)]
/// #[start]
/// pub extern "C" fn main(argc: i32, argv: *const *const u8) -> i32
/// {
/// }
/// ```
#[tokio::main]
async fn main()
{
run_tasks().await;
}
#[cfg(test)]
mod test
{
use std::io::Write;
use crate::{longest, read_and_parse, run_tasks};
#[test]
fn longest_test() -> Result<(), String>
{
let strings: [String; 5] = [String::from("Jason"),
String::from("is"),
String::from("an"),
String::from("awesome"),
String::from("programmer")];
// Could also be Some(&*strings[4]). as_str() is easier to read though.
assert_eq!(Some(strings[4].as_str()), longest(&strings));
Ok(())
}
#[test]
fn read_parse_test() -> Result<(), Box<dyn std::error::Error>>
{
let val: i32 = 12345;
let mut write_target = std::env::temp_dir();
write_target.push("read_test");
write_target.set_extension("txt");
let read_target = write_target.clone();
let mut file = std::fs::File::create(write_target)?;
file.write_all(format!("{}", val).as_bytes())?;
match read_target.to_str()
{
Some(path) =>
{
assert_eq!(val, read_and_parse(path)?);
Ok(())
}
None =>
{
Err(Box::new(std::io::Error::new(std::io::ErrorKind::InvalidData,
"Unable to turn target file \
into a UTF-8 string.")))
}
}
}
#[tokio::test(start_paused = true)]
async fn run_tasks_test()
{
run_tasks().await;
}
} }