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