Skip to content

Commit 70bf1c6

Browse files
committed
feat: make DialogFileBrowserOptions::new() use native initialization function
1 parent 4d6b318 commit 70bf1c6

File tree

3 files changed

+36
-17
lines changed

3 files changed

+36
-17
lines changed

crates/flipperzero/examples/storage.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use flipperzero::io::*;
1818
use flipperzero::println;
1919
use flipperzero::storage::*;
2020
use flipperzero_rt::{entry, manifest};
21+
use flipperzero_sys::c_str;
2122

2223
manifest!(name = "Rust storage example");
2324
entry!(main);
@@ -41,7 +42,9 @@ fn main(_args: *mut u8) -> i32 {
4142

4243
// Next, we'll open a file browser dialog and let the user select the file.
4344
let mut dialogs_app = DialogsApp::open();
44-
let file_browser_options = DialogFileBrowserOptions::new().set_hide_ext(false);
45+
46+
static EXTENSION: &CStr = c_str!("*");
47+
let file_browser_options = DialogFileBrowserOptions::new(EXTENSION).set_hide_ext(false);
4548
let mut start_path = FuriString::from(path);
4649
let result_path =
4750
dialogs_app.show_file_browser(Some(&mut start_path), Some(&file_browser_options));

crates/flipperzero/src/dialogs/mod.rs

+18-14
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use alloc::ffi::CString;
55

66
use core::ffi::{c_char, c_void, CStr};
77
use core::marker::PhantomData;
8+
use core::mem::MaybeUninit;
89
use core::ptr::{self, NonNull};
9-
1010
use flipperzero_sys as sys;
11-
use sys::{c_string, furi::UnsafeRecord};
11+
use sys::furi::UnsafeRecord;
1212

1313
use crate::furi::string::FuriString;
1414
use crate::gui::canvas::Align;
@@ -25,6 +25,7 @@ pub struct DialogMessage<'a> {
2525
}
2626

2727
/// A dialog file browser options.
28+
#[repr(transparent)]
2829
pub struct DialogFileBrowserOptions<'a> {
2930
data: sys::DialogsFileBrowserOptions,
3031
_phantom: PhantomData<&'a ()>,
@@ -202,19 +203,22 @@ impl DialogMessageButton {
202203

203204
impl<'a> DialogFileBrowserOptions<'a> {
204205
/// Creates a new dialog file browser options and initializes to default values.
205-
pub fn new() -> Self {
206+
pub fn new<'e: 'a>(extension: &'e CStr) -> Self {
207+
let mut options = MaybeUninit::<sys::DialogsFileBrowserOptions>::uninit();
208+
let uninit_options = options.as_mut_ptr();
209+
let extension = extension.as_ptr();
210+
// TODO: as for now, we stick to default (NULL) icon,
211+
// although we may want to make it customizable via this function's parameter
212+
// once there are safe Icon-related APIs
213+
let icon = ptr::null();
214+
// SAFETY: all pointers are valid (`icon` is allowed to be NULL)
215+
// and options is intentionally uninitialized
216+
// since it is the called function's job to do it
217+
unsafe { sys::dialog_file_browser_set_basic_options(uninit_options, extension, icon) };
206218
Self {
207-
// default values from sys::dialog_file_browser_set_basic_options()
208-
data: sys::DialogsFileBrowserOptions {
209-
extension: c_string!("*"),
210-
base_path: ptr::null(),
211-
skip_assets: true,
212-
hide_dot_files: false,
213-
icon: ptr::null(),
214-
hide_ext: true,
215-
item_loader_callback: None,
216-
item_loader_context: ptr::null_mut(),
217-
},
219+
// SAFETY: data has just been initialized fully
220+
// as guaranteed by the previously called function's contract
221+
data: unsafe { options.assume_init() },
218222
_phantom: PhantomData,
219223
}
220224
}

crates/sys/src/lib.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,24 @@ mod inlines;
2929
)]
3030
mod bindings;
3131

32-
/// Create a static C string.
32+
/// Create a static C string of type [`*const c_char`][core::ffi::c_char].
3333
/// Will automatically add a NUL terminator.
3434
#[macro_export]
3535
macro_rules! c_string {
3636
($str:expr $(,)?) => {{
37-
concat!($str, "\0").as_ptr() as *const core::ffi::c_char
37+
::core::concat!($str, "\0").as_ptr() as *const ::core::ffi::c_char
38+
}};
39+
}
40+
41+
/// Create a static C string of type [`&CStr`][`core::ffi::CStr`].
42+
/// Will automatically add a NUL terminator.
43+
#[macro_export]
44+
macro_rules! c_str {
45+
($str:expr $(,)?) => {{
46+
match ::core::ffi::CStr::from_bytes_with_nul(::core::concat!($str, "\0").as_bytes()) {
47+
Ok(c_str) => c_str,
48+
Err(error) => panic!("invalid C-string literal"),
49+
}
3850
}};
3951
}
4052

0 commit comments

Comments
 (0)