diff --git a/Cargo.lock b/Cargo.lock index 01ca893..b771d7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -795,6 +795,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +dependencies = [ + "getrandom 0.2.17", +] + [[package]] name = "filetime" version = "0.2.27" @@ -834,6 +843,18 @@ dependencies = [ "spin", ] +[[package]] +name = "flume" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" +dependencies = [ + "fastrand", + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -873,9 +894,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -888,9 +909,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -898,15 +919,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -921,9 +942,9 @@ checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -932,21 +953,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -956,7 +977,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1443,7 +1463,10 @@ version = "0.1.0" dependencies = [ "clap", "deno_core", + "flume 0.12.0", + "futures", "mize", + "tokio", ] [[package]] @@ -1542,7 +1565,7 @@ dependencies = [ "daemonize", "dyn-clone", "flate2", - "flume", + "flume 0.11.1", "home", "http_req", "interner", @@ -1739,12 +1762,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "potential_utf" version = "0.1.4" diff --git a/deno.json b/deno.json index 6685180..93cd9ed 100644 --- a/deno.json +++ b/deno.json @@ -1,4 +1,8 @@ { - "workspace": ["./packages/ppc/platform/obsidian", "./packages/marts"], + "workspace": [ + "./packages/ppc/platform/obsidian", + "./packages/marts", + "./packages/mize" + ], "imports": {} } diff --git a/packages/ac_mize_macros/src/lib.rs b/packages/ac_mize_macros/src/lib.rs index 0f17b8b..001c79f 100644 --- a/packages/ac_mize_macros/src/lib.rs +++ b/packages/ac_mize_macros/src/lib.rs @@ -35,7 +35,6 @@ pub fn mize_part(attr: TokenStream, item: TokenStream) -> TokenStream { let expanded = quote! { #input - use std::any::Any; // impl the default new impl impl mize::MizePartGenerated for #struct_name { @@ -45,13 +44,13 @@ pub fn mize_part(attr: TokenStream, item: TokenStream) -> TokenStream { fn get_mize_generated(&mut self) -> &mut Mize { &mut self.mize } - fn as_any_generated(&self) -> &dyn Any { + fn as_any_generated(&self) -> &dyn std::any::Any { self } - fn as_any_mut_generated(&mut self) -> &mut dyn Any { + fn as_any_mut_generated(&mut self) -> &mut dyn std::any::Any { self } - fn into_any_generated(self: Box) -> Box { + fn into_any_generated(self: Box) -> Box { self } } @@ -64,6 +63,22 @@ pub fn mize_part(attr: TokenStream, item: TokenStream) -> TokenStream { } } } + + /* + impl std::ops::Deref for mize::MizePartGuard<#struct_name> { + type Target = #struct_name; + + fn deref(&self) -> &Self::Target { + &*self.part.as_ref().unwrap() + } + } + + impl std::ops::DerefMut for mize::MizePartGuard<#struct_name> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.part.as_mut().unwrap() + } + } + */ }; TokenStream::from(expanded) diff --git a/packages/marts/Cargo.toml b/packages/marts/Cargo.toml index 2fc071e..f2c1c4b 100644 --- a/packages/marts/Cargo.toml +++ b/packages/marts/Cargo.toml @@ -7,11 +7,14 @@ edition = "2021" [dependencies] clap = { version = "4.5.59", optional = true } deno_core = { version = "0.385.0", optional = true } +flume = "0.12.0" +futures = "0.3.32" mize = { path = "../mize/", default-features = false } +tokio = "1.49.0" [features] default = ["target-os"] -target-os = [ "clap", "mize/target-os" ] +target-os = [ "clap", "mize/target-os", "deno_core" ] target-wasm = [ "mize/target-wasm" ] [lib] diff --git a/packages/marts/deno.json b/packages/marts/deno.json index 38e8585..b4f2038 100644 --- a/packages/marts/deno.json +++ b/packages/marts/deno.json @@ -2,6 +2,10 @@ "name": "@ppc/marts", "imports": {}, "exports": { - ".": "./index.ts" + ".": "./index.ts", + "stub_deno": "./js/stub_deno.ts" + }, + "tasks": { + "build": "deno bundle -o ./deno_dist/habitica.js ./habitica.ts" } } diff --git a/packages/marts/deno_dist/habitica.js b/packages/marts/deno_dist/habitica.js new file mode 100644 index 0000000..0b66e93 --- /dev/null +++ b/packages/marts/deno_dist/habitica.js @@ -0,0 +1,75 @@ +// habitica.ts +var opts = { + "habitica.api_url": { + env_var_name: "PPC_HABITICA_API_URL", + default_val: "https://habitica.com/api/v3" + }, + "habitica.user_id": { + env_var_name: "PPC_HABITICA_USER_ID" + }, + "habitica.client_name": { + default_val: "3544a0b8-d71a-46e0-9bb1-6ddbb2abcddb-PPC-Software" + }, + "habitica.api_token": { + env_var_name: "PPC_HABITICA_API_TOKEN" + } +}; +async function habitica(mize) { + console.log("hiiiiiiiiiiiiiiiiiiii"); + mize.add_opts(opts); + mize.add_part(new Habitica(mize)); +} +async function handleRateLimit(response) { + const limit = response.headers.get("X-RateLimit-Limit") || "NONE"; + const remaining = parseInt(response.headers.get("X-RateLimit-Remaining") || "10", 10); + const reset = response.headers.get("X-RateLimit-Reset"); + console.log(`RateLimit: ${limit} | Remaining: ${remaining} | Reset: ${reset}`); + if (remaining < 2 && reset) { + const resetDate = new Date(reset); + const now = /* @__PURE__ */ new Date(); + const waitMs = resetDate.getTime() - now.getTime() + 1e3; + if (waitMs > 0) { + console.log(`Waiting ${Math.round(waitMs / 1e3)} secs for next rate limit window...`); + await new Promise((resolve) => setTimeout(resolve, waitMs)); + } + } +} +var Habitica = class { + mize; + constructor(mize) { + this.mize = mize; + } + async get_tasks(type = "todos") { + return await this.api_request("GET", `tasks/user?type=${type}`); + } + async delete_task(id) { + await this.api_request("DELETE", `tasks/${id}`); + } + async api_request(method, path, extraHeaders = {}, data = {}) { + const mize = this.mize; + if (!path.startsWith("/")) { + path = "/" + path; + } + const headers = Object.assign({ + "Content-Type": "application/json", + "x-api-user": mize.get_config("habitica.user_id"), + "x-api-key": mize.get_config("habitica.api_token"), + "x-client": mize.get_config("habitica.client_name") + }, extraHeaders); + const response = await fetch(mize.get_config("habitica.api_url") + path, { + method, + headers, + body: JSON.stringify(data) + }); + await handleRateLimit(response); + if (!response.ok) { + console.log("request_url:", mize.get_config("habitica.api_url") + path); + throw new Error(`Habitica API error: ${response.status} ${response.statusText}`); + } + return (await response.json()).data; + } +}; +export { + habitica, + opts +}; diff --git a/packages/marts/habitica.ts b/packages/marts/habitica.ts new file mode 100644 index 0000000..1b337fd --- /dev/null +++ b/packages/marts/habitica.ts @@ -0,0 +1,105 @@ +import { Mize } from "@ppc/marts/stub_deno"; + +export const opts = { + "habitica.api_url": { + env_var_name: "PPC_HABITICA_API_URL", + default_val: "https://habitica.com/api/v3", + }, + "habitica.user_id": { + env_var_name: "PPC_HABITICA_USER_ID", + }, + "habitica.client_name": { + default_val: "3544a0b8-d71a-46e0-9bb1-6ddbb2abcddb-PPC-Software", + }, + "habitica.api_token": { + env_var_name: "PPC_HABITICA_API_TOKEN", + }, +}; + +export async function habitica(mize: Mize) { + console.log("hiiiiiiiiiiiiiiiiiiii"); + mize.add_opts(opts); + + mize.add_part(new Habitica(mize)); +} + +async function handleRateLimit(response) { + const limit = response.headers.get("X-RateLimit-Limit") || "NONE"; + const remaining = parseInt( + response.headers.get("X-RateLimit-Remaining") || "10", + 10, + ); + const reset = response.headers.get("X-RateLimit-Reset"); + + console.log( + `RateLimit: ${limit} | Remaining: ${remaining} | Reset: ${reset}`, + ); + + if (remaining < 2 && reset) { + const resetDate = new Date(reset); + const now = new Date(); + const waitMs = resetDate.getTime() - now.getTime() + 1000; + + if (waitMs > 0) { + console.log( + `Waiting ${Math.round(waitMs / 1000)} secs for next rate limit window...`, + ); + await new Promise((resolve) => setTimeout(resolve, waitMs)); + } + } +} + +class Habitica { + mize: Mize; + + constructor(mize: Mize) { + this.mize = mize; + } + + async get_tasks(type: string = "todos") { + return await this.api_request("GET", `tasks/user?type=${type}`); + } + + async delete_task(id: string) { + await this.api_request("DELETE", `tasks/${id}`); + } + + async api_request( + method: string, + path: string, + extraHeaders: object = {}, + data: object = {}, + ) { + const mize = this.mize; + + if (!path.startsWith("/")) { + path = "/" + path; + } + const headers = Object.assign( + { + "Content-Type": "application/json", + "x-api-user": mize.get_config("habitica.user_id"), + "x-api-key": mize.get_config("habitica.api_token"), + "x-client": mize.get_config("habitica.client_name"), + }, + extraHeaders, + ); + + const response = await fetch(mize.get_config("habitica.api_url") + path, { + method, + headers, + body: JSON.stringify(data), + }); + + await handleRateLimit(response); + + if (!response.ok) { + console.log("request_url:", mize.get_config("habitica.api_url") + path); + throw new Error( + `Habitica API error: ${response.status} ${response.statusText}`, + ); + } + + return (await response.json()).data; + } +} diff --git a/packages/marts/js/glue_deno.js b/packages/marts/js/glue_deno.js new file mode 100644 index 0000000..e69de29 diff --git a/packages/marts/js/glue_deno.rs b/packages/marts/js/glue_deno.rs new file mode 100644 index 0000000..02fc564 --- /dev/null +++ b/packages/marts/js/glue_deno.rs @@ -0,0 +1,35 @@ +use deno_core::extension; +use deno_core::op2; +use deno_core::OpState; +use mize::{Mize, MizeError}; +use std::sync::Arc; + +#[op2(fast)] +fn op_mize_get_part(#[string] name: &str) { + println!("js wants the part {}", name); +} + +#[op2] +#[string] +fn op_mize_get_config(state: &mut OpState, #[string] key: &str) -> String { + let mize: Mize = state.borrow::().clone(); + format!("config_value_for_{}", key) +} + +#[op2(fast)] +fn op_mize_add_part(state: &mut OpState, #[string] key: &str) { + let mize: Mize = state.borrow::().clone(); + println!("adding part {}", key); +} + +// Create an extension with your custom ops +extension!( + my_extension, + ops = [op_mize_get_part, op_mize_get_config], + options = { + mize: Mize, + }, + state = |state: &mut OpState, config: Config| { + state.put::(config.mize); + }, +); diff --git a/packages/marts/js/mod.rs b/packages/marts/js/mod.rs index 957b25a..f348630 100644 --- a/packages/marts/js/mod.rs +++ b/packages/marts/js/mod.rs @@ -1,32 +1,30 @@ use deno_core::error::AnyError; -use deno_core::FsModuleLoader; +use deno_core::url::Url; use deno_core::{extension, op2, JsRuntime, ModuleSpecifier, PollEventLoopOptions, RuntimeOptions}; +use deno_core::{FastStaticString, FsModuleLoader}; use mize::async_trait; use mize::instance::MizePartCreate; use mize::{mize_part, Mize, MizePart, MizeResult}; +use std::future::Future; use std::path::Path; +use std::pin::Pin; use std::rc::Rc; +use std::str::FromStr; +use tokio::runtime::Builder; +use tokio::task::{spawn_local, LocalSet}; + +mod glue_deno; #[mize_part("js")] +#[derive(Default)] pub struct JsPart { mize: Mize, - js_runtime: JsRuntime, + closure_sender: Option MizeResult<()> + Send>>>, + async_closure_sender: Option>, } -// Define your custom ops for the "mize" object inside deno -#[op2(fast)] -fn op_mize_get_part(#[string] name: &str) { - println!("js wants the part {}", name); -} - -#[op2] -#[string] -fn op_mize_get_config(#[string] key: &str) -> String { - format!("config_value_for_{}", key) -} - -// Create an extension with your custom ops -extension!(mize_ext, ops = [op_mize_get_part, op_mize_get_config]); +pub type BoxFuture<'a> = Pin> + 'a>>; +pub type BoxClosure = Box FnOnce(&'a mut JsRuntime) -> BoxFuture<'a> + Send + 'static>; impl MizePart for JsPart { fn init(&mut self, mize: &mut Mize) -> MizeResult<()> { @@ -35,26 +33,44 @@ impl MizePart for JsPart { } } -fn js(mize: &mut Mize) -> Box { - let mut js_runtime = JsRuntime::new(RuntimeOptions { - module_loader: Some(Rc::new(FsModuleLoader)), - extensions: vec![mize_ext::init_ops()], - ..Default::default() - }); - let bootstrap_code = r#" - globalThis.mize = { - get_part: (name) => Deno.core.ops.op_mize_get_part(name), - get_config: (key) => Deno.core.ops.op_mize_get_config(key), - version: "1.0.0", - // Add more methods as needed - }; - "#; +pub fn js(mize: &mut Mize) -> MizeResult<()> { + let (closure_sender, closure_receiver) = + flume::unbounded:: MizeResult<()> + Send>>(); + let (async_closure_sender, async_closure_receiver) = flume::unbounded::(); + let mize_clone = mize.clone(); - js_runtime.execute_script("[bootstrap]", bootstrap_code)?; - JsPart { mize, js_runtime } + // the thread which will run any js + mize.spawn("js_runtime_thread", || { + js_runtime_thread(mize_clone, closure_receiver, async_closure_receiver) + })?; + + mize.add_part(Box::new(JsPart { + mize: mize.clone(), + closure_sender: Some(closure_sender), + async_closure_sender: Some(async_closure_sender), + })) +} + +pub fn part_from_file( + mize: &mut Mize, + name: &'static str, + code: FastStaticString, +) -> MizeResult<()> { + let mut js = mize.get_part_native::("js")?; + js.with_runtime_async(move |runtime: &mut JsRuntime| { + let module_spec = ModuleSpecifier::from_str(name).unwrap(); + return Box::pin(async move { + runtime + .load_side_es_module_from_code(&module_spec, code) + .await; + Ok(()) + }); + }); + Ok(()) } impl JsPart { + /* pub fn part_from_js_file( &mut self, name: &'static str, @@ -66,12 +82,32 @@ impl JsPart { js_file: path, }) } - pub fn runtime(&mut self) -> &mut JsRuntime { - &mut self.js_runtime + */ + pub fn with_runtime MizeResult<()> + Send + 'static>( + &mut self, + func: T, + ) { + self.closure_sender + .as_mut() + .unwrap() + .send(Box::new(func)) + .unwrap(); + } + pub fn with_runtime_async(&mut self, func: F) + where + F: for<'a> FnOnce(&'a mut JsRuntime) -> BoxFuture<'a> + Send + 'static, + { + self.async_closure_sender + .as_mut() + .unwrap() + .send(Box::new(func)) + .unwrap(); } } +/* #[mize_part] +#[derive(Default)] struct PartFromJsFileAdapter { mize: Mize, name: &'static str, @@ -92,22 +128,22 @@ impl MizePart for PartFromJsFileAdapter { let js_code = format!( r#" import {{ opts, deps, create }} from "{path}"; - - const isPromise = (value) => { + + const isPromise = (value) => {{ return !!value && (typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function'; - }; - + }}; + // Call the async function let create_result = create(mize); - if (isPromise(create_result)) { + if (isPromise(create_result)) {{ create_result = await create_result; - } - const result = { + }} + const result = {{ opts: opts(mize), deps: deps(mize), create: create_result, - }; - + }}; + result; "# ); @@ -132,9 +168,9 @@ impl MizePart for PartFromJsFileAdapter { let js_code = format!( r#" import {{ run }} from "{path}"; - + const result = run() - + result; "# ); @@ -142,7 +178,7 @@ impl MizePart for PartFromJsFileAdapter { let result = js.runtime().execute_script("[main]", js_code)?; // Resolve the promise and run event loop - let resolved_value = js.runtime.resolve_value(result).await?; + let resolved_value = js.runtime().resolve_value(result).await?; // Run the event loop to completion js.runtime() @@ -153,3 +189,37 @@ impl MizePart for PartFromJsFileAdapter { Ok(()) } } +*/ + +fn js_runtime_thread( + mize: Mize, + closure_receiver: flume::Receiver MizeResult<()> + Send>>, + async_closure_receiver: flume::Receiver, +) -> MizeResult<()> { + let mut js_runtime = JsRuntime::new(RuntimeOptions { + module_loader: Some(Rc::new(FsModuleLoader)), + extensions: vec![glue_deno::my_extension::init(mize.clone())], + ..Default::default() + }); + + let poll_opts = PollEventLoopOptions::default(); + + let tokio_runtime = Builder::new_current_thread().enable_all().build().unwrap(); + + let local = LocalSet::new(); + local.block_on(&tokio_runtime, async move { + loop { + // Drain queued closures quickly (no await here if possible) + if let Ok(func) = closure_receiver.recv_async().await { + if let Err(e) = func(&mut js_runtime) { + mize.report_err(e); + } + } + + // Drive JS one tick + let _ = futures::future::poll_fn(|cx| js_runtime.poll_event_loop(cx, poll_opts)).await; + } + }); + + Ok(()) +} diff --git a/packages/marts/js/stub_deno.ts b/packages/marts/js/stub_deno.ts new file mode 100644 index 0000000..01f5755 --- /dev/null +++ b/packages/marts/js/stub_deno.ts @@ -0,0 +1,10 @@ +export class Mize { + async get_config(key: string): Promise { + return "hiiiiiii"; + } + async add_opts(opts: any): Promise {} + async add_part(part: any): Promise {} + async report_err(err: MizeError) {} +} + +type MizeError = string; diff --git a/packages/marts/lib.rs b/packages/marts/lib.rs index 7cf95e6..34eef46 100644 --- a/packages/marts/lib.rs +++ b/packages/marts/lib.rs @@ -1,6 +1,17 @@ #[cfg(feature = "target-os")] mod cli; #[cfg(feature = "target-os")] -pub use cli::*; +pub use cli::cli; -//mod js; +mod js; + +#[cfg(feature = "target-os")] +pub fn habitica(mize: &mut mize::Mize) { + use deno_core::{ascii_str_include, include_js_files}; + + js::part_from_file( + mize, + "habitica", + ascii_str_include!("./deno_dist/habitica.js"), + ); +} diff --git a/packages/mize/deno.json b/packages/mize/deno.json new file mode 100644 index 0000000..26cf443 --- /dev/null +++ b/packages/mize/deno.json @@ -0,0 +1,5 @@ +{ + "name": "@ppc/mize", + "imports": {}, + "exports": {} +} diff --git a/packages/mize/main.ts b/packages/mize/main.ts new file mode 100644 index 0000000..292ce5f --- /dev/null +++ b/packages/mize/main.ts @@ -0,0 +1,8 @@ +export function add(a: number, b: number): number { + return a + b; +} + +// Learn more at https://docs.deno.com/runtime/manual/examples/module_metadata#concepts +if (import.meta.main) { + console.log("Add 2 + 3 =", add(2, 3)); +} diff --git a/packages/mize/main_test.ts b/packages/mize/main_test.ts new file mode 100644 index 0000000..3d981e9 --- /dev/null +++ b/packages/mize/main_test.ts @@ -0,0 +1,6 @@ +import { assertEquals } from "@std/assert"; +import { add } from "./main.ts"; + +Deno.test(function addTest() { + assertEquals(add(2, 3), 5); +}); diff --git a/packages/mize/src/core/instance/mod.rs b/packages/mize/src/core/instance/mod.rs index a1fab7f..42e3ac4 100644 --- a/packages/mize/src/core/instance/mod.rs +++ b/packages/mize/src/core/instance/mod.rs @@ -3,6 +3,7 @@ use colored::Colorize; use core::fmt; use flume::{bounded, unbounded, Receiver, Sender}; use interner::shared::{StringPool, VecStringPool}; +use mize_macros::mize_part; use std::any::Any; use std::collections::HashMap; use std::fs::create_dir; @@ -860,6 +861,38 @@ impl Mize { part: Some(*concrete_part), }) } + pub fn add_name_only_part(&mut self, name: &'static str) { + let part = NameOnlyPart { + mize: self.clone(), + name, + }; + self.add_part(Box::new(part)); + } +} + +#[derive(Default)] +struct NameOnlyPart { + mize: Mize, + name: &'static str, +} + +impl MizePart for NameOnlyPart {} +impl MizePartGenerated for NameOnlyPart { + fn as_any_generated(&self) -> &dyn Any { + self.as_any() + } + fn as_any_mut_generated(&mut self) -> &mut dyn Any { + self.as_any_mut() + } + fn get_mize_generated(&mut self) -> &mut Mize { + &mut self.mize + } + fn into_any_generated(self: Box) -> Box { + self.into_any() + } + fn name_generated(&self) -> &'static str { + self.name + } } impl fmt::Debug for Mize { diff --git a/packages/ppc/Cargo.toml b/packages/ppc/Cargo.toml index 128e3ae..1a80b87 100644 --- a/packages/ppc/Cargo.toml +++ b/packages/ppc/Cargo.toml @@ -12,15 +12,16 @@ wasm-bindgen = { version = "0.2.108", optional = true } [[bin]] name = "ppc" -path = "src/platform/os/main.rs" +path = "platform/os/main.rs" [lib] crate-type = ["cdylib", "rlib"] path = "lib.rs" +name = "ppc" [features] default = ["target-os"] -target-os = [ "clap", "mize/target-os" ] +target-os = [ "clap", "mize/target-os", "marts/target-os" ] target-obsidian = [ "js-sys", "wasm-bindgen", "mize/target-wasm", "marts/target-wasm" ] [package.metadata.wasm-pack.profile.release]