(val: PyObjectRef, vm: &VirtualMachine)
| 201 | } |
| 202 | |
| 203 | fn float_from_string(val: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> { |
| 204 | let (bytearray, buffer, buffer_lock, mapped_string); |
| 205 | let b = if let Some(s) = val.downcast_ref::<PyStr>() { |
| 206 | use crate::common::str::PyKindStr; |
| 207 | match s.as_str_kind() { |
| 208 | PyKindStr::Ascii(s) => s.trim().as_bytes(), |
| 209 | PyKindStr::Utf8(s) => { |
| 210 | mapped_string = s |
| 211 | .trim() |
| 212 | .chars() |
| 213 | .map(|c| { |
| 214 | if let Some(n) = rustpython_common::str::char_to_decimal(c) { |
| 215 | char::from_digit(n.into(), 10).unwrap() |
| 216 | } else if c.is_whitespace() { |
| 217 | ' ' |
| 218 | } else { |
| 219 | c |
| 220 | } |
| 221 | }) |
| 222 | .collect::<String>(); |
| 223 | mapped_string.as_bytes() |
| 224 | } |
| 225 | // if there are surrogates, it's not gonna parse anyway, |
| 226 | // so we can just choose a known bad value |
| 227 | PyKindStr::Wtf8(_) => b"", |
| 228 | } |
| 229 | } else if let Some(bytes) = val.downcast_ref::<PyBytes>() { |
| 230 | bytes.as_bytes() |
| 231 | } else if let Some(buf) = val.downcast_ref::<PyByteArray>() { |
| 232 | bytearray = buf.borrow_buf(); |
| 233 | &*bytearray |
| 234 | } else if let Ok(b) = ArgBytesLike::try_from_borrowed_object(vm, &val) { |
| 235 | buffer = b; |
| 236 | buffer_lock = buffer.borrow_buf(); |
| 237 | &*buffer_lock |
| 238 | } else { |
| 239 | return Err(vm.new_type_error(format!( |
| 240 | "float() argument must be a string or a number, not '{}'", |
| 241 | val.class().name() |
| 242 | ))); |
| 243 | }; |
| 244 | crate::literal::float::parse_bytes(b).ok_or_else(|| { |
| 245 | val.repr(vm) |
| 246 | .map(|repr| vm.new_value_error(format!("could not convert string to float: {repr}"))) |
| 247 | .unwrap_or_else(|e| e) |
| 248 | }) |
| 249 | } |
| 250 | |
| 251 | #[pyclass( |
| 252 | flags(BASETYPE, _MATCH_SELF), |
no test coverage detected