(
vm: &VirtualMachine,
format_string: &Wtf8,
values_obj: PyObjectRef,
)
| 377 | } |
| 378 | |
| 379 | pub(crate) fn cformat_string( |
| 380 | vm: &VirtualMachine, |
| 381 | format_string: &Wtf8, |
| 382 | values_obj: PyObjectRef, |
| 383 | ) -> PyResult<Wtf8Buf> { |
| 384 | let format = CFormatWtf8::parse_from_wtf8(format_string) |
| 385 | .map_err(|err| vm.new_value_error(err.to_string()))?; |
| 386 | let (num_specifiers, mapping_required) = format |
| 387 | .check_specifiers() |
| 388 | .ok_or_else(|| specifier_error(vm))?; |
| 389 | |
| 390 | let mut result = Wtf8Buf::new(); |
| 391 | |
| 392 | let is_mapping = values_obj.class().has_attr(identifier!(vm, __getitem__)) |
| 393 | && !values_obj.fast_isinstance(vm.ctx.types.tuple_type) |
| 394 | && !values_obj.fast_isinstance(vm.ctx.types.str_type); |
| 395 | |
| 396 | if num_specifiers == 0 { |
| 397 | // literal only |
| 398 | return if is_mapping |
| 399 | || values_obj |
| 400 | .downcast_ref::<tuple::PyTuple>() |
| 401 | .is_some_and(|e| e.is_empty()) |
| 402 | { |
| 403 | for (_, part) in format.iter() { |
| 404 | match part { |
| 405 | CFormatPart::Literal(literal) => result.push_wtf8(literal), |
| 406 | CFormatPart::Spec(_) => unreachable!(), |
| 407 | } |
| 408 | } |
| 409 | Ok(result) |
| 410 | } else { |
| 411 | Err(vm.new_type_error("not all arguments converted during string formatting")) |
| 412 | }; |
| 413 | } |
| 414 | |
| 415 | if mapping_required { |
| 416 | // dict |
| 417 | return if is_mapping { |
| 418 | for (idx, part) in format { |
| 419 | match part { |
| 420 | CFormatPart::Literal(literal) => result.push_wtf8(&literal), |
| 421 | CFormatPart::Spec(CFormatSpecKeyed { mapping_key, spec }) => { |
| 422 | let value = values_obj.get_item(&mapping_key.unwrap(), vm)?; |
| 423 | let part_result = spec_format_string(vm, &spec, value, idx)?; |
| 424 | result.push_wtf8(&part_result); |
| 425 | } |
| 426 | } |
| 427 | } |
| 428 | Ok(result) |
| 429 | } else { |
| 430 | Err(vm.new_type_error("format requires a mapping")) |
| 431 | }; |
| 432 | } |
| 433 | |
| 434 | // tuple |
| 435 | let values = if let Some(tup) = values_obj.downcast_ref::<tuple::PyTuple>() { |
| 436 | tup.as_slice() |
no test coverage detected