@devaloop/devalang 0.0.1-alpha.16-hotfix.3 → 0.0.1-alpha.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +10 -10
  3. package/.github/workflows/ci.yml +0 -1
  4. package/Cargo.toml +18 -2
  5. package/README.md +82 -34
  6. package/docs/CHANGELOG.md +91 -0
  7. package/docs/ROADMAP.md +7 -4
  8. package/docs/TODO.md +1 -1
  9. package/examples/index.deva +55 -35
  10. package/examples/pattern.deva +5 -5
  11. package/out-tsc/bin/index.d.ts +2 -0
  12. package/out-tsc/core/functions/index.d.ts +37 -0
  13. package/out-tsc/core/functions/index.js +76 -0
  14. package/out-tsc/core/index.d.ts +6 -0
  15. package/out-tsc/core/index.js +22 -0
  16. package/out-tsc/core/types/index.d.ts +4 -0
  17. package/out-tsc/core/types/index.js +20 -0
  18. package/out-tsc/core/types/plugin.d.ts +18 -0
  19. package/out-tsc/core/types/plugin.js +2 -0
  20. package/out-tsc/core/types/result.d.ts +27 -0
  21. package/out-tsc/core/types/result.js +2 -0
  22. package/out-tsc/core/types/statement.d.ts +106 -0
  23. package/out-tsc/core/types/statement.js +2 -0
  24. package/out-tsc/core/types/value.d.ts +43 -0
  25. package/out-tsc/core/types/value.js +2 -0
  26. package/out-tsc/index.d.ts +7 -0
  27. package/out-tsc/index.js +41 -2
  28. package/out-tsc/pkg/devalang_core.d.ts +7 -0
  29. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
  30. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  31. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  32. package/out-tsc/scripts/postinstall.d.ts +1 -0
  33. package/out-tsc/scripts/postinstall.js +33 -23
  34. package/out-tsc/scripts/version/bump.d.ts +1 -0
  35. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  36. package/out-tsc/scripts/version/index.d.ts +1 -0
  37. package/out-tsc/scripts/version/sync.d.ts +1 -0
  38. package/package.json +16 -4
  39. package/project-version.json +3 -3
  40. package/rust/cli/bank/api.rs +122 -0
  41. package/rust/cli/bank/commands.rs +275 -0
  42. package/rust/cli/bank/mod.rs +29 -0
  43. package/rust/cli/build/commands.rs +107 -0
  44. package/rust/cli/build/mod.rs +2 -0
  45. package/rust/cli/build/process.rs +146 -0
  46. package/rust/cli/{check.rs → check/mod.rs} +18 -31
  47. package/rust/cli/discover/commands.rs +253 -0
  48. package/rust/cli/discover/config.rs +111 -0
  49. package/rust/cli/discover/fs.rs +19 -0
  50. package/rust/cli/discover/install.rs +103 -0
  51. package/rust/cli/discover/metadata.rs +48 -0
  52. package/rust/cli/discover/mod.rs +5 -0
  53. package/rust/cli/{init.rs → init/commands.rs} +88 -87
  54. package/rust/cli/init/mod.rs +1 -0
  55. package/rust/cli/install/addon.rs +126 -0
  56. package/rust/cli/install/bank.rs +53 -0
  57. package/rust/cli/{install.rs → install/commands.rs} +9 -9
  58. package/rust/{installer → cli/install}/mod.rs +2 -3
  59. package/rust/cli/install/plugin.rs +61 -0
  60. package/rust/cli/{login.rs → login/commands.rs} +8 -11
  61. package/rust/cli/login/mod.rs +1 -0
  62. package/rust/cli/mod.rs +2 -2
  63. package/rust/cli/{driver.rs → parser.rs} +7 -2
  64. package/rust/cli/play/commands.rs +324 -0
  65. package/rust/cli/play/io.rs +17 -0
  66. package/rust/cli/play/mod.rs +5 -0
  67. package/rust/cli/play/process.rs +150 -0
  68. package/rust/cli/play/realtime.rs +91 -0
  69. package/rust/cli/play/utils.rs +23 -0
  70. package/rust/cli/{telemetry.rs → telemetry/commands.rs} +4 -4
  71. package/rust/cli/telemetry/event_creator.rs +80 -0
  72. package/rust/cli/telemetry/mod.rs +3 -0
  73. package/rust/cli/telemetry/send.rs +51 -0
  74. package/rust/cli/{template.rs → template/commands.rs} +1 -1
  75. package/rust/cli/template/mod.rs +1 -0
  76. package/rust/cli/{update.rs → update/commands.rs} +6 -6
  77. package/rust/cli/update/mod.rs +1 -0
  78. package/rust/config/driver.rs +57 -72
  79. package/rust/config/mod.rs +1 -2
  80. package/rust/config/ops.rs +26 -0
  81. package/rust/config/settings.rs +40 -42
  82. package/rust/core/audio/engine/helpers.rs +158 -0
  83. package/rust/core/audio/engine/mod.rs +7 -0
  84. package/rust/core/audio/engine/sample.rs +359 -0
  85. package/rust/core/audio/engine/synth.rs +325 -0
  86. package/rust/core/audio/evaluator.rs +68 -27
  87. package/rust/core/audio/interpreter/arrow_call.rs +113 -33
  88. package/rust/core/audio/interpreter/call.rs +232 -56
  89. package/rust/core/audio/interpreter/condition.rs +3 -2
  90. package/rust/core/audio/interpreter/driver.rs +206 -151
  91. package/rust/core/audio/interpreter/let_.rs +1 -1
  92. package/rust/core/audio/interpreter/load.rs +2 -1
  93. package/rust/core/audio/interpreter/loop_.rs +7 -6
  94. package/rust/core/audio/interpreter/sleep.rs +2 -1
  95. package/rust/core/audio/interpreter/spawn.rs +186 -54
  96. package/rust/core/audio/interpreter/tempo.rs +31 -10
  97. package/rust/core/audio/interpreter/trigger.rs +2 -2
  98. package/rust/core/audio/loader/trigger.rs +4 -7
  99. package/rust/core/audio/player.rs +6 -0
  100. package/rust/core/audio/renderer.rs +5 -7
  101. package/rust/core/audio/special/env.rs +3 -1
  102. package/rust/core/audio/special/math.rs +26 -6
  103. package/rust/core/audio/special/modulator.rs +2 -2
  104. package/rust/core/builder/mod.rs +9 -3
  105. package/rust/core/debugger/lexer.rs +1 -1
  106. package/rust/core/debugger/mod.rs +6 -0
  107. package/rust/core/debugger/module.rs +4 -4
  108. package/rust/core/debugger/preprocessor.rs +1 -1
  109. package/rust/core/debugger/store.rs +2 -2
  110. package/rust/core/error/mod.rs +189 -0
  111. package/rust/core/lexer/driver.rs +61 -0
  112. package/rust/core/lexer/handler/arrow.rs +1 -1
  113. package/rust/core/lexer/handler/at.rs +1 -1
  114. package/rust/core/lexer/handler/brace.rs +2 -2
  115. package/rust/core/lexer/handler/colon.rs +1 -1
  116. package/rust/core/lexer/handler/comment.rs +1 -1
  117. package/rust/core/lexer/handler/dot.rs +1 -1
  118. package/rust/core/lexer/handler/driver.rs +1 -1
  119. package/rust/core/lexer/handler/identifier.rs +4 -3
  120. package/rust/core/lexer/handler/mod.rs +1 -2
  121. package/rust/core/lexer/handler/number.rs +1 -1
  122. package/rust/core/lexer/handler/operator.rs +1 -1
  123. package/rust/core/lexer/handler/parenthesis.rs +2 -2
  124. package/rust/core/lexer/handler/slash.rs +1 -1
  125. package/rust/core/lexer/handler/string.rs +1 -1
  126. package/rust/core/lexer/mod.rs +1 -52
  127. package/rust/core/lexer/token.rs +91 -97
  128. package/rust/core/mod.rs +0 -1
  129. package/rust/core/parser/driver.rs +78 -22
  130. package/rust/core/parser/handler/arrow_call.rs +28 -8
  131. package/rust/core/parser/handler/at.rs +55 -21
  132. package/rust/core/parser/handler/bank.rs +14 -4
  133. package/rust/core/parser/handler/condition.rs +6 -3
  134. package/rust/core/parser/handler/dot.rs +5 -3
  135. package/rust/core/parser/handler/identifier/automate.rs +13 -16
  136. package/rust/core/parser/handler/identifier/call.rs +4 -4
  137. package/rust/core/parser/handler/identifier/emit.rs +9 -5
  138. package/rust/core/parser/handler/identifier/function.rs +20 -7
  139. package/rust/core/parser/handler/identifier/group.rs +11 -7
  140. package/rust/core/parser/handler/identifier/let_.rs +24 -9
  141. package/rust/core/parser/handler/identifier/mod.rs +6 -5
  142. package/rust/core/parser/handler/identifier/on.rs +16 -7
  143. package/rust/core/parser/handler/identifier/print.rs +6 -9
  144. package/rust/core/parser/handler/identifier/sleep.rs +12 -5
  145. package/rust/core/parser/handler/identifier/spawn.rs +4 -4
  146. package/rust/core/parser/handler/identifier/synth.rs +79 -9
  147. package/rust/core/parser/handler/loop_.rs +38 -13
  148. package/rust/core/parser/handler/mod.rs +1 -0
  149. package/rust/core/parser/handler/pattern.rs +74 -0
  150. package/rust/core/parser/handler/tempo.rs +9 -5
  151. package/rust/core/parser/mod.rs +0 -1
  152. package/rust/core/parser/statement.rs +6 -137
  153. package/rust/core/plugin/loader.rs +41 -27
  154. package/rust/core/plugin/runner.rs +68 -17
  155. package/rust/core/preprocessor/loader.rs +181 -99
  156. package/rust/core/preprocessor/processor.rs +9 -9
  157. package/rust/core/preprocessor/resolver/bank.rs +6 -8
  158. package/rust/core/preprocessor/resolver/call.rs +47 -23
  159. package/rust/core/preprocessor/resolver/condition.rs +6 -8
  160. package/rust/core/preprocessor/resolver/driver.rs +28 -28
  161. package/rust/core/preprocessor/resolver/function.rs +6 -6
  162. package/rust/core/preprocessor/resolver/group.rs +6 -8
  163. package/rust/core/preprocessor/resolver/loop_.rs +8 -10
  164. package/rust/core/preprocessor/resolver/mod.rs +1 -0
  165. package/rust/core/preprocessor/resolver/pattern.rs +75 -0
  166. package/rust/core/preprocessor/resolver/spawn.rs +45 -22
  167. package/rust/core/preprocessor/resolver/synth.rs +6 -8
  168. package/rust/core/preprocessor/resolver/tempo.rs +6 -8
  169. package/rust/core/preprocessor/resolver/trigger.rs +22 -19
  170. package/rust/core/preprocessor/resolver/value.rs +99 -4
  171. package/rust/core/store/export.rs +28 -28
  172. package/rust/core/store/function.rs +6 -0
  173. package/rust/core/store/global.rs +7 -1
  174. package/rust/core/store/import.rs +28 -28
  175. package/rust/core/store/variable.rs +16 -2
  176. package/rust/core/utils/mod.rs +0 -1
  177. package/rust/lib.rs +102 -9
  178. package/rust/main.rs +159 -45
  179. package/rust/types/Cargo.toml +11 -0
  180. package/rust/types/src/addons.rs +55 -0
  181. package/rust/types/src/ast.rs +202 -0
  182. package/rust/types/src/config.rs +74 -0
  183. package/rust/types/src/lib.rs +12 -0
  184. package/rust/types/src/telemetry.rs +85 -0
  185. package/rust/utils/Cargo.toml +26 -0
  186. package/rust/utils/{error.rs → src/error.rs} +186 -200
  187. package/rust/utils/src/file.rs +94 -0
  188. package/rust/utils/src/first_usage.rs +97 -0
  189. package/rust/utils/{mod.rs → src/lib.rs} +1 -1
  190. package/rust/utils/{logger.rs → src/logger.rs} +17 -12
  191. package/rust/utils/src/path.rs +88 -0
  192. package/rust/utils/src/signature.rs +41 -0
  193. package/rust/utils/{spinner.rs → src/spinner.rs} +3 -5
  194. package/rust/utils/src/version.rs +27 -0
  195. package/rust/utils/{watcher.rs → src/watcher.rs} +13 -1
  196. package/rust/web/cdn.rs +34 -0
  197. package/templates/minimal/README.md +98 -54
  198. package/templates/welcome/README.md +98 -54
  199. package/templates/welcome/src/index.deva +56 -8
  200. package/templates/welcome/src/variables.deva +2 -4
  201. package/tests/rust/TODO.md +0 -0
  202. package/tests/typescript/index.spec.ts +136 -0
  203. package/tests/typescript/playhead.spec.ts +36 -0
  204. package/tests/typescript/render_e2e.spec.ts +77 -0
  205. package/tsconfig.json +1 -1
  206. package/typescript/core/functions/index.ts +83 -0
  207. package/typescript/core/index.ts +6 -0
  208. package/typescript/core/types/index.ts +4 -0
  209. package/typescript/core/types/plugin.ts +19 -0
  210. package/typescript/core/types/result.ts +29 -0
  211. package/typescript/core/types/statement.ts +47 -0
  212. package/typescript/core/types/value.ts +29 -0
  213. package/typescript/index.ts +7 -2
  214. package/typescript/pkg/devalang_core.d.ts +4 -0
  215. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  216. package/rust/cli/bank.rs +0 -462
  217. package/rust/cli/build.rs +0 -252
  218. package/rust/cli/play.rs +0 -1123
  219. package/rust/common/cdn.rs +0 -5
  220. package/rust/config/loader.rs +0 -165
  221. package/rust/config/stats.rs +0 -257
  222. package/rust/core/audio/engine.rs +0 -696
  223. package/rust/core/shared/bank.rs +0 -21
  224. package/rust/core/shared/duration.rs +0 -9
  225. package/rust/core/shared/mod.rs +0 -3
  226. package/rust/core/shared/value.rs +0 -35
  227. package/rust/core/utils/validation.rs +0 -35
  228. package/rust/installer/addon.rs +0 -84
  229. package/rust/installer/bank.rs +0 -62
  230. package/rust/installer/plugin.rs +0 -54
  231. package/rust/installer/utils.rs +0 -56
  232. package/rust/utils/file.rs +0 -38
  233. package/rust/utils/first_usage.rs +0 -83
  234. package/rust/utils/signature.rs +0 -19
  235. package/rust/utils/telemetry.rs +0 -292
  236. package/rust/utils/version.rs +0 -15
  237. /package/rust/{common → web}/api.rs +0 -0
  238. /package/rust/{common → web}/mod.rs +0 -0
  239. /package/rust/{common → web}/sso.rs +0 -0
