@shieldbattery/danimoth 0.0.0-stage → 0.1.1

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.
@@ -0,0 +1,103 @@
1
+ //! Conversions between the SDK's enum values and the names `index.d.ts` uses for them.
2
+ // The SDK's constants keep their C names (see `sys.rs`).
3
+ #![allow(non_upper_case_globals)]
4
+
5
+ use neon::prelude::*;
6
+
7
+ use crate::sys::*;
8
+
9
+ pub fn client_status_name(status: Discord_Client_Status) -> &'static str {
10
+ match status {
11
+ Discord_Client_Status_Disconnected => "disconnected",
12
+ Discord_Client_Status_Connecting => "connecting",
13
+ Discord_Client_Status_Connected => "connected",
14
+ Discord_Client_Status_Ready => "ready",
15
+ Discord_Client_Status_Reconnecting => "reconnecting",
16
+ Discord_Client_Status_Disconnecting => "disconnecting",
17
+ Discord_Client_Status_HttpWait => "httpWait",
18
+ _ => "unknown",
19
+ }
20
+ }
21
+
22
+ pub fn client_error_name(error: Discord_Client_Error) -> &'static str {
23
+ match error {
24
+ Discord_Client_Error_None => "none",
25
+ Discord_Client_Error_ConnectionFailed => "connectionFailed",
26
+ Discord_Client_Error_UnexpectedClose => "unexpectedClose",
27
+ Discord_Client_Error_ConnectionCanceled => "connectionCanceled",
28
+ _ => "unknown",
29
+ }
30
+ }
31
+
32
+ pub fn error_type_name(error_type: Discord_ErrorType) -> &'static str {
33
+ match error_type {
34
+ Discord_ErrorType_None => "none",
35
+ Discord_ErrorType_NetworkError => "networkError",
36
+ Discord_ErrorType_HTTPError => "httpError",
37
+ Discord_ErrorType_ClientNotReady => "clientNotReady",
38
+ Discord_ErrorType_Disabled => "disabled",
39
+ Discord_ErrorType_ClientDestroyed => "clientDestroyed",
40
+ Discord_ErrorType_ValidationError => "validationError",
41
+ Discord_ErrorType_Aborted => "aborted",
42
+ Discord_ErrorType_AuthorizationFailed => "authorizationFailed",
43
+ Discord_ErrorType_RPCError => "rpcError",
44
+ _ => "unknown",
45
+ }
46
+ }
47
+
48
+ pub fn log_severity_name(severity: Discord_LoggingSeverity) -> &'static str {
49
+ match severity {
50
+ Discord_LoggingSeverity_Verbose => "verbose",
51
+ Discord_LoggingSeverity_Info => "info",
52
+ Discord_LoggingSeverity_Warning => "warning",
53
+ Discord_LoggingSeverity_Error => "error",
54
+ _ => "unknown",
55
+ }
56
+ }
57
+
58
+ pub fn parse_log_severity(cx: &mut Cx, name: &str) -> NeonResult<Discord_LoggingSeverity> {
59
+ match name {
60
+ "verbose" => Ok(Discord_LoggingSeverity_Verbose),
61
+ "info" => Ok(Discord_LoggingSeverity_Info),
62
+ "warning" => Ok(Discord_LoggingSeverity_Warning),
63
+ "error" => Ok(Discord_LoggingSeverity_Error),
64
+ _ => cx.throw_type_error(format!("Unknown log severity: {name}")),
65
+ }
66
+ }
67
+
68
+ pub fn parse_activity_type(cx: &mut Cx, name: &str) -> NeonResult<Discord_ActivityTypes> {
69
+ match name {
70
+ "playing" => Ok(Discord_ActivityTypes_Playing),
71
+ "streaming" => Ok(Discord_ActivityTypes_Streaming),
72
+ "listening" => Ok(Discord_ActivityTypes_Listening),
73
+ "watching" => Ok(Discord_ActivityTypes_Watching),
74
+ "competing" => Ok(Discord_ActivityTypes_Competing),
75
+ _ => cx.throw_type_error(format!("Unknown activity type: {name}")),
76
+ }
77
+ }
78
+
79
+ pub fn parse_status_display_type(
80
+ cx: &mut Cx,
81
+ name: &str,
82
+ ) -> NeonResult<Discord_StatusDisplayTypes> {
83
+ match name {
84
+ "name" => Ok(Discord_StatusDisplayTypes_Name),
85
+ "state" => Ok(Discord_StatusDisplayTypes_State),
86
+ "details" => Ok(Discord_StatusDisplayTypes_Details),
87
+ _ => cx.throw_type_error(format!("Unknown status display type: {name}")),
88
+ }
89
+ }
90
+
91
+ pub fn parse_platform(cx: &mut Cx, name: &str) -> NeonResult<Discord_ActivityGamePlatforms> {
92
+ match name {
93
+ "desktop" => Ok(Discord_ActivityGamePlatforms_Desktop),
94
+ "xbox" => Ok(Discord_ActivityGamePlatforms_Xbox),
95
+ "samsung" => Ok(Discord_ActivityGamePlatforms_Samsung),
96
+ "ios" => Ok(Discord_ActivityGamePlatforms_IOS),
97
+ "android" => Ok(Discord_ActivityGamePlatforms_Android),
98
+ "embedded" => Ok(Discord_ActivityGamePlatforms_Embedded),
99
+ "ps4" => Ok(Discord_ActivityGamePlatforms_PS4),
100
+ "ps5" => Ok(Discord_ActivityGamePlatforms_PS5),
101
+ _ => cx.throw_type_error(format!("Unknown platform: {name}")),
102
+ }
103
+ }
@@ -0,0 +1,364 @@
1
+ //! The parts of the Discord Social SDK's C API (`cdiscord.h`) this module uses, loaded from the SDK
2
+ //! DLL at runtime so the module builds without the SDK present.
3
+ //!
4
+ //! The declarations are written by hand against SDK 1.10. They must match `cdiscord.h` exactly:
5
+ //! check every signature here against the header when moving to a new SDK version. C enums are
6
+ //! declared as `i32` rather than Rust enums, since a newer SDK may pass values this module doesn't
7
+ //! know about.
8
+ #![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
9
+
10
+ use std::ffi::c_void;
11
+ use std::path::Path;
12
+ use std::ptr;
13
+
14
+ use libloading::Library;
15
+ use libloading::os::windows::{LOAD_WITH_ALTERED_SEARCH_PATH, Library as WindowsLibrary};
16
+
17
+ /// A string the SDK reads (when passed in) or allocates (when handed back). Strings the SDK hands
18
+ /// back must be released with `Discord_Free`.
19
+ #[repr(C)]
20
+ pub struct Discord_String {
21
+ pub ptr: *mut u8,
22
+ pub size: usize,
23
+ }
24
+
25
+ impl Discord_String {
26
+ /// Borrows `s` for the duration of a call. The SDK copies strings it keeps.
27
+ pub fn borrow(s: &str) -> Self {
28
+ Self {
29
+ ptr: s.as_ptr() as *mut u8,
30
+ size: s.len(),
31
+ }
32
+ }
33
+
34
+ pub fn empty() -> Self {
35
+ Self {
36
+ ptr: ptr::null_mut(),
37
+ size: 0,
38
+ }
39
+ }
40
+ }
41
+
42
+ macro_rules! handles {
43
+ ($($name:ident),* $(,)?) => {$(
44
+ /// An SDK object handle. Objects this module creates are wrapped in `Owned`.
45
+ #[repr(C)]
46
+ pub struct $name {
47
+ opaque: *mut c_void,
48
+ }
49
+
50
+ impl Default for $name {
51
+ fn default() -> Self {
52
+ Self { opaque: ptr::null_mut() }
53
+ }
54
+ }
55
+ )*};
56
+ }
57
+
58
+ handles!(
59
+ Discord_Client,
60
+ Discord_ClientResult,
61
+ Discord_Activity,
62
+ Discord_ActivityAssets,
63
+ Discord_ActivityTimestamps,
64
+ Discord_ActivityParty,
65
+ Discord_ActivitySecrets,
66
+ Discord_ActivityButton,
67
+ );
68
+
69
+ /// An SDK object this module created, dropped through the SDK when it goes out of scope.
70
+ ///
71
+ /// The handle is a pointer to SDK-owned memory, so moving it is fine.
72
+ pub struct Owned<T> {
73
+ raw: T,
74
+ drop: unsafe extern "C" fn(*mut T),
75
+ }
76
+
77
+ impl<T: Default> Owned<T> {
78
+ /// # Safety
79
+ ///
80
+ /// `init` and `drop` must be the SDK's init and drop functions for `T`.
81
+ pub unsafe fn new(
82
+ init: unsafe extern "C" fn(*mut T),
83
+ drop: unsafe extern "C" fn(*mut T),
84
+ ) -> Self {
85
+ let mut raw = T::default();
86
+ unsafe { init(&mut raw) };
87
+ Self { raw, drop }
88
+ }
89
+
90
+ /// # Safety
91
+ ///
92
+ /// `raw` must be an SDK object whose ownership the SDK handed to the caller, and `drop` the
93
+ /// SDK's drop function for `T`.
94
+ pub unsafe fn from_raw(raw: T, drop: unsafe extern "C" fn(*mut T)) -> Self {
95
+ Self { raw, drop }
96
+ }
97
+
98
+ pub fn as_ptr(&mut self) -> *mut T {
99
+ &mut self.raw
100
+ }
101
+ }
102
+
103
+ impl<T> Drop for Owned<T> {
104
+ fn drop(&mut self) {
105
+ unsafe { (self.drop)(&mut self.raw) }
106
+ }
107
+ }
108
+
109
+ pub type Discord_FreeFn = unsafe extern "C" fn(ptr: *mut c_void);
110
+
111
+ pub type Discord_ActivityPartyPrivacy = i32;
112
+ pub const Discord_ActivityPartyPrivacy_Private: i32 = 0;
113
+ pub const Discord_ActivityPartyPrivacy_Public: i32 = 1;
114
+
115
+ pub type Discord_ActivityTypes = i32;
116
+ pub const Discord_ActivityTypes_Playing: i32 = 0;
117
+ pub const Discord_ActivityTypes_Streaming: i32 = 1;
118
+ pub const Discord_ActivityTypes_Listening: i32 = 2;
119
+ pub const Discord_ActivityTypes_Watching: i32 = 3;
120
+ pub const Discord_ActivityTypes_Competing: i32 = 5;
121
+
122
+ pub type Discord_StatusDisplayTypes = i32;
123
+ pub const Discord_StatusDisplayTypes_Name: i32 = 0;
124
+ pub const Discord_StatusDisplayTypes_State: i32 = 1;
125
+ pub const Discord_StatusDisplayTypes_Details: i32 = 2;
126
+
127
+ /// A bit set of `Discord_ActivityGamePlatforms_*` values.
128
+ pub type Discord_ActivityGamePlatforms = i32;
129
+ pub const Discord_ActivityGamePlatforms_Desktop: i32 = 1;
130
+ pub const Discord_ActivityGamePlatforms_Xbox: i32 = 2;
131
+ pub const Discord_ActivityGamePlatforms_Samsung: i32 = 4;
132
+ pub const Discord_ActivityGamePlatforms_IOS: i32 = 8;
133
+ pub const Discord_ActivityGamePlatforms_Android: i32 = 16;
134
+ pub const Discord_ActivityGamePlatforms_Embedded: i32 = 32;
135
+ pub const Discord_ActivityGamePlatforms_PS4: i32 = 64;
136
+ pub const Discord_ActivityGamePlatforms_PS5: i32 = 128;
137
+
138
+ pub type Discord_ErrorType = i32;
139
+ pub const Discord_ErrorType_None: i32 = 0;
140
+ pub const Discord_ErrorType_NetworkError: i32 = 1;
141
+ pub const Discord_ErrorType_HTTPError: i32 = 2;
142
+ pub const Discord_ErrorType_ClientNotReady: i32 = 3;
143
+ pub const Discord_ErrorType_Disabled: i32 = 4;
144
+ pub const Discord_ErrorType_ClientDestroyed: i32 = 5;
145
+ pub const Discord_ErrorType_ValidationError: i32 = 6;
146
+ pub const Discord_ErrorType_Aborted: i32 = 7;
147
+ pub const Discord_ErrorType_AuthorizationFailed: i32 = 8;
148
+ pub const Discord_ErrorType_RPCError: i32 = 9;
149
+
150
+ pub type Discord_Client_Error = i32;
151
+ pub const Discord_Client_Error_None: i32 = 0;
152
+ pub const Discord_Client_Error_ConnectionFailed: i32 = 1;
153
+ pub const Discord_Client_Error_UnexpectedClose: i32 = 2;
154
+ pub const Discord_Client_Error_ConnectionCanceled: i32 = 3;
155
+
156
+ pub type Discord_Client_Status = i32;
157
+ pub const Discord_Client_Status_Disconnected: i32 = 0;
158
+ pub const Discord_Client_Status_Connecting: i32 = 1;
159
+ pub const Discord_Client_Status_Connected: i32 = 2;
160
+ pub const Discord_Client_Status_Ready: i32 = 3;
161
+ pub const Discord_Client_Status_Reconnecting: i32 = 4;
162
+ pub const Discord_Client_Status_Disconnecting: i32 = 5;
163
+ pub const Discord_Client_Status_HttpWait: i32 = 6;
164
+
165
+ pub type Discord_AuthorizationTokenType = i32;
166
+ pub const Discord_AuthorizationTokenType_Bearer: i32 = 1;
167
+
168
+ pub type Discord_LoggingSeverity = i32;
169
+ pub const Discord_LoggingSeverity_Verbose: i32 = 1;
170
+ pub const Discord_LoggingSeverity_Info: i32 = 2;
171
+ pub const Discord_LoggingSeverity_Warning: i32 = 3;
172
+ pub const Discord_LoggingSeverity_Error: i32 = 4;
173
+
174
+ // Callbacks that hand over a `Discord_ClientResult*` give ownership of it to the callee, which must
175
+ // drop it. Strings they hand over must be released with `Discord_Free`.
176
+ pub type Discord_Client_LogCallback = unsafe extern "C" fn(
177
+ message: Discord_String,
178
+ severity: Discord_LoggingSeverity,
179
+ user_data: *mut c_void,
180
+ );
181
+ pub type Discord_Client_OnStatusChanged = unsafe extern "C" fn(
182
+ status: Discord_Client_Status,
183
+ error: Discord_Client_Error,
184
+ error_detail: i32,
185
+ user_data: *mut c_void,
186
+ );
187
+ pub type Discord_Client_TokenExpirationCallback = unsafe extern "C" fn(user_data: *mut c_void);
188
+ pub type Discord_Client_ActivityJoinCallback =
189
+ unsafe extern "C" fn(join_secret: Discord_String, user_data: *mut c_void);
190
+ /// The shape shared by `Discord_Client_UpdateTokenCallback` and
191
+ /// `Discord_Client_UpdateRichPresenceCallback`.
192
+ pub type Discord_Client_ResultCallback =
193
+ unsafe extern "C" fn(result: *mut Discord_ClientResult, user_data: *mut c_void);
194
+
195
+ macro_rules! sdk_functions {
196
+ ($($name:ident: fn($($arg:ty),* $(,)?) $(-> $ret:ty)?;)*) => {
197
+ /// The loaded SDK DLL and the functions this module calls in it.
198
+ pub struct Sdk {
199
+ _library: Library,
200
+ $(pub $name: unsafe extern "C" fn($($arg),*) $(-> $ret)?,)*
201
+ }
202
+
203
+ impl Sdk {
204
+ /// Loads the SDK DLL at `path` and looks up every function this module uses, so a DLL
205
+ /// that lacks one fails here rather than on first use.
206
+ ///
207
+ /// # Safety
208
+ ///
209
+ /// Loading a DLL runs its initialization code. `path` must be a Discord Social SDK DLL
210
+ /// whose C API matches the declarations in this file.
211
+ pub unsafe fn load(path: &Path) -> Result<Self, libloading::Error> {
212
+ // LOAD_WITH_ALTERED_SEARCH_PATH resolves the DLL's own dependencies from its
213
+ // directory first, rather than from the directory of the executable.
214
+ let library: Library = unsafe {
215
+ WindowsLibrary::load_with_flags(path, LOAD_WITH_ALTERED_SEARCH_PATH)?
216
+ }
217
+ .into();
218
+ Ok(Self {
219
+ $($name: unsafe {
220
+ *library.get(concat!(stringify!($name), "\0").as_bytes())?
221
+ },)*
222
+ _library: library,
223
+ })
224
+ }
225
+ }
226
+ };
227
+ }
228
+
229
+ sdk_functions! {
230
+ Discord_Free: fn(*mut c_void);
231
+ Discord_RunCallbacks: fn();
232
+
233
+ Discord_ClientResult_Drop: fn(*mut Discord_ClientResult);
234
+ Discord_ClientResult_ToString: fn(*mut Discord_ClientResult, *mut Discord_String);
235
+ Discord_ClientResult_Type: fn(*mut Discord_ClientResult) -> Discord_ErrorType;
236
+ Discord_ClientResult_Error: fn(*mut Discord_ClientResult, *mut Discord_String);
237
+ Discord_ClientResult_ErrorCode: fn(*mut Discord_ClientResult) -> i32;
238
+ Discord_ClientResult_Successful: fn(*mut Discord_ClientResult) -> bool;
239
+ Discord_ClientResult_Retryable: fn(*mut Discord_ClientResult) -> bool;
240
+ Discord_ClientResult_RetryAfter: fn(*mut Discord_ClientResult) -> f32;
241
+
242
+ Discord_ActivityAssets_Init: fn(*mut Discord_ActivityAssets);
243
+ Discord_ActivityAssets_Drop: fn(*mut Discord_ActivityAssets);
244
+ Discord_ActivityAssets_SetLargeImage: fn(*mut Discord_ActivityAssets, *mut Discord_String);
245
+ Discord_ActivityAssets_SetLargeText: fn(*mut Discord_ActivityAssets, *mut Discord_String);
246
+ Discord_ActivityAssets_SetSmallImage: fn(*mut Discord_ActivityAssets, *mut Discord_String);
247
+ Discord_ActivityAssets_SetSmallText: fn(*mut Discord_ActivityAssets, *mut Discord_String);
248
+
249
+ Discord_ActivityTimestamps_Init: fn(*mut Discord_ActivityTimestamps);
250
+ Discord_ActivityTimestamps_Drop: fn(*mut Discord_ActivityTimestamps);
251
+ Discord_ActivityTimestamps_SetStart: fn(*mut Discord_ActivityTimestamps, u64);
252
+ Discord_ActivityTimestamps_SetEnd: fn(*mut Discord_ActivityTimestamps, u64);
253
+
254
+ Discord_ActivityParty_Init: fn(*mut Discord_ActivityParty);
255
+ Discord_ActivityParty_Drop: fn(*mut Discord_ActivityParty);
256
+ Discord_ActivityParty_SetId: fn(*mut Discord_ActivityParty, Discord_String);
257
+ Discord_ActivityParty_SetCurrentSize: fn(*mut Discord_ActivityParty, i32);
258
+ Discord_ActivityParty_SetMaxSize: fn(*mut Discord_ActivityParty, i32);
259
+ Discord_ActivityParty_SetPrivacy: fn(*mut Discord_ActivityParty, Discord_ActivityPartyPrivacy);
260
+
261
+ Discord_ActivitySecrets_Init: fn(*mut Discord_ActivitySecrets);
262
+ Discord_ActivitySecrets_Drop: fn(*mut Discord_ActivitySecrets);
263
+ Discord_ActivitySecrets_SetJoin: fn(*mut Discord_ActivitySecrets, Discord_String);
264
+
265
+ Discord_ActivityButton_Init: fn(*mut Discord_ActivityButton);
266
+ Discord_ActivityButton_Drop: fn(*mut Discord_ActivityButton);
267
+ Discord_ActivityButton_SetLabel: fn(*mut Discord_ActivityButton, Discord_String);
268
+ Discord_ActivityButton_SetUrl: fn(*mut Discord_ActivityButton, Discord_String);
269
+
270
+ Discord_Activity_Init: fn(*mut Discord_Activity);
271
+ Discord_Activity_Drop: fn(*mut Discord_Activity);
272
+ Discord_Activity_AddButton: fn(*mut Discord_Activity, *const Discord_ActivityButton);
273
+ Discord_Activity_SetType: fn(*mut Discord_Activity, Discord_ActivityTypes);
274
+ Discord_Activity_SetStatusDisplayType: fn(*mut Discord_Activity, *mut Discord_StatusDisplayTypes);
275
+ Discord_Activity_SetState: fn(*mut Discord_Activity, *mut Discord_String);
276
+ Discord_Activity_SetDetails: fn(*mut Discord_Activity, *mut Discord_String);
277
+ Discord_Activity_SetAssets: fn(*mut Discord_Activity, *mut Discord_ActivityAssets);
278
+ Discord_Activity_SetTimestamps: fn(*mut Discord_Activity, *mut Discord_ActivityTimestamps);
279
+ Discord_Activity_SetParty: fn(*mut Discord_Activity, *mut Discord_ActivityParty);
280
+ Discord_Activity_SetSecrets: fn(*mut Discord_Activity, *mut Discord_ActivitySecrets);
281
+ Discord_Activity_SetSupportedPlatforms: fn(*mut Discord_Activity, Discord_ActivityGamePlatforms);
282
+
283
+ Discord_Client_Init: fn(*mut Discord_Client);
284
+ Discord_Client_Drop: fn(*mut Discord_Client);
285
+ Discord_Client_GetVersionMajor: fn() -> i32;
286
+ Discord_Client_GetVersionMinor: fn() -> i32;
287
+ Discord_Client_GetVersionPatch: fn() -> i32;
288
+ Discord_Client_GetVersionHash: fn(*mut Discord_String);
289
+ Discord_Client_SetApplicationId: fn(*mut Discord_Client, u64);
290
+ Discord_Client_AddLogCallback: fn(
291
+ *mut Discord_Client,
292
+ Discord_Client_LogCallback,
293
+ Discord_FreeFn,
294
+ *mut c_void,
295
+ Discord_LoggingSeverity,
296
+ );
297
+ Discord_Client_SetStatusChangedCallback: fn(
298
+ *mut Discord_Client,
299
+ Discord_Client_OnStatusChanged,
300
+ Discord_FreeFn,
301
+ *mut c_void,
302
+ );
303
+ Discord_Client_SetTokenExpirationCallback: fn(
304
+ *mut Discord_Client,
305
+ Discord_Client_TokenExpirationCallback,
306
+ Discord_FreeFn,
307
+ *mut c_void,
308
+ );
309
+ Discord_Client_SetActivityJoinCallback: fn(
310
+ *mut Discord_Client,
311
+ Discord_Client_ActivityJoinCallback,
312
+ Discord_FreeFn,
313
+ *mut c_void,
314
+ );
315
+ Discord_Client_UpdateToken: fn(
316
+ *mut Discord_Client,
317
+ Discord_AuthorizationTokenType,
318
+ Discord_String,
319
+ Discord_Client_ResultCallback,
320
+ Discord_FreeFn,
321
+ *mut c_void,
322
+ );
323
+ Discord_Client_Connect: fn(*mut Discord_Client);
324
+ Discord_Client_Disconnect: fn(*mut Discord_Client);
325
+ Discord_Client_GetStatus: fn(*mut Discord_Client) -> Discord_Client_Status;
326
+ Discord_Client_UpdateRichPresence: fn(
327
+ *mut Discord_Client,
328
+ *mut Discord_Activity,
329
+ Discord_Client_ResultCallback,
330
+ Discord_FreeFn,
331
+ *mut c_void,
332
+ );
333
+ Discord_Client_ClearRichPresence: fn(*mut Discord_Client);
334
+ Discord_Client_RegisterLaunchCommand: fn(*mut Discord_Client, u64, Discord_String) -> bool;
335
+ }
336
+
337
+ impl Sdk {
338
+ /// Copies a string the SDK handed over and releases the SDK's copy.
339
+ ///
340
+ /// # Safety
341
+ ///
342
+ /// `s` must be a string the SDK allocated and handed to the caller, not yet released.
343
+ pub unsafe fn take_string(&self, s: Discord_String) -> String {
344
+ if s.ptr.is_null() {
345
+ return String::new();
346
+ }
347
+ let value = String::from_utf8_lossy(unsafe { std::slice::from_raw_parts(s.ptr, s.size) })
348
+ .into_owned();
349
+ unsafe { (self.Discord_Free)(s.ptr as *mut c_void) };
350
+ value
351
+ }
352
+
353
+ /// Calls an SDK function that writes a newly allocated string to an out-parameter, and returns
354
+ /// a copy of it.
355
+ ///
356
+ /// # Safety
357
+ ///
358
+ /// `f` must write a string the SDK allocated (or leave it empty).
359
+ pub unsafe fn get_string(&self, f: impl FnOnce(*mut Discord_String)) -> String {
360
+ let mut s = Discord_String::empty();
361
+ f(&mut s);
362
+ unsafe { self.take_string(s) }
363
+ }
364
+ }
package/package.json CHANGED
@@ -1,6 +1,37 @@
1
1
  {
2
2
  "name": "@shieldbattery/danimoth",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Rust-based Node.js native module wrapping the Discord Social SDK",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "scripts": {
8
+ "build": "cd native && cargo-cp-artifact -nc index.node -- cargo build --target=x86_64-pc-windows-msvc --message-format=json-render-diagnostics",
9
+ "build-debug": "pnpm run build",
10
+ "build-release": "pnpm run build --release",
11
+ "tag-prebuild": "node ./tag-prebuild.js",
12
+ "format": "prettier --write .",
13
+ "format:check": "prettier --check .",
14
+ "test": "cd native && cargo test && cd .. && pnpm run build && pnpm run tag-prebuild && node --test"
15
+ },
16
+ "license": "MIT",
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/ShieldBattery/danimoth.git"
23
+ },
24
+ "keywords": [
25
+ "discord",
26
+ "rich-presence"
27
+ ],
28
+ "bugs": {
29
+ "url": "https://github.com/ShieldBattery/danimoth/issues"
30
+ },
31
+ "homepage": "https://github.com/ShieldBattery/danimoth#readme",
32
+ "devDependencies": {
33
+ "cargo-cp-artifact": "^0.1.9",
34
+ "prettier": "^3.9.10"
35
+ },
36
+ "packageManager": "pnpm@12.14.0+sha512.c18ba6d87993d3d164cb5e8948f32b2c06ee854487e06cd8d86781342fb3e5bb4634367034711e86802baa9c37bea906ce1929ad08d70884c97d801df13389a6"
37
+ }
Binary file
@@ -0,0 +1,16 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+
4
+ const orig = path.join('.', 'native', 'index.node')
5
+ if (!fs.existsSync(orig)) {
6
+ throw new Error('there is no ./native/index.node built by Neon to mark as prebuild')
7
+ }
8
+
9
+ const prebuildDir = path.join('.', 'prebuilds')
10
+ fs.mkdirSync(prebuildDir, { recursive: true })
11
+ const dest = path.join(prebuildDir, 'x64.node')
12
+ fs.copyFile(orig, dest, err => {
13
+ if (err) {
14
+ throw err
15
+ }
16
+ })