(
vm: &VirtualMachine,
spec: &CFormatSpec,
obj: PyObjectRef,
)
| 19 | use num_traits::cast::ToPrimitive; |
| 20 | |
| 21 | fn spec_format_bytes( |
| 22 | vm: &VirtualMachine, |
| 23 | spec: &CFormatSpec, |
| 24 | obj: PyObjectRef, |
| 25 | ) -> PyResult<Vec<u8>> { |
| 26 | match &spec.format_type { |
| 27 | CFormatType::String(conversion) => match conversion { |
| 28 | // Unlike strings, %r and %a are identical for bytes: the behaviour corresponds to |
| 29 | // %a for strings (not %r) |
| 30 | CFormatConversion::Repr | CFormatConversion::Ascii => { |
| 31 | let b = builtins::ascii(obj, vm)?.as_bytes().to_vec(); |
| 32 | Ok(b) |
| 33 | } |
| 34 | CFormatConversion::Str | CFormatConversion::Bytes => { |
| 35 | if let Ok(buffer) = PyBuffer::try_from_borrowed_object(vm, &obj) { |
| 36 | Ok(buffer.contiguous_or_collect(|bytes| spec.format_bytes(bytes))) |
| 37 | } else { |
| 38 | let bytes = vm |
| 39 | .get_special_method(&obj, identifier!(vm, __bytes__))? |
| 40 | .ok_or_else(|| { |
| 41 | vm.new_type_error(format!( |
| 42 | "%b requires a bytes-like object, or an object that \ |
| 43 | implements __bytes__, not '{}'", |
| 44 | obj.class().name() |
| 45 | )) |
| 46 | })? |
| 47 | .invoke((), vm)?; |
| 48 | let bytes = PyBytes::try_from_borrowed_object(vm, &bytes)?; |
| 49 | Ok(spec.format_bytes(bytes.as_bytes())) |
| 50 | } |
| 51 | } |
| 52 | }, |
| 53 | CFormatType::Number(number_type) => match number_type { |
| 54 | CNumberType::DecimalD | CNumberType::DecimalI | CNumberType::DecimalU => { |
| 55 | match_class!(match &obj { |
| 56 | ref i @ PyInt => { |
| 57 | Ok(spec.format_number(i.as_bigint()).into_bytes()) |
| 58 | } |
| 59 | ref f @ PyFloat => { |
| 60 | Ok(spec |
| 61 | .format_number(&try_f64_to_bigint(f.to_f64(), vm)?) |
| 62 | .into_bytes()) |
| 63 | } |
| 64 | obj => { |
| 65 | if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) { |
| 66 | let result = method?.call((), vm)?; |
| 67 | if let Some(i) = result.downcast_ref::<PyInt>() { |
| 68 | return Ok(spec.format_number(i.as_bigint()).into_bytes()); |
| 69 | } |
| 70 | } |
| 71 | Err(vm.new_type_error(format!( |
| 72 | "%{} format: a number is required, not {}", |
| 73 | spec.format_type.to_char(), |
| 74 | obj.class().name() |
| 75 | ))) |
| 76 | } |
| 77 | }) |
| 78 | } |
no test coverage detected