From f2f668331d4fc7b8fe60783370a6e25726ccf9a8 Mon Sep 17 00:00:00 2001 From: soup Date: Sat, 19 Oct 2024 14:14:16 -0400 Subject: [PATCH] The first running test --- Cargo.lock | 140 +++++++++++++++++++++++++++++++++++++++ Cargo.toml | 18 +++-- flake.lock | 165 ++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 38 +++++++++++ rustfmt.toml | 5 ++ src/aliases.rs | 1 + src/fs.rs | 21 ++++++ src/lib.rs | 61 ++++++++++++++--- src/net.rs | 1 + src/plat/linux.rs | 124 ++++++++++++++++++++++++++++++++++ src/plat/mod.rs | 24 +++++++ src/wove.rs | 1 + 12 files changed, 586 insertions(+), 13 deletions(-) create mode 100644 Cargo.lock create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 rustfmt.toml create mode 100644 src/aliases.rs create mode 100644 src/fs.rs create mode 100644 src/net.rs create mode 100644 src/plat/linux.rs create mode 100644 src/plat/mod.rs create mode 100644 src/wove.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..227d9dd --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,140 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "io-uring" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c844e08c94e8558389fb9b8944cb99fc697e231c975e4274b42bc99e0625b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + +[[package]] +name = "wove" +version = "0.0.0" +dependencies = [ + "async-channel", + "futures-lite", + "io-uring", + "libc", + "pollster", +] diff --git a/Cargo.toml b/Cargo.toml index c510360..a9799dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,18 @@ [package] -name = "o_o" -version = "0.1.0" +name = "wove" +version = "0.0.0" edition = "2021" -description = "An async runtime" -license = "AGPL" +description = "wove" +license = "AGPL-3.0-or-later" [dependencies] + +[dev-dependencies] +pollster = { version = "0.3.0" } +futures-lite = { version = "2.3.0" } + +[target.'cfg(target_os = "linux")'.dependencies] +io-uring = { version = '0.7.1' } +libc = { version = "0.2.161" } +async-channel = { version = "2.3.1" } + diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..c57637d --- /dev/null +++ b/flake.lock @@ -0,0 +1,165 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1729273024, + "narHash": "sha256-Mb5SemVsootkn4Q2IiY0rr9vrXdCCpQ9HnZeD/J3uXs=", + "owner": "ipetkov", + "repo": "crane", + "rev": "fa8b7445ddadc37850ed222718ca86622be01967", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "deno-flake": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 0, + "narHash": "sha256-RsFYFS4k28JneAcEQO8ITXqIXKyBIa8FIKEPfz3NJHA=", + "type": "git", + "url": "file:///home/n/src/deno-flake" + }, + "original": { + "type": "git", + "url": "file:///home/n/src/deno-flake" + } + }, + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1728973961, + "narHash": "sha256-Jkqaw9O7WXTf5SHrK7xr9HpVU/mEPVg0Sp6s3AENC90=", + "owner": "nix-community", + "repo": "fenix", + "rev": "d6a9ff4d1e60c347a23bc96ccdb058d37a810541", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1725930920, + "narHash": "sha256-RVhD9hnlTT2nJzPHlAqrWqCkA7T6CYrP41IoVRkciZM=", + "path": "/nix/store/20yis5w6g397plssim663hqxdiiah2wr-source", + "rev": "44a71ff39c182edaf25a7ace5c9454e7cba2c658", + "type": "path" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "crane": "crane", + "deno-flake": "deno-flake", + "fenix": "fenix", + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1728921748, + "narHash": "sha256-BOCZ5osPOMh2BPHnkK4sVdTGj7sn47rBn1nxjrzWe5U=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "0319586ef2a2636f6d6b891690b7ebebf4337c85", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..a91d238 --- /dev/null +++ b/flake.nix @@ -0,0 +1,38 @@ +{ + inputs.nixpkgs.url = "nixpkgs"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.deno-flake = { + url = "git+file:///home/n/src/deno-flake"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + inputs.fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + inputs.crane = { + url = "github:ipetkov/crane"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + + outputs = i: + i.flake-utils.lib.eachDefaultSystem (system: + let + pkgs = i.nixpkgs.legacyPackages.${system}; + pkgsDeno = i.deno-flake.packages.${system}; + pkgsFenix = i.fenix.packages.${system}; + minimal = pkgsFenix.minimal; + complete = pkgsFenix.complete; + stable = pkgsFenix.stable; + in { + devShells.default = pkgs.mkShell { + packages = [ + (pkgsFenix.combine [ + (complete.withComponents [ "rust-src" "rust-analyzer" "rustfmt" "clippy" ]) + (minimal.withComponents [ "cargo" "rustc" "rust-std" ]) + ]) + pkgs.cargo-watch + ]; + }; + }); +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..cb6146a --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,5 @@ +edition = "2021" +hard_tabs = true +match_block_trailing_comma = true +max_width = 95 +empty_item_single_line = false diff --git a/src/aliases.rs b/src/aliases.rs new file mode 100644 index 0000000..c1c4ce1 --- /dev/null +++ b/src/aliases.rs @@ -0,0 +1 @@ +pub type IoResult = std::io::Result; diff --git a/src/fs.rs b/src/fs.rs new file mode 100644 index 0000000..03147ee --- /dev/null +++ b/src/fs.rs @@ -0,0 +1,21 @@ +use std::path::PathBuf; + +use crate::{aliases::IoResult, plat::Platform, Wove}; + +pub async fn read_to_string(wove: &Wove, path: PathBuf) -> IoResult { + let mut file = wove.platform.open_file(path).await?; + + let mut out = Vec::new(); + loop { + let buf = vec![0; 4096].into_boxed_slice(); + let buf = wove.platform.read(&mut file, out.len(), buf).await?; + dbg!(buf.len()); + if buf.len() == 0 { + break; + } + + out.extend_from_slice(&buf); + } + + String::from_utf8(out).map_err(std::io::Error::other) +} diff --git a/src/lib.rs b/src/lib.rs index b93cf3f..b1b9020 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,57 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +#![feature(async_closure)] + +mod aliases; +pub mod fs; +pub mod net; +mod plat; +mod wove; + +use aliases::IoResult; +#[cfg(target_os = "linux")] +pub use plat::linux::PlatformLinux as PlatImpl; +use plat::Platform; + +pub struct Wove { + platform: PlatImpl, +} + +impl Wove { + pub fn new() -> IoResult { + Ok(Self { + platform: PlatImpl::new(Default::default())?, + }) + } + + pub async fn run(&self) -> IoResult<()> { + loop { + self.platform.tick().await?; + } + } } #[cfg(test)] -mod tests { - use super::*; +mod test { + use std::path::PathBuf; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } + use crate::Wove; + + #[test] + fn sketch() { + let mut wove = Wove::new().unwrap(); + let wove = &mut wove; + let fut = async { + let run = async { + wove.run().await?; + Ok("".to_string()) + }; + + let contents = crate::fs::read_to_string(wove, PathBuf::from("src/lib.rs")); + let contents = futures_lite::future::race(run, contents).await; + + contents + }; + let out = pollster::block_on(fut).unwrap(); + + assert_eq!(out, ""); + } } diff --git a/src/net.rs b/src/net.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/net.rs @@ -0,0 +1 @@ + diff --git a/src/plat/linux.rs b/src/plat/linux.rs new file mode 100644 index 0000000..5348240 --- /dev/null +++ b/src/plat/linux.rs @@ -0,0 +1,124 @@ +use std::{ffi::CString, future::Future, path::PathBuf, pin::Pin}; + +use io_uring::IoUring; + +use crate::aliases::IoResult; + +use super::Platform; + +pub type CallbackFuture = Pin + 'static>>; +pub type Callback = Box CallbackFuture + 'static>; + +fn box_callback_as_u64(callback: impl async FnOnce(io_uring::cqueue::Entry) + 'static) -> u64 { + let bx: Callback = Box::new(move |entry| Box::pin(callback(entry))); + let bx: Box = Box::new(bx); + let leaked = Box::leak(bx); + let ptr = leaked as *mut _; + + ptr as u64 +} + +unsafe fn u64_as_callback(v: u64) -> Box { + let v = v as *mut Callback; + + unsafe { Box::from_raw(v) } +} + +pub struct PlatformLinux { + uring: io_uring::IoUring, + tx_should_tick: async_channel::Sender<()>, + rx_should_tick: async_channel::Receiver<()>, + + _pd: core::marker::PhantomData>, +} + +impl PlatformLinux { + fn set_should_tick(&self) { + self.tx_should_tick.force_send(()).unwrap(); + } + + async fn wait_tick(&self) { + self.rx_should_tick.recv().await.unwrap() + } +} +impl Platform for PlatformLinux { + type NewOptions = (); + type FileHandle = io_uring::types::Fd; + + fn new(opts: Self::NewOptions) -> IoResult { + let (tx_should_tick, rx_should_tick) = async_channel::bounded(1); + + Ok(Self { + uring: IoUring::new(256)?, + tx_should_tick, + rx_should_tick, + + _pd: Default::default(), + }) + } + + async fn tick(&self) -> IoResult<()> { + self.wait_tick().await; + self.uring.submit()?; + + let cq = unsafe { self.uring.completion_shared() }; + for entry in cq { + let cb = unsafe { u64_as_callback(entry.user_data()) }; + cb(entry).await; + } + + Ok(()) + } + + async fn open_file(&self, path: PathBuf) -> IoResult { + let (tx, rx) = async_channel::bounded(1); + + let path = CString::new(path.into_os_string().into_encoded_bytes())?; + let entry = + io_uring::opcode::OpenAt::new(io_uring::types::Fd(libc::AT_FDCWD), path.as_ptr()) + .build() + .user_data(box_callback_as_u64(async move |entry| { + let fd = entry.result(); + let fd = io_uring::types::Fd(fd); + + tx.send(fd).await.unwrap(); + std::mem::drop(path); + })); + + unsafe { + self.uring.submission_shared().push(&entry).unwrap(); + } + + self.set_should_tick(); + Ok(rx.recv().await.unwrap()) + } + + async fn read( + &self, + f: &mut Self::FileHandle, + offset: usize, + mut buf: Box<[u8]>, + ) -> IoResult> { + let (tx, rx) = async_channel::bounded(1); + + let entry = io_uring::opcode::Read::new(*f, buf.as_mut_ptr(), buf.len() as _) + .offset(offset as _) + .build() + .user_data(box_callback_as_u64(async move |entry| { + let read_amt = entry.result(); + dbg!(read_amt); + + let mut buf = buf.into_vec(); + buf.truncate(read_amt as _); + + tx.send(buf.into_boxed_slice()).await.unwrap() + })); + + unsafe { + self.uring.submission_shared().push(&entry).unwrap(); + } + + self.set_should_tick(); + Ok(rx.recv().await.unwrap()) + } +} diff --git a/src/plat/mod.rs b/src/plat/mod.rs new file mode 100644 index 0000000..4da9482 --- /dev/null +++ b/src/plat/mod.rs @@ -0,0 +1,24 @@ +use std::path::PathBuf; + +use crate::aliases::IoResult; + +pub(crate) mod linux; + +pub trait Platform { + type NewOptions: Default; + type FileHandle; + + fn new(opts: Self::NewOptions) -> IoResult + where + Self: Sized; + + async fn tick(&self) -> IoResult<()>; + + async fn open_file(&self, path: PathBuf) -> IoResult; + async fn read( + &self, + f: &mut Self::FileHandle, + offset: usize, + buf: Box<[u8]>, + ) -> IoResult>; +} diff --git a/src/wove.rs b/src/wove.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/wove.rs @@ -0,0 +1 @@ +