1pub(crate) mod bindings {
8 #![allow(non_upper_case_globals)]
9 #![allow(non_camel_case_types)]
10 #![allow(non_snake_case)]
11 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
12}
13
14#[cfg(test)]
15mod test;
16
17extern crate asar_snes_proc_macros;
18pub use asar_snes_proc_macros::use_asar_global_lock;
19
20use core::fmt;
21#[cfg(feature = "thread-safe")]
22use parking_lot::ReentrantMutex;
23#[cfg(feature = "thread-safe")]
24use std::sync::OnceLock;
25
26use std::{
27 ffi::{CStr, CString},
28 os::raw::{c_char, c_int, c_void},
29 ptr,
30};
31
32use crate::bindings::{
33 asar_apiversion, asar_getalldefines, asar_getalllabels, asar_getdefine, asar_geterrors,
34 asar_getlabelval, asar_getmapper, asar_getprints, asar_getsymbolsfile, asar_getwarnings,
35 asar_getwrittenblocks, asar_math, asar_maxromsize, asar_patch, asar_patch_ex, asar_reset,
36 asar_resolvedefines, asar_version, definedata, errordata, labeldata, mappertype, memoryfile,
37 patchparams, warnsetting, writtenblockdata,
38};
39
40#[cfg(feature = "thread-safe")]
41fn global_asar_lock() -> &'static ReentrantMutex<()> {
42 static LOCK: OnceLock<ReentrantMutex<()>> = OnceLock::new();
43 LOCK.get_or_init(|| ReentrantMutex::new(()))
44}
45
46#[cfg(not(feature = "thread-safe"))]
47fn global_asar_lock() -> &'static FakeLock {
48 &FakeLock
49}
50
51#[cfg(not(feature = "thread-safe"))]
52struct FakeLock;
53
54#[cfg(not(feature = "thread-safe"))]
55impl FakeLock {
56 fn lock(&self) -> FakeLock {
57 FakeLock
58 }
59}
60
61pub fn with_asar_lock<F, R>(f: F) -> R
92where
93 F: FnOnce() -> R,
94{
95 let _lock = global_asar_lock().lock();
96 f()
97}
98
99#[derive(Debug, Clone, Default)]
107pub struct RomData {
108 pub data: Vec<u8>,
109 pub length: usize,
110}
111
112#[derive(Debug, Clone)]
114pub struct ErrorData {
115 pub fullerrdata: String,
116 pub rawerrdata: String,
117 pub block: String,
118 pub filename: String,
119 pub line: i32,
120 pub callerfilename: String,
121 pub callerline: i32,
122 pub errid: i32,
123}
124
125pub type WarningData = ErrorData;
127
128#[derive(Debug, Clone)]
130pub struct Define {
131 pub name: String,
132 pub contents: String,
133}
134
135#[derive(Debug, Clone)]
138pub struct WrittenBlock {
139 pub pcoffset: i32,
140 pub snesoffset: i32,
141 pub numbytes: i32,
142}
143
144#[derive(Debug, Clone)]
147pub struct Label {
148 pub name: String,
149 pub location: i32,
150}
151
152#[derive(Debug, Clone)]
154pub struct BasicPatchOptions {
155 romdata: RomData,
156 patchloc: String,
157}
158
159#[derive(Debug, Clone)]
161pub struct WarnSetting {
162 pub warnid: String,
163 pub enabled: bool,
164}
165
166#[derive(Debug, Clone)]
168pub enum MemoryFileData {
169 Binary(Vec<u8>),
170 Text(String),
171}
172
173impl From<Vec<u8>> for MemoryFileData {
174 fn from(data: Vec<u8>) -> Self {
175 MemoryFileData::Binary(data)
176 }
177}
178
179impl From<String> for MemoryFileData {
180 fn from(data: String) -> Self {
181 MemoryFileData::Text(data)
182 }
183}
184
185impl From<&str> for MemoryFileData {
186 fn from(data: &str) -> Self {
187 MemoryFileData::Text(data.into())
188 }
189}
190
191#[derive(Debug, Clone)]
193pub struct MemoryFile {
194 pub filename: String,
195 pub data: MemoryFileData,
196}
197
198#[derive(Debug, Clone)]
203pub struct AdvancedPatchOptions {
204 includepaths: Vec<String>,
205 should_reset: bool,
206 additional_defines: Vec<Define>,
207 stdincludesfile: Option<String>,
208 stddefinesfile: Option<String>,
209 warning_settings: Vec<WarnSetting>,
210 memory_files: Vec<MemoryFile>,
211 override_checksum_gen: bool,
212 generate_checksum: bool,
213}
214
215pub type MapperType = mappertype;
216
217#[derive(Debug, Clone)]
218pub enum SymbolType {
219 WLA,
220 NoCash,
221}
222
223#[derive(Debug, Clone)]
224pub enum PatchResult {
225 Success(RomData, Vec<WarningData>),
226 Failure(Vec<ErrorData>),
227}
228
229#[derive(Debug, Clone)]
231pub enum PatchOption {
232 Include(String),
234 Define(String, String),
236 Warning(String, bool),
238 MemoryFile(String, MemoryFileData),
240 StdIncludesFile(String),
242 StdDefinesFile(String),
244 OverrideChecksumGen(bool),
246 GenerateChecksum(bool),
248 ShouldReset(bool),
250}
251
252impl RomData {
253 pub fn from_vec(data: Vec<u8>) -> RomData {
255 let length = data.len();
256 RomData { data, length }
257 }
258
259 pub fn new(data: Vec<u8>, length: usize) -> RomData {
261 RomData { data, length }
262 }
263}
264
265impl From<Vec<u8>> for RomData {
266 fn from(data: Vec<u8>) -> Self {
267 RomData::from_vec(data)
268 }
269}
270
271impl MemoryFile {
272 fn as_raw(&self) -> memoryfile {
273 let filename = CString::new(self.filename.clone()).unwrap();
274 let data = match &self.data {
275 MemoryFileData::Binary(d) => d.as_ptr() as *mut c_void,
276 MemoryFileData::Text(d) => d.as_ptr() as *mut c_void,
277 };
278 let size = match &self.data {
279 MemoryFileData::Binary(d) => d.len(),
280 MemoryFileData::Text(d) => d.len(),
281 };
282 memoryfile {
283 path: filename.into_raw(),
284 buffer: data,
285 length: size,
286 }
287 }
288}
289
290impl WarnSetting {
291 fn as_raw(&self) -> warnsetting {
292 let warnid = CString::new(self.warnid.clone()).unwrap();
293 warnsetting {
294 warnid: warnid.into_raw(),
295 enabled: self.enabled,
296 }
297 }
298}
299
300impl ErrorData {
301 fn from_raw(raw: &errordata) -> ErrorData {
302 ErrorData {
303 fullerrdata: unsafe { CStr::from_ptr(raw.fullerrdata) }
304 .to_string_lossy()
305 .into_owned(),
306 rawerrdata: unsafe { CStr::from_ptr(raw.rawerrdata) }
307 .to_string_lossy()
308 .into_owned(),
309 block: unsafe { CStr::from_ptr(raw.block) }
310 .to_string_lossy()
311 .into_owned(),
312 filename: if raw.filename.is_null() {
313 "".into()
314 } else {
315 unsafe { CStr::from_ptr(raw.filename) }
316 .to_string_lossy()
317 .into_owned()
318 },
319 line: raw.line,
320 callerfilename: if raw.callerfilename.is_null() {
321 "".into()
322 } else {
323 unsafe { CStr::from_ptr(raw.callerfilename) }
324 .to_string_lossy()
325 .into_owned()
326 },
327 callerline: raw.callerline,
328 errid: raw.errid,
329 }
330 }
331}
332
333impl Define {
334 fn from_raw(raw: &definedata) -> Define {
335 Define {
336 name: unsafe { CStr::from_ptr(raw.name) }
337 .to_string_lossy()
338 .into_owned(),
339 contents: unsafe { CStr::from_ptr(raw.contents) }
340 .to_string_lossy()
341 .into_owned(),
342 }
343 }
344 fn as_raw(&self) -> definedata {
345 let name = std::ffi::CString::new(self.name.clone()).unwrap();
346 let contents = std::ffi::CString::new(self.contents.clone()).unwrap();
347 definedata {
348 name: name.into_raw(),
349 contents: contents.into_raw(),
350 }
351 }
352}
353
354impl WrittenBlock {
355 fn from_raw(raw: &writtenblockdata) -> WrittenBlock {
356 WrittenBlock {
357 pcoffset: raw.pcoffset,
358 snesoffset: raw.snesoffset,
359 numbytes: raw.numbytes,
360 }
361 }
362}
363
364impl Label {
365 fn from_raw(raw: &labeldata) -> Label {
366 Label {
367 name: unsafe { CStr::from_ptr(raw.name) }
368 .to_string_lossy()
369 .into_owned(),
370 location: raw.location,
371 }
372 }
373}
374
375impl BasicPatchOptions {
376 pub fn new(romdata: RomData, patchloc: String) -> BasicPatchOptions {
378 BasicPatchOptions { romdata, patchloc }
379 }
380}
381
382impl AdvancedPatchOptions {
383 pub fn new() -> AdvancedPatchOptions {
385 AdvancedPatchOptions {
386 includepaths: Vec::new(),
387 should_reset: true,
388 additional_defines: Vec::new(),
389 stdincludesfile: None,
390 stddefinesfile: None,
391 warning_settings: Vec::new(),
392 memory_files: Vec::new(),
393 override_checksum_gen: false,
394 generate_checksum: false,
395 }
396 }
397
398 pub fn from(options: Vec<PatchOption>) -> AdvancedPatchOptions {
400 AdvancedPatchOptions::new().options(options)
401 }
402
403 pub fn option(mut self, option: PatchOption) -> AdvancedPatchOptions {
405 match option {
406 PatchOption::Include(path) => self.includepaths.push(path),
407 PatchOption::Define(name, contents) => {
408 self.additional_defines.push(Define { name, contents })
409 }
410 PatchOption::Warning(warnid, enabled) => {
411 self.warning_settings.push(WarnSetting { warnid, enabled })
412 }
413 PatchOption::MemoryFile(filename, data) => {
414 self.memory_files.push(MemoryFile { filename, data })
415 }
416 PatchOption::StdIncludesFile(filename) => self.stdincludesfile = Some(filename),
417 PatchOption::StdDefinesFile(filename) => self.stddefinesfile = Some(filename),
418 PatchOption::OverrideChecksumGen(override_checksum_gen) => {
419 self.override_checksum_gen = override_checksum_gen
420 }
421 PatchOption::GenerateChecksum(generate_checksum) => {
422 self.generate_checksum = generate_checksum
423 }
424 PatchOption::ShouldReset(should_reset) => self.should_reset = should_reset,
425 };
426 self
427 }
428
429 pub fn options(mut self, options: Vec<PatchOption>) -> AdvancedPatchOptions {
431 for option in options {
432 self = self.option(option);
433 }
434 self
435 }
436}
437
438impl Default for AdvancedPatchOptions {
439 fn default() -> Self {
440 Self::new()
441 }
442}
443
444pub fn max_rom_size() -> i32 {
448 unsafe { asar_maxromsize() }
449}
450
451pub fn api_version() -> i32 {
453 unsafe { asar_apiversion() }
454}
455
456pub fn version() -> i32 {
458 unsafe { asar_version() }
459}
460
461pub fn math(math: &str) -> Result<f64, String> {
465 let math = CString::new(math).unwrap();
466 let mut err: *const i8 = std::ptr::null();
467 let result = unsafe { asar_math(math.as_ptr(), &mut err) };
468 if err.is_null() {
469 Ok(result)
470 } else {
471 Err(unsafe { CStr::from_ptr(err) }
472 .to_string_lossy()
473 .into_owned())
474 }
475}
476
477pub mod patching {
506
507 use super::*;
508
509 #[use_asar_global_lock]
519 pub fn reset() -> bool {
520 unsafe { asar_reset() }
521 }
522
523 #[use_asar_global_lock]
529 pub fn patch(mut options: BasicPatchOptions) -> PatchResult {
530 let romdata = options.romdata.data.as_mut_ptr() as *mut c_char;
531 let buflen = options.romdata.data.len() as c_int;
532 let patchloc = CString::new(options.patchloc).unwrap();
533 let mut romsize = options.romdata.length as c_int;
534 let romlen: *mut c_int = &mut romsize;
535 let result = unsafe { asar_patch(patchloc.as_ptr(), romdata, buflen, romlen) };
536 let mut count: c_int = 0;
537 let warnings = unsafe { asar_getwarnings(&mut count) };
538 let warnings = unsafe { std::slice::from_raw_parts(warnings, count as usize) };
539 let warnings = warnings.iter().map(ErrorData::from_raw).collect();
540 if result {
541 options.romdata.length = romsize as usize;
542 PatchResult::Success(options.romdata, warnings)
543 } else {
544 let mut count: c_int = 0;
545 let errors = unsafe { asar_geterrors(&mut count) };
546 let errors = unsafe { std::slice::from_raw_parts(errors, count as usize) };
547 let errors = errors.iter().map(ErrorData::from_raw).collect();
548 PatchResult::Failure(errors)
549 }
550 }
551
552 #[use_asar_global_lock]
553 pub(crate) fn patch_ex_basic(
554 mut rom: RomData,
555 patch: String,
556 options: AdvancedPatchOptions,
557 ) -> (RomData, bool) {
558 let romdata = rom.data.as_mut_ptr() as *mut c_char;
559 let buflen = rom.data.len() as c_int;
560 let patchloc = CString::new(patch).unwrap();
561 let mut romsize = rom.length as c_int;
562 let romlen: *mut c_int = &mut romsize;
563
564 let mut definedata = options
565 .additional_defines
566 .iter()
567 .map(Define::as_raw)
568 .collect::<Vec<definedata>>();
569 let mut warning_settings = options
570 .warning_settings
571 .iter()
572 .map(WarnSetting::as_raw)
573 .collect::<Vec<warnsetting>>();
574 let mut memory_files = options
575 .memory_files
576 .iter()
577 .map(MemoryFile::as_raw)
578 .collect::<Vec<memoryfile>>();
579 let mut includepaths = options
580 .includepaths
581 .iter()
582 .map(|p| CString::new(p.clone()).unwrap().into_raw() as *const i8)
583 .collect::<Vec<_>>();
584
585 let stdincludesfile = options.stdincludesfile.map(|s| CString::new(s).unwrap());
586 let stddefinesfile = options.stddefinesfile.map(|s| CString::new(s).unwrap());
587
588 let params = patchparams {
589 structsize: std::mem::size_of::<patchparams>() as c_int,
590 buflen,
591 patchloc: patchloc.as_ptr(),
592 romdata,
593 romlen,
594 includepaths: includepaths.as_mut_ptr(),
595 numincludepaths: includepaths.len() as c_int,
596 should_reset: options.should_reset,
597 additional_defines: definedata.as_mut_ptr(),
598 additional_define_count: definedata.len() as c_int,
599 stdincludesfile: stdincludesfile.map_or(ptr::null(), |s| s.as_ptr()),
600 stddefinesfile: stddefinesfile.map_or(ptr::null(), |s| s.as_ptr()),
601 warning_settings: warning_settings.as_mut_ptr(),
602 warning_setting_count: warning_settings.len() as c_int,
603 memory_files: memory_files.as_mut_ptr(),
604 memory_file_count: memory_files.len() as c_int,
605 override_checksum_gen: options.override_checksum_gen,
606 generate_checksum: options.generate_checksum,
607 };
608 let result = unsafe { asar_patch_ex(¶ms) };
609
610 for define in definedata {
611 unsafe {
612 drop(CString::from_raw(define.name as *mut i8));
613 drop(CString::from_raw(define.contents as *mut i8));
614 }
615 }
616
617 for path in includepaths {
618 unsafe {
619 drop(CString::from_raw(path as *mut i8));
620 }
621 }
622
623 rom.length = romsize as usize;
624
625 (rom, result)
626 }
627
628 #[use_asar_global_lock]
634 pub fn patch_ex<T: Into<String>>(rom: RomData, patch: T, options: AdvancedPatchOptions) -> PatchResult {
635 let (romdata, result) = patch_ex_basic(rom, patch.into(), options);
636
637 let mut count: c_int = 0;
638 let warnings = unsafe { asar_getwarnings(&mut count) };
639 let warnings = unsafe { std::slice::from_raw_parts(warnings, count as usize) };
640 let warnings = warnings.iter().map(ErrorData::from_raw).collect();
641
642 if result {
643 PatchResult::Success(romdata, warnings)
644 } else {
645 let mut count: c_int = 0;
646 let errors = unsafe { asar_geterrors(&mut count) };
647 let errors = unsafe { std::slice::from_raw_parts(errors, count as usize) };
648 let errors = errors.iter().map(ErrorData::from_raw).collect();
649 PatchResult::Failure(errors)
650 }
651 }
652
653 #[use_asar_global_lock]
657 pub fn errors() -> Vec<ErrorData> {
658 let mut count: c_int = 0;
659 let errors = unsafe { asar_geterrors(&mut count) };
660 let errors = unsafe { std::slice::from_raw_parts(errors, count as usize) };
661 errors.iter().map(ErrorData::from_raw).collect()
662 }
663
664 #[use_asar_global_lock]
668 pub fn warnings() -> Vec<ErrorData> {
669 let mut count: c_int = 0;
670 let errors = unsafe { asar_getwarnings(&mut count) };
671 let errors = unsafe { std::slice::from_raw_parts(errors, count as usize) };
672 errors.iter().map(ErrorData::from_raw).collect()
673 }
674
675 #[use_asar_global_lock]
679 pub fn prints() -> Vec<String> {
680 let mut count: c_int = 0;
681 let prints = unsafe { asar_getprints(&mut count) };
682 let prints = unsafe { std::slice::from_raw_parts(prints, count as usize) };
683 prints
684 .iter()
685 .map(|p| unsafe { CStr::from_ptr(*p) }.to_string_lossy().into_owned())
686 .collect()
687 }
688
689 #[use_asar_global_lock]
693 pub fn labels() -> Vec<Label> {
694 let mut count: c_int = 0;
695 let labels = unsafe { asar_getalllabels(&mut count) };
696 let labels = unsafe { std::slice::from_raw_parts(labels, count as usize) };
697 labels.iter().map(Label::from_raw).collect()
698 }
699
700 #[use_asar_global_lock]
706 pub fn label_value(name: &str) -> Option<i32> {
707 let name = CString::new(name).unwrap();
708 let value = unsafe { asar_getlabelval(name.as_ptr()) };
709 if value == -1 {
710 None
711 } else {
712 Some(value)
713 }
714 }
715
716 #[use_asar_global_lock]
720 pub fn define(name: &str) -> Option<String> {
721 let name = CString::new(name).unwrap();
722 let def = unsafe { asar_getdefine(name.as_ptr()) };
723 if def.is_null() {
724 None
725 } else {
726 Some(
727 unsafe { CStr::from_ptr(def) }
728 .to_string_lossy()
729 .into_owned(),
730 )
731 }
732 }
733
734 #[use_asar_global_lock]
738 pub fn defines() -> Vec<Define> {
739 let mut count: c_int = 0;
740 let defines = unsafe { asar_getalldefines(&mut count) };
741 let defines = unsafe { std::slice::from_raw_parts(defines, count as usize) };
742 defines.iter().map(Define::from_raw).collect()
743 }
744
745 #[use_asar_global_lock]
751 pub fn resolve_defines(data: &str) -> String {
752 unsafe {
753 let data = CString::new(data).unwrap();
754 let resolved = asar_resolvedefines(data.as_ptr(), false);
755 CStr::from_ptr(resolved).to_string_lossy().into_owned()
756 }
757 }
758
759 #[use_asar_global_lock]
763 pub fn written_blocks() -> Vec<WrittenBlock> {
764 let mut count: c_int = 0;
765 let blocks = unsafe { asar_getwrittenblocks(&mut count) };
766 let blocks = unsafe { std::slice::from_raw_parts(blocks, count as usize) };
767 blocks.iter().map(WrittenBlock::from_raw).collect()
768 }
769
770 #[use_asar_global_lock]
776 pub fn mapper_type() -> Option<MapperType> {
777 let raw = unsafe { asar_getmapper() };
778 match raw {
779 MapperType::invalid_mapper => None,
780 _ => Some(raw),
781 }
782 }
783
784 #[use_asar_global_lock]
790 pub fn symbols_file(symboltype: SymbolType) -> Option<String> {
791 let symboltype = match symboltype {
792 SymbolType::WLA => "wla",
793 SymbolType::NoCash => "nocash",
794 };
795 let symboltype = CString::new(symboltype).unwrap();
796 unsafe {
797 let file = asar_getsymbolsfile(symboltype.as_ptr());
798 if file.is_null() {
799 None
800 } else {
801 Some(CStr::from_ptr(file).to_string_lossy().into_owned())
802 }
803 }
804 }
805}
806#[cfg(feature = "thread-safe")]
807use parking_lot::ReentrantMutexGuard;
808
809#[derive(Debug, Clone)]
815pub struct Patcher {
816 options: Option<AdvancedPatchOptions>,
817}
818
819#[cfg(feature = "thread-safe")]
847pub struct ApplyResult<'a> {
848 romdata: RomData,
849 success: bool,
850 _guard: ReentrantMutexGuard<'a, ()>,
851}
852
853#[cfg(not(feature = "thread-safe"))]
859pub struct ApplyResult<'a> {
860 romdata: RomData,
861 success: bool,
862 _marker: std::marker::PhantomData<&'a ()>,
863}
864
865use std::sync::atomic::{AtomicBool, Ordering};
866
867static APPLYRESULT_ONCE_ALIVE: AtomicBool = AtomicBool::new(false);
868
869#[derive(Debug, Clone)]
873pub struct ConcurrentApplyError;
874
875impl fmt::Display for ConcurrentApplyError {
876 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
877 write!(f, "Cannot call `Patcher::apply` while another `ApplyResult` is alive, drop() it or consume it by calling `ApplyResult::romdata()`.")
878 }
879}
880
881impl Patcher {
882 pub fn new() -> Self {
884 Self { options: None }
885 }
886 pub fn option(&mut self, option: PatchOption) {
888 self.options = Some(self.options.take().unwrap_or_default().option(option));
889 }
890 pub fn options(&mut self, options: AdvancedPatchOptions) {
892 self.options = Some(options);
893 }
894 #[cfg(feature = "thread-safe")]
902 pub fn apply<'a, T: Into<String>>(
903 self,
904 rom: RomData,
905 patch: T,
906 ) -> Result<ApplyResult<'a>, ConcurrentApplyError> {
907 if APPLYRESULT_ONCE_ALIVE
908 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
909 .is_err()
910 {
911 return Err(ConcurrentApplyError);
912 }
913
914 let guard = global_asar_lock().lock();
915 let (romdata, result) =
916 patching::patch_ex_basic(rom, patch.into(), self.options.unwrap_or_default());
917
918 Ok(ApplyResult {
919 romdata,
920 success: result,
921 _guard: guard,
922 })
923 }
924
925 #[cfg(not(feature = "thread-safe"))]
931 pub fn apply<'a, T: Into<String>>(
932 self,
933 rom: RomData,
934 patch: T,
935 ) -> Result<ApplyResult<'a>, ConcurrentApplyError> {
936 if APPLYRESULT_ONCE_ALIVE
937 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
938 .is_err()
939 {
940 return Err(ConcurrentApplyError);
941 }
942
943 let (romdata, result) =
944 patching::patch_ex_basic(rom, patch.into(), self.options.unwrap_or_default());
945
946 Ok(ApplyResult {
947 romdata,
948 success: result,
949 _marker: std::marker::PhantomData,
950 })
951 }
952}
953
954impl Default for Patcher {
955 fn default() -> Self {
956 Self::new()
957 }
958}
959
960impl ApplyResult<'_> {
961 pub fn success(&self) -> bool {
963 self.success
964 }
965
966 pub fn warnings(&self) -> Vec<WarningData> {
969 patching::warnings()
970 }
971
972 pub fn errors(&self) -> Vec<ErrorData> {
976 patching::errors()
977 }
978
979 pub fn prints(&self) -> Vec<String> {
981 patching::prints()
982 }
983
984 pub fn labels(&self) -> Vec<Label> {
988 patching::labels()
989 }
990
991 pub fn label_value(&self, name: &str) -> Option<i32> {
995 patching::label_value(name)
996 }
997
998 pub fn define(&self, name: &str) -> Option<String> {
1002 patching::define(name)
1003 }
1004
1005 pub fn defines(&self) -> Vec<Define> {
1009 patching::defines()
1010 }
1011
1012 pub fn written_blocks(&self) -> Vec<WrittenBlock> {
1016 patching::written_blocks()
1017 }
1018
1019 pub fn mapper_type(&self) -> Option<MapperType> {
1023 patching::mapper_type()
1024 }
1025
1026 pub fn symbols_file(&self, symboltype: SymbolType) -> Option<String> {
1030 patching::symbols_file(symboltype)
1031 }
1032
1033 pub fn romdata(mut self) -> RomData {
1039 let romdata = std::mem::take(&mut self.romdata);
1040 APPLYRESULT_ONCE_ALIVE.store(false, Ordering::SeqCst);
1041 romdata
1042 }
1043}
1044
1045impl Drop for ApplyResult<'_> {
1046 fn drop(&mut self) {
1047 patching::reset();
1048 }
1049}