1use crate::state_stub::{LuaState, LuaStateStubExt as _};
24use lua_types::{LuaError, LuaValue, NumberModel};
25
26type LuaCFunction = fn(&mut LuaState) -> Result<usize, LuaError>;
27
28fn arg_u32(state: &mut LuaState, arg: i32) -> Result<u32, LuaError> {
42 let model = state.global().lua_version.number_model();
43 match model {
44 NumberModel::FloatOnly => {
45 let n = state.check_number(arg)?;
46 Ok(n.round_ties_even().rem_euclid(4_294_967_296.0) as u32)
47 }
48 NumberModel::Dual => {
49 let n = state.check_integer(arg)?;
50 Ok(n as u32)
51 }
52 }
53}
54
55fn arg_int(state: &mut LuaState, arg: i32) -> Result<i64, LuaError> {
63 let model = state.global().lua_version.number_model();
64 match model {
65 NumberModel::FloatOnly => Ok(state.check_number(arg)?.trunc() as i64),
66 NumberModel::Dual => state.check_integer(arg),
67 }
68}
69
70fn push_u32(state: &mut LuaState, v: u32) {
72 state.push(LuaValue::Int(v as i64));
73}
74
75fn fold(state: &mut LuaState, init: u32, op: fn(u32, u32) -> u32) -> Result<usize, LuaError> {
77 let top = state.get_top();
78 let mut acc = init;
79 for i in 1..=top {
80 acc = op(acc, arg_u32(state, i)?);
81 }
82 push_u32(state, acc);
83 Ok(1)
84}
85
86fn bit_band(state: &mut LuaState) -> Result<usize, LuaError> {
87 fold(state, 0xFFFF_FFFF, |a, b| a & b)
88}
89
90fn bit_bor(state: &mut LuaState) -> Result<usize, LuaError> {
91 fold(state, 0, |a, b| a | b)
92}
93
94fn bit_bxor(state: &mut LuaState) -> Result<usize, LuaError> {
95 fold(state, 0, |a, b| a ^ b)
96}
97
98fn bit_bnot(state: &mut LuaState) -> Result<usize, LuaError> {
99 let a = arg_u32(state, 1)?;
100 push_u32(state, !a);
101 Ok(1)
102}
103
104fn bit_lshift(state: &mut LuaState) -> Result<usize, LuaError> {
105 let a = arg_u32(state, 1)?;
106 let disp = arg_int(state, 2)?;
107 push_u32(state, shift(a, disp));
108 Ok(1)
109}
110
111fn bit_rshift(state: &mut LuaState) -> Result<usize, LuaError> {
112 let a = arg_u32(state, 1)?;
113 let disp = arg_int(state, 2)?;
114 push_u32(state, shift(a, -disp));
115 Ok(1)
116}
117
118fn shift(x: u32, disp: i64) -> u32 {
121 if disp <= -32 || disp >= 32 {
122 0
123 } else if disp >= 0 {
124 x << disp
125 } else {
126 x >> (-disp)
127 }
128}
129
130fn mask_w(w: u32) -> u32 {
132 if w >= 32 {
133 0xFFFF_FFFF
134 } else {
135 (1u32 << w) - 1
136 }
137}
138
139fn field_args(
142 state: &mut LuaState,
143 field_arg: i32,
144 width_arg: i32,
145) -> Result<(u32, u32), LuaError> {
146 let f = arg_int(state, field_arg)?;
147 let w = if state.get_top() >= width_arg {
148 arg_int(state, width_arg)?
149 } else {
150 1
151 };
152 if f < 0 {
153 return Err(LuaError::arg_error(field_arg, "field cannot be negative"));
154 }
155 if w < 1 {
156 return Err(LuaError::arg_error(width_arg, "width must be positive"));
157 }
158 if f + w > 32 {
159 return Err(LuaError::arg_error(
160 field_arg,
161 "trying to access non-existent bits",
162 ));
163 }
164 Ok((f as u32, w as u32))
165}
166
167fn bit_btest(state: &mut LuaState) -> Result<usize, LuaError> {
169 let top = state.get_top();
170 let mut acc: u32 = 0xFFFF_FFFF;
171 for i in 1..=top {
172 acc &= arg_u32(state, i)?;
173 }
174 state.push(LuaValue::Bool(acc != 0));
175 Ok(1)
176}
177
178fn bit_extract(state: &mut LuaState) -> Result<usize, LuaError> {
180 let n = arg_u32(state, 1)?;
181 let (f, w) = field_args(state, 2, 3)?;
182 push_u32(state, (n >> f) & mask_w(w));
183 Ok(1)
184}
185
186fn bit_replace(state: &mut LuaState) -> Result<usize, LuaError> {
189 let n = arg_u32(state, 1)?;
190 let v = arg_u32(state, 2)?;
191 let (f, w) = field_args(state, 3, 4)?;
192 let m = mask_w(w);
193 push_u32(state, (n & !(m << f)) | ((v & m) << f));
194 Ok(1)
195}
196
197fn bit_arshift(state: &mut LuaState) -> Result<usize, LuaError> {
200 let x = arg_u32(state, 1)?;
201 let disp = arg_int(state, 2)?;
202 let r = if disp < 0 {
203 shift(x, -disp)
204 } else if disp >= 32 {
205 if x & 0x8000_0000 != 0 {
206 0xFFFF_FFFF
207 } else {
208 0
209 }
210 } else if x & 0x8000_0000 != 0 {
211 (x >> disp) | !(0xFFFF_FFFFu32 >> disp)
212 } else {
213 x >> disp
214 };
215 push_u32(state, r);
216 Ok(1)
217}
218
219fn rotate(x: u32, disp: i64) -> u32 {
221 let d = (((disp % 32) + 32) % 32) as u32;
222 if d == 0 {
223 x
224 } else {
225 (x << d) | (x >> (32 - d))
226 }
227}
228
229fn bit_lrotate(state: &mut LuaState) -> Result<usize, LuaError> {
230 let x = arg_u32(state, 1)?;
231 let disp = arg_int(state, 2)?;
232 push_u32(state, rotate(x, disp));
233 Ok(1)
234}
235
236fn bit_rrotate(state: &mut LuaState) -> Result<usize, LuaError> {
237 let x = arg_u32(state, 1)?;
238 let disp = arg_int(state, 2)?;
239 push_u32(state, rotate(x, -disp));
240 Ok(1)
241}
242
243const BIT32_FUNCS: &[(&[u8], LuaCFunction)] = &[
245 (b"band", bit_band),
246 (b"bor", bit_bor),
247 (b"bxor", bit_bxor),
248 (b"bnot", bit_bnot),
249 (b"lshift", bit_lshift),
250 (b"rshift", bit_rshift),
251 (b"btest", bit_btest),
252 (b"extract", bit_extract),
253 (b"replace", bit_replace),
254 (b"arshift", bit_arshift),
255 (b"lrotate", bit_lrotate),
256 (b"rrotate", bit_rrotate),
257];
258
259pub fn open_bit32(state: &mut LuaState) -> Result<usize, LuaError> {
261 state.new_lib(BIT32_FUNCS)?;
262 Ok(1)
263}
264
265