1use crate::state_stub::{LuaState, LuaStateStubExt as _};
15use lua_types::{LuaError, LuaValue};
16
17type LuaCFunction = fn(&mut LuaState) -> Result<usize, LuaError>;
18
19fn arg_u32(state: &mut LuaState, arg: i32) -> Result<u32, LuaError> {
22 let n = state.check_integer(arg)?;
23 Ok(n as u32)
24}
25
26fn push_u32(state: &mut LuaState, v: u32) {
28 state.push(LuaValue::Int(v as i64));
29}
30
31fn fold(
33 state: &mut LuaState,
34 init: u32,
35 op: fn(u32, u32) -> u32,
36) -> Result<usize, LuaError> {
37 let top = state.get_top();
38 let mut acc = init;
39 for i in 1..=top {
40 acc = op(acc, arg_u32(state, i)?);
41 }
42 push_u32(state, acc & 0xFFFF_FFFF);
43 Ok(1)
44}
45
46fn bit_band(state: &mut LuaState) -> Result<usize, LuaError> {
47 fold(state, 0xFFFF_FFFF, |a, b| a & b)
48}
49
50fn bit_bor(state: &mut LuaState) -> Result<usize, LuaError> {
51 fold(state, 0, |a, b| a | b)
52}
53
54fn bit_bxor(state: &mut LuaState) -> Result<usize, LuaError> {
55 fold(state, 0, |a, b| a ^ b)
56}
57
58fn bit_bnot(state: &mut LuaState) -> Result<usize, LuaError> {
59 let a = arg_u32(state, 1)?;
60 push_u32(state, !a);
61 Ok(1)
62}
63
64fn bit_lshift(state: &mut LuaState) -> Result<usize, LuaError> {
65 let a = arg_u32(state, 1)?;
66 let disp = state.check_integer(2)?;
67 push_u32(state, shift(a, disp));
68 Ok(1)
69}
70
71fn bit_rshift(state: &mut LuaState) -> Result<usize, LuaError> {
72 let a = arg_u32(state, 1)?;
73 let disp = state.check_integer(2)?;
74 push_u32(state, shift(a, -disp));
75 Ok(1)
76}
77
78fn shift(x: u32, disp: i64) -> u32 {
81 if disp <= -32 || disp >= 32 {
82 0
83 } else if disp >= 0 {
84 x << disp
85 } else {
86 x >> (-disp)
87 }
88}
89
90fn mask_w(w: u32) -> u32 {
92 if w >= 32 {
93 0xFFFF_FFFF
94 } else {
95 (1u32 << w) - 1
96 }
97}
98
99fn field_args(
102 state: &mut LuaState,
103 field_arg: i32,
104 width_arg: i32,
105) -> Result<(u32, u32), LuaError> {
106 let f = state.check_integer(field_arg)?;
107 let w = if state.get_top() >= width_arg {
108 state.check_integer(width_arg)?
109 } else {
110 1
111 };
112 if f < 0 {
113 return Err(LuaError::arg_error(field_arg, "field cannot be negative"));
114 }
115 if w < 1 {
116 return Err(LuaError::arg_error(width_arg, "width must be positive"));
117 }
118 if f + w > 32 {
119 return Err(LuaError::arg_error(
120 field_arg,
121 "trying to access non-existent bits",
122 ));
123 }
124 Ok((f as u32, w as u32))
125}
126
127fn bit_btest(state: &mut LuaState) -> Result<usize, LuaError> {
129 let top = state.get_top();
130 let mut acc: u32 = 0xFFFF_FFFF;
131 for i in 1..=top {
132 acc &= arg_u32(state, i)?;
133 }
134 state.push(LuaValue::Bool(acc != 0));
135 Ok(1)
136}
137
138fn bit_extract(state: &mut LuaState) -> Result<usize, LuaError> {
140 let n = arg_u32(state, 1)?;
141 let (f, w) = field_args(state, 2, 3)?;
142 push_u32(state, (n >> f) & mask_w(w));
143 Ok(1)
144}
145
146fn bit_replace(state: &mut LuaState) -> Result<usize, LuaError> {
149 let n = arg_u32(state, 1)?;
150 let v = arg_u32(state, 2)?;
151 let (f, w) = field_args(state, 3, 4)?;
152 let m = mask_w(w);
153 push_u32(state, (n & !(m << f)) | ((v & m) << f));
154 Ok(1)
155}
156
157fn bit_arshift(state: &mut LuaState) -> Result<usize, LuaError> {
160 let x = arg_u32(state, 1)?;
161 let disp = state.check_integer(2)?;
162 let r = if disp < 0 {
163 shift(x, -disp)
164 } else if disp >= 32 {
165 if x & 0x8000_0000 != 0 {
166 0xFFFF_FFFF
167 } else {
168 0
169 }
170 } else if x & 0x8000_0000 != 0 {
171 (x >> disp) | !(0xFFFF_FFFFu32 >> disp)
172 } else {
173 x >> disp
174 };
175 push_u32(state, r);
176 Ok(1)
177}
178
179fn rotate(x: u32, disp: i64) -> u32 {
181 let d = (((disp % 32) + 32) % 32) as u32;
182 if d == 0 {
183 x
184 } else {
185 (x << d) | (x >> (32 - d))
186 }
187}
188
189fn bit_lrotate(state: &mut LuaState) -> Result<usize, LuaError> {
190 let x = arg_u32(state, 1)?;
191 let disp = state.check_integer(2)?;
192 push_u32(state, rotate(x, disp));
193 Ok(1)
194}
195
196fn bit_rrotate(state: &mut LuaState) -> Result<usize, LuaError> {
197 let x = arg_u32(state, 1)?;
198 let disp = state.check_integer(2)?;
199 push_u32(state, rotate(x, -disp));
200 Ok(1)
201}
202
203const BIT32_FUNCS: &[(&[u8], LuaCFunction)] = &[
205 (b"band", bit_band),
206 (b"bor", bit_bor),
207 (b"bxor", bit_bxor),
208 (b"bnot", bit_bnot),
209 (b"lshift", bit_lshift),
210 (b"rshift", bit_rshift),
211 (b"btest", bit_btest),
212 (b"extract", bit_extract),
213 (b"replace", bit_replace),
214 (b"arshift", bit_arshift),
215 (b"lrotate", bit_lrotate),
216 (b"rrotate", bit_rrotate),
217];
218
219pub fn open_bit32(state: &mut LuaState) -> Result<usize, LuaError> {
221 state.new_lib(BIT32_FUNCS)?;
222 Ok(1)
223}
224
225