1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use crate::result::*;
use crate::svc;
use crate::mem::alloc;
use crate::rrt0;
use crate::ipc::sf;
use crate::service;
use crate::service::fatal;
use crate::service::fatal::IService;
use core::mem;
pub mod rc;
bit_enum! {
AssertLevel(u32) {
NeedsHeapAllocation = bit!(31),
FatalThrow = 1 | Self::NeedsHeapAllocation().get(),
Panic = 2 | Self::NeedsHeapAllocation().get(),
ProcessExit = 3,
SvcBreak = 4
}
}
impl AssertLevel {
const ASSERT_LEVEL_ORDER: [AssertLevel; 4] = [AssertLevel::FatalThrow(), AssertLevel::Panic(), AssertLevel::ProcessExit(), AssertLevel::SvcBreak()];
#[inline]
pub fn get_next_level(self) -> Option<Self> {
for i in 0..Self::ASSERT_LEVEL_ORDER.len() {
if Self::ASSERT_LEVEL_ORDER[i] == self {
let next_i = i + 1;
if next_i < Self::ASSERT_LEVEL_ORDER.len() {
return Some(Self::ASSERT_LEVEL_ORDER[next_i]);
}
}
}
None
}
}
#[inline]
fn do_assert(level: AssertLevel, rc: ResultCode) -> bool {
if level.contains(AssertLevel::NeedsHeapAllocation()) && !alloc::is_enabled() {
false
}
else {
if level == AssertLevel::FatalThrow() {
match service::new_service_object::<fatal::Service>() {
Ok(fatal) => {
let _ = fatal.get().throw_fatal_with_policy(rc, fatal::FatalPolicy::ErrorScreen, sf::ProcessId::new());
},
_ => {}
};
}
else if level == AssertLevel::Panic() {
let res: Result<()> = Err(rc);
res.unwrap();
}
else if level == AssertLevel::ProcessExit() {
rrt0::exit(rc);
}
else if level == AssertLevel::SvcBreak() {
svc::break_(svc::BreakReason::Panic, &rc as *const _ as *const u8, mem::size_of::<ResultCode>());
}
true
}
}
#[inline]
pub fn assert(desired_level: AssertLevel, rc: ResultCode) {
if rc.is_failure() {
let mut current_level = desired_level;
while !do_assert(current_level, rc) {
if let Some(next_level) = current_level.get_next_level() {
current_level = next_level;
}
else {
loop {}
}
}
}
}