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