@@ -1,142 +1,11 @@
1
- use crate::core::{
2
- lexer::token::Token,
3
- shared::{duration::Duration, value::Value},
4
- };
5
- use serde::{Deserialize, Serialize};
1
+ use crate::core::lexer::token::Token;
6
2
 
7
- #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8
- pub struct Statement {
9
- pub kind: StatementKind,
10
- pub value: Value,
11
- pub indent: usize,
12
- pub line: usize,
13
- pub column: usize,
14
- }
15
-
16
- impl Statement {
17
- pub fn unknown() -> Self {
18
- Statement {
19
- kind: StatementKind::Unknown,
20
- value: Value::Null,
21
- indent: 0,
22
- line: 0,
23
- column: 0,
24
- }
25
- }
26
-
27
- pub fn unknown_from_token(token: &Token) -> Self {
28
- Statement {
29
- kind: StatementKind::Unknown,
30
- value: Value::Null,
31
- indent: token.indent,
32
- line: token.line,
33
- column: token.column,
34
- }
35
- }
3
+ pub use devalang_types::{Duration, Statement, StatementKind, Value};
36
4
 
37
- pub fn error(token: Token, message: String) -> Self {
38
- Statement {
39
- kind: StatementKind::Error { message },
40
- value: Value::Null,
41
- indent: token.indent,
42
- line: token.line,
43
- column: token.column,
44
- }
45
- }
5
+ pub fn unknown_from_token(token: &Token) -> Statement {
6
+ Statement::unknown_with_pos(token.indent, token.line, token.column)
46
7
  }
47
8
 
48
- #[derive(Debug, Serialize, Clone, Deserialize, PartialEq)]
49
- pub enum StatementKind {
50
- // ───── Core Instructions ─────
51
- Tempo,
52
- Bank {
53
- alias: Option<String>,
54
- },
55
- Print,
56
- Load {
57
- source: String,
58
- alias: String,
59
- },
60
- Use {
61
- name: String,
62
- alias: Option<String>,
63
- },
64
- Let {
65
- name: String,
66
- },
67
- Automate {
68
- target: String,
69
- },
70
- ArrowCall {
71
- target: String,
72
- method: String,
73
- args: Vec<Value>,
74
- },
75
- Function {
76
- name: String,
77
- parameters: Vec<String>,
78
- body: Vec<Statement>,
79
- },
80
-
81
- // ───── Instruments ─────
82
- Synth,
83
-
84
- // ───── Playback / Scheduling ─────
85
- Trigger {
86
- entity: String,
87
- duration: Duration,
88
- effects: Option<Value>,
89
- },
90
- Sleep,
91
- Call {
92
- name: String,
93
- args: Vec<Value>,
94
- },
95
- Spawn {
96
- name: String,
97
- args: Vec<Value>,
98
- },
99
- Loop,
100
-
101
- // ───── Structure & Logic ─────
102
- Group,
103
-
104
- // ───── Module System ─────
105
- Include(String),
106
- Export {
107
- names: Vec<String>,
108
- source: String,
109
- },
110
- Import {
111
- names: Vec<String>,
112
- source: String,
113
- },
114
-
115
- // ───── Conditions ─────
116
- If,
117
- Else,
118
- ElseIf,
119
-
120
- // ───── Internal / Utility ─────
121
- Comment,
122
- Indent,
123
- Dedent,
124
- NewLine,
125
-
126
- // ───── Events / Live coding ─────
127
- On {
128
- event: String,
129
- args: Option<Vec<Value>>,
130
- body: Vec<Statement>,
131
- },
132
- Emit {
133
- event: String,
134
- payload: Option<Value>,
135
- },
136
-
137
- // ───── Error Handling ─────
138
- Unknown,
139
- Error {
140
- message: String,
141
- },
9
+ pub fn error_from_token(token: Token, message: String) -> Statement {
10
+ Statement::error_with_pos(token.indent, token.line, token.column, message)
142
11
  }
@@ -1,19 +1,10 @@
1
+ use devalang_types::{PluginExport, PluginInfo as SharedPluginInfo};
2
+ use devalang_utils::path as path_utils;
1
3
  use serde::Deserialize;
2
- use std::path::Path;
3
4
  use toml::Value as TomlValue;
4
5
 
5
6
  #[derive(Debug, Deserialize, Clone)]
6
- pub struct PluginInfo {
7
- pub name: String,
8
- pub version: Option<String>,
9
- pub description: Option<String>,
10
- pub author: Option<String>,
11
- #[serde(skip)]
12
- pub exports: Vec<ExportEntry>,
13
- }
14
-
15
- #[derive(Debug, Deserialize, Clone)]
16
- pub struct ExportEntry {
7
+ struct LocalExportEntry {
17
8
  pub name: String,
18
9
  #[serde(rename = "type")]
19
10
  pub kind: String,
@@ -22,24 +13,29 @@ pub struct ExportEntry {
22
13
  }
23
14
 
24
15
  #[derive(Debug, Deserialize, Clone)]
25
- pub struct PluginFile {
26
- pub plugin: PluginInfo,
16
+ struct LocalPluginFile {
17
+ pub plugin: LocalPluginInfo,
27
18
  #[serde(default)]
28
- pub export: Vec<ExportEntry>,
19
+ pub export: Vec<LocalExportEntry>,
29
20
  }
30
21
 
31
- /// Load a plugin from local .deva directory given author and name
32
- pub fn load_plugin(author: &str, name: &str) -> Result<(PluginInfo, Vec<u8>), String> {
33
- // Align with other loaders (banks) that use relative ./.deva paths
34
- let root = Path::new("./.deva");
35
- // Preferred layout: ./.deva/plugin/<author>.<name>/
36
- let plugin_dir_preferred = root.join("plugin").join(format!("{}.{}", author, name));
22
+ #[derive(Debug, Deserialize, Clone)]
23
+ struct LocalPluginInfo {
24
+ pub name: String,
25
+ pub version: Option<String>,
26
+ pub description: Option<String>,
27
+ pub author: Option<String>,
28
+ }
29
+
30
+ pub fn load_plugin(author: &str, name: &str) -> Result<(SharedPluginInfo, Vec<u8>), String> {
31
+ let root = path_utils::get_deva_dir()?;
32
+ let plugin_dir_preferred = root.join("plugins").join(format!("{}.{}", author, name));
37
33
  let toml_path_preferred = plugin_dir_preferred.join("plugin.toml");
38
34
  let wasm_path_preferred_bg = plugin_dir_preferred.join(format!("{}_bg.wasm", name));
39
35
  let wasm_path_preferred_plain = plugin_dir_preferred.join(format!("{}.wasm", name));
40
36
 
41
37
  // Legacy layout (fallback): ./.deva/plugin/<author>/<name>/
42
- let plugin_dir_fallback = root.join("plugin").join(author).join(name);
38
+ let plugin_dir_fallback = root.join("plugins").join(author).join(name);
43
39
  let toml_path_fallback = plugin_dir_fallback.join("plugin.toml");
44
40
  let wasm_path_fallback_bg = plugin_dir_fallback.join(format!("{}_bg.wasm", name));
45
41
  let wasm_path_fallback_plain = plugin_dir_fallback.join(format!("{}.wasm", name));
@@ -74,20 +70,38 @@ pub fn load_plugin(author: &str, name: &str) -> Result<(PluginInfo, Vec<u8>), St
74
70
 
75
71
  let toml_content = std::fs::read_to_string(&toml_path)
76
72
  .map_err(|e| format!("Failed to read '{}': {}", toml_path.display(), e))?;
77
- let plugin_file: PluginFile = toml::from_str(&toml_content)
73
+ let plugin_file: LocalPluginFile = toml::from_str(&toml_content)
78
74
  .map_err(|e| format!("Failed to parse '{}': {}", toml_path.display(), e))?;
79
75
 
80
76
  let wasm_bytes = std::fs::read(&wasm_path)
81
77
  .map_err(|e| format!("Failed to read '{}': {}", wasm_path.display(), e))?;
82
78
 
83
- let mut info = plugin_file.plugin.clone();
84
- info.exports = plugin_file.export.clone();
79
+ // Map local parsed plugin info to shared PluginInfo
80
+ let mut exports: Vec<PluginExport> = Vec::new();
81
+ for e in plugin_file.export.iter() {
82
+ exports.push(PluginExport {
83
+ name: e.name.clone(),
84
+ kind: e.kind.clone(),
85
+ default: e.default.clone(),
86
+ });
87
+ }
88
+
89
+ let info = SharedPluginInfo {
90
+ author: plugin_file
91
+ .plugin
92
+ .author
93
+ .unwrap_or_else(|| author.to_string()),
94
+ name: plugin_file.plugin.name.clone(),
95
+ version: plugin_file.plugin.version.clone(),
96
+ description: plugin_file.plugin.description.clone(),
97
+ exports,
98
+ };
85
99
 
86
100
  Ok((info, wasm_bytes))
87
101
  }
88
102
 
89
103
  /// Load a plugin from dot notation: "author.name"
90
- pub fn load_plugin_from_dot(dot: &str) -> Result<(PluginInfo, Vec<u8>), String> {
104
+ pub fn load_plugin_from_dot(dot: &str) -> Result<(SharedPluginInfo, Vec<u8>), String> {
91
105
  let mut parts = dot.split('.');
92
106
  let author = parts
93
107
  .next()
@@ -101,7 +115,7 @@ pub fn load_plugin_from_dot(dot: &str) -> Result<(PluginInfo, Vec<u8>), String>
101
115
  load_plugin(author, name)
102
116
  }
103
117
 
104
- pub fn load_plugin_from_uri(uri: &str) -> Result<(PluginInfo, Vec<u8>), String> {
118
+ pub fn load_plugin_from_uri(uri: &str) -> Result<(SharedPluginInfo, Vec<u8>), String> {
105
119
  if !uri.starts_with("devalang://plugin/") {
106
120
  return Err("Invalid plugin URI".into());
107
121
  }
@@ -1,10 +1,24 @@
1
1
  use std::collections::HashMap;
2
+
3
+ #[cfg(not(target_arch = "wasm32"))]
2
4
  use wasmtime::{Engine, Instance, Linker, Module, Store, TypedFunc};
3
5
 
6
+ #[cfg(not(target_arch = "wasm32"))]
7
+ type RenderFunc = TypedFunc<(i32, i32, f32, f32, i32, i32, i32), ()>;
8
+
9
+ #[cfg(not(target_arch = "wasm32"))]
4
10
  pub struct WasmPluginRunner {
5
11
  engine: Engine,
6
12
  }
7
13
 
14
+ #[cfg(not(target_arch = "wasm32"))]
15
+ impl Default for WasmPluginRunner {
16
+ fn default() -> Self {
17
+ Self::new()
18
+ }
19
+ }
20
+
21
+ #[cfg(not(target_arch = "wasm32"))]
8
22
  impl WasmPluginRunner {
9
23
  pub fn new() -> Self {
10
24
  let engine = Engine::default();
@@ -18,38 +32,32 @@ impl WasmPluginRunner {
18
32
  let mut store = Store::new(&self.engine, ());
19
33
  let linker = Linker::new(&self.engine);
20
34
 
21
- // Instantiate
22
35
  let instance = linker
23
36
  .instantiate(&mut store, &module)
24
37
  .map_err(|e| format!("Failed to instantiate wasm: {e}"))?;
25
38
 
26
- // Get exports
27
39
  let memory = instance
28
40
  .get_memory(&mut store, "memory")
29
41
  .ok_or_else(|| "WASM memory export not found".to_string())?;
30
42
 
31
- // wasm-bindgen usually exports a function taking (ptr: i32, len: i32) to represent &mut [f32]
32
43
  let func = instance
33
44
  .get_typed_func::<(i32, i32), ()>(&mut store, "process")
34
45
  .map_err(|_| "Exported function `process(i32,i32)` not found".to_string())?;
35
46
 
36
- // Copy host buffer into wasm memory
37
- let byte_len = (buffer.len() * std::mem::size_of::<f32>()) as i32;
47
+ let byte_len = std::mem::size_of_val(buffer) as i32;
38
48
  let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
39
49
  let mem_slice = memory
40
50
  .data_mut(&mut store)
41
51
  .get_mut(ptr as usize..(ptr as usize) + (byte_len as usize))
42
52
  .ok_or_else(|| "Failed to get memory slice".to_string())?;
43
- // Safety: same alignment/layout
53
+
44
54
  let src_bytes =
45
55
  unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const u8, byte_len as usize) };
46
56
  mem_slice.copy_from_slice(src_bytes);
47
57
 
48
- // Call process
49
58
  func.call(&mut store, (ptr, buffer.len() as i32))
50
59
  .map_err(|e| format!("Error calling `process`: {e}"))?;
51
60
 
52
- // Copy back
53
61
  let mem_slice_after = memory
54
62
  .data(&store)
55
63
  .get(ptr as usize..(ptr as usize) + (byte_len as usize))
@@ -62,8 +70,6 @@ impl WasmPluginRunner {
62
70
  Ok(())
63
71
  }
64
72
 
65
- /// Render a note by invoking either `render_note_<name>` or a generic `render_note(ptr,len,freq,amp,duration_ms,sample_rate,channels)`.
66
- /// The buffer is interleaved stereo if channels=2. The buffer is modified in place.
67
73
  pub fn render_note_in_place(
68
74
  &self,
69
75
  wasm_bytes: &[u8],
@@ -90,7 +96,7 @@ impl WasmPluginRunner {
90
96
  .ok_or_else(|| "WASM memory export not found".to_string())?;
91
97
 
92
98
  // Try specific function first
93
- let mut func_opt: Option<TypedFunc<(i32, i32, f32, f32, i32, i32, i32), ()>> = None;
99
+ let mut func_opt: Option<RenderFunc> = None;
94
100
  if let Some(name) = synth_name {
95
101
  let specific = format!("render_note_{}", name);
96
102
  if let Ok(f) = instance
@@ -113,7 +119,7 @@ impl WasmPluginRunner {
113
119
  func_opt.ok_or_else(|| "Exported function `render_note` not found".to_string())?;
114
120
 
115
121
  // Copy host buffer into wasm memory
116
- let byte_len = (buffer.len() * std::mem::size_of::<f32>()) as i32;
122
+ let byte_len = std::mem::size_of_val(buffer) as i32;
117
123
  let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
118
124
  let mem_slice = memory
119
125
  .data_mut(&mut store)
@@ -207,7 +213,7 @@ impl WasmPluginRunner {
207
213
  }
208
214
 
209
215
  // Try specific or generic render function
210
- let mut func_opt: Option<TypedFunc<(i32, i32, f32, f32, i32, i32, i32), ()>> = None;
216
+ let mut func_opt: Option<RenderFunc> = None;
211
217
  if let Some(name) = synth_name {
212
218
  let specific = format!("render_note_{}", name);
213
219
  if let Ok(f) = instance
@@ -228,7 +234,7 @@ impl WasmPluginRunner {
228
234
  func_opt.ok_or_else(|| "Exported function `render_note` not found".to_string())?;
229
235
 
230
236
  // Copy host buffer into wasm memory
231
- let byte_len = (buffer.len() * std::mem::size_of::<f32>()) as i32;
237
+ let byte_len = std::mem::size_of_val(buffer) as i32;
232
238
  let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
233
239
  let mem_slice = memory
234
240
  .data_mut(&mut store)
@@ -283,10 +289,10 @@ impl WasmPluginRunner {
283
289
  // Fallback: grow memory and use end of memory as scratch space
284
290
  let current_len = memory.data_size(&mut *store);
285
291
  let need = size;
286
- let pages_needed = ((current_len + need + 0xffff) / 0x10000) as u64; // 64KiB pages
292
+ let pages_needed = (current_len + need).div_ceil(0x10000) as u64; // 64KiB pages
287
293
  let current_pages = memory.size(&mut *store);
288
- if pages_needed > (current_pages as u64) {
289
- let to_grow = pages_needed - (current_pages as u64);
294
+ if pages_needed > current_pages {
295
+ let to_grow = pages_needed - current_pages;
290
296
  memory
291
297
  .grow(&mut *store, to_grow)
292
298
  .map_err(|e| format!("memory.grow failed: {e}"))?;
@@ -294,3 +300,48 @@ impl WasmPluginRunner {
294
300
  Ok(current_len)
295
301
  }
296
302
  }
303
+
304
+ // Provide a minimal stub for wasm32 target so the crate compiles there.
305
+ #[cfg(target_arch = "wasm32")]
306
+ pub struct WasmPluginRunner;
307
+
308
+ #[cfg(target_arch = "wasm32")]
309
+ impl WasmPluginRunner {
310
+ pub fn new() -> Self {
311
+ WasmPluginRunner
312
+ }
313
+
314
+ pub fn process_in_place(&self, _wasm_bytes: &[u8], _buffer: &mut [f32]) -> Result<(), String> {
315
+ Err("Wasm plugin execution is not available in wasm builds".to_string())
316
+ }
317
+
318
+ pub fn render_note_in_place(
319
+ &self,
320
+ _wasm_bytes: &[u8],
321
+ _buffer: &mut [f32],
322
+ _synth_name: Option<&str>,
323
+ _freq: f32,
324
+ _amp: f32,
325
+ _duration_ms: i32,
326
+ _sample_rate: i32,
327
+ _channels: i32,
328
+ ) -> Result<(), String> {
329
+ Err("Wasm plugin rendering is not available in wasm builds".to_string())
330
+ }
331
+
332
+ pub fn render_note_with_params_in_place(
333
+ &self,
334
+ _wasm_bytes: &[u8],
335
+ _buffer: &mut [f32],
336
+ _synth_name: Option<&str>,
337
+ _freq: f32,
338
+ _amp: f32,
339
+ _duration_ms: i32,
340
+ _sample_rate: i32,
341
+ _channels: i32,
342
+ _params_num: &HashMap<String, f32>,
343
+ _params_str: Option<&HashMap<String, String>>,
344
+ ) -> Result<(), String> {
345
+ Err("Wasm plugin rendering is not available in wasm builds".to_string())
346
+ }
347
+ }