diff --git a/rust-ffi-demo/demo.c b/rust-ffi-demo/demo.c index 9e7de27..0526cab 100644 --- a/rust-ffi-demo/demo.c +++ b/rust-ffi-demo/demo.c @@ -35,6 +35,12 @@ int main() { storybook_advance_nooption(book); break; case (FOOTER_CHOICES): + int n = storybook_get_num_choices(book); + for (int i = 1; i <= n; i++) { + Choice* choice = storybook_get_choice(book, i); + printf("%d) %s\n", choice->option, choice->flavor); + storybook_free_choice(choice); + } uint32_t option; printf("Make a choice: "); scanf("%d", &option); diff --git a/src/rust-base/src/lib.rs b/src/rust-base/src/lib.rs index 9b0c184..90be838 100644 --- a/src/rust-base/src/lib.rs +++ b/src/rust-base/src/lib.rs @@ -13,12 +13,12 @@ pub struct Page { pub enum Footer { Ending, Goto(String), - Choices(HashMap), + Choices(HashMap), } #[derive(Debug, PartialEq)] pub struct Choice { - option: u32, + option: usize, flavor: String, redirect: String, stat_check: Option, @@ -130,7 +130,7 @@ impl Book { Footer::Choices(_) => panic!("No option for advance on choices page!"), } } - pub fn advance_option(&mut self, option: u32) { + pub fn advance_option(&mut self, option: usize) { let footer = &self.get_current().footer; match footer { Footer::Ending => panic!("Option provided for advance on ending page!"), @@ -181,6 +181,34 @@ pub mod ffi { Choices, } + #[repr(C)] + pub struct Choice { + option: usize, + flavor: *const c_char, + } + + #[repr(C)] + pub struct StatCheck { + stat: *const c_char, + value: i32, + rel: c_char, + } + + #[repr(C)] + pub struct StatChange { + stat: *const c_char, + addend: i32, + } + + impl Choice { + pub fn new(choice: &super::Choice) -> Self { + Choice { + option: choice.option, + flavor: CString::new(choice.flavor.clone()).unwrap().into_raw(), + } + } + } + #[no_mangle] pub extern fn storybook_make_book(string: *const c_char) -> *mut Book { let string = unsafe { @@ -245,10 +273,42 @@ pub mod ffi { } #[no_mangle] - pub extern fn storybook_advance_option(book: *mut Book, option: u32) { + pub extern fn storybook_advance_option(book: *mut Book, option: usize) { let book = get_book_from_ref(book); book.advance_option(option); } + + #[no_mangle] + pub extern fn storybook_get_num_choices(book: *mut Book) -> usize { + let book = get_book_from_ref(book); + let footer = &book.get_current().footer; + if let super::Footer::Choices(choices) = footer { + choices.len() + } else { + panic!("Requested num choices but page is not choices."); + } + } + + #[no_mangle] + pub extern fn storybook_get_choice(book: *mut Book, n: usize) -> *mut Choice { + let book = get_book_from_ref(book); + let footer = &book.get_current().footer; + if let super::Footer::Choices(choices) = footer { + let choice = choices.get(&n).expect("Requested option isn't present in choices."); + let choice = Choice::new(choice); + let choice = Box::from(choice); + Box::into_raw(choice) + } else { + panic!("Requested a choice but page is not choices."); + } + } + + #[no_mangle] + pub extern fn storybook_free_choice(choice: *mut Choice) { + unsafe { + Box::from_raw(choice); + } + } } #[cfg(test)]