1use std::{
2 ffi::{CStr, CString},
3 os::raw::c_char,
4 rc::Rc,
5};
6
7use bladeink::{choice::Choice, story::Story};
8
9use crate::{BINK_FAIL, BINK_FAIL_NULL_POINTER, BINK_OK};
10
11#[allow(clippy::not_unsafe_ptr_arg_deref)]
12#[no_mangle]
13pub extern "C" fn bink_story_new(
14 story: *mut *mut Story,
15 json_string: *const c_char,
16 err_msg: *mut *mut c_char,
17) -> u32 {
18 if story.is_null() || err_msg.is_null() {
19 return BINK_FAIL_NULL_POINTER;
20 }
21
22 unsafe {
23 *story = std::ptr::null_mut();
24 *err_msg = std::ptr::null_mut();
25 }
26
27 let c_str: &CStr = unsafe { CStr::from_ptr(json_string) };
28 let str_slice: &str = c_str.to_str().unwrap();
29
30 let result = Story::new(str_slice);
31
32 match result {
33 Ok(s) => unsafe {
34 *story = Box::into_raw(Box::new(s));
35 BINK_OK
36 },
37 Err(e) => unsafe {
38 *err_msg = CString::new(e.to_string()).unwrap().into_raw();
39 BINK_FAIL
40 },
41 }
42}
43
44#[allow(clippy::not_unsafe_ptr_arg_deref)]
45#[no_mangle]
46pub extern "C" fn bink_story_free(story: *mut Story) {
47 if !story.is_null() {
48 unsafe {
49 drop(Box::from_raw(story));
50 }
51 }
52}
53
54#[allow(clippy::not_unsafe_ptr_arg_deref)]
55#[no_mangle]
56pub extern "C" fn bink_story_can_continue(story: *mut Story, can_continue: *mut bool) -> u32 {
57 if story.is_null() {
58 return BINK_FAIL_NULL_POINTER;
59 }
60
61 let story: &mut Story = unsafe { &mut *story };
62
63 unsafe {
64 *can_continue = story.can_continue();
65 }
66
67 BINK_OK
68}
69
70#[allow(clippy::not_unsafe_ptr_arg_deref)]
71#[no_mangle]
72pub extern "C" fn bink_story_cont(
73 story: *mut Story,
74 line: *mut *mut c_char,
75 err_msg: *mut *mut c_char,
76) -> u32 {
77 if story.is_null() {
78 return BINK_FAIL_NULL_POINTER;
79 }
80
81 let story: &mut Story = unsafe { &mut *story };
82
83 let result = story.cont();
84
85 match result {
86 Ok(l) => unsafe {
87 *line = CString::new(l).unwrap().into_raw();
88 BINK_OK
89 },
90 Err(e) => unsafe {
91 *err_msg = CString::new(e.to_string()).unwrap().into_raw();
92 BINK_FAIL
93 },
94 }
95}
96
97#[allow(clippy::not_unsafe_ptr_arg_deref)]
98#[no_mangle]
99pub extern "C" fn bink_story_get_current_choices(
100 story: *mut Story,
101 choices: *mut *mut Vec<Rc<Choice>>,
102 len: *mut usize,
103) -> u32 {
104 if story.is_null() {
105 return BINK_FAIL_NULL_POINTER;
106 }
107
108 let story: &mut Story = unsafe { &mut *story };
109
110 let result = Box::new(story.get_current_choices());
111
112 unsafe {
113 *len = result.len();
114 *choices = Box::into_raw(result);
115 }
116
117 BINK_OK
118}
119
120#[allow(clippy::not_unsafe_ptr_arg_deref)]
121#[no_mangle]
122pub extern "C" fn bink_story_choose_choice_index(story: *mut Story, choice_index: usize) -> u32 {
123 if story.is_null() {
124 return BINK_FAIL_NULL_POINTER;
125 }
126
127 let story: &mut Story = unsafe { &mut *story };
128
129 let result = story.choose_choice_index(choice_index);
130
131 match result {
132 Ok(_) => BINK_OK,
133 Err(_) => BINK_FAIL,
134 }
135}
136
137#[allow(clippy::not_unsafe_ptr_arg_deref)]
138#[no_mangle]
139pub extern "C" fn bink_story_get_current_tags(
140 story: *mut Story,
141 tags: *mut *mut Vec<String>,
142 len: *mut usize,
143) -> u32 {
144 if story.is_null() {
145 return BINK_FAIL_NULL_POINTER;
146 }
147
148 let story: &mut Story = unsafe { &mut *story };
149
150 let result = story.get_current_tags();
151
152 match result {
153 Ok(result) => unsafe {
154 *len = result.len();
155 *tags = Box::into_raw(Box::new(result));
156 },
157 Err(_) => return BINK_FAIL,
158 }
159
160 BINK_OK
161}