(attrs: &[Attribute], item_new: F)
| 428 | } |
| 429 | |
| 430 | fn attrs_to_module_items<F, R>(attrs: &[Attribute], item_new: F) -> Result<(Vec<R>, Vec<Attribute>)> |
| 431 | where |
| 432 | F: Fn(usize, AttrName, Vec<usize>) -> R, |
| 433 | { |
| 434 | let mut cfgs: Vec<Attribute> = Vec::new(); |
| 435 | let mut result = Vec::new(); |
| 436 | |
| 437 | let mut iter = attrs.iter().enumerate().peekable(); |
| 438 | while let Some((_, attr)) = iter.peek() { |
| 439 | // take all cfgs but no py items |
| 440 | let attr = *attr; |
| 441 | if let Some(ident) = attr.get_ident() { |
| 442 | let attr_name = ident.to_string(); |
| 443 | if attr_name == "cfg" { |
| 444 | cfgs.push(attr.clone()); |
| 445 | } else if ALL_ALLOWED_NAMES.contains(&attr_name.as_str()) { |
| 446 | break; |
| 447 | } |
| 448 | } |
| 449 | iter.next(); |
| 450 | } |
| 451 | |
| 452 | let mut closed = false; |
| 453 | let mut py_attrs = Vec::new(); |
| 454 | for (i, attr) in iter { |
| 455 | // take py items but no cfgs |
| 456 | let attr_name = if let Some(ident) = attr.get_ident() { |
| 457 | ident.to_string() |
| 458 | } else { |
| 459 | continue; |
| 460 | }; |
| 461 | if attr_name == "cfg" { |
| 462 | bail_span!(attr, "#[py*] items must be placed under `cfgs`") |
| 463 | } |
| 464 | |
| 465 | let attr_name = match AttrName::from_str(attr_name.as_str()) { |
| 466 | Ok(name) => name, |
| 467 | Err(wrong_name) => { |
| 468 | if !ALL_ALLOWED_NAMES.contains(&wrong_name.as_str()) { |
| 469 | continue; |
| 470 | } else if closed { |
| 471 | bail_span!(attr, "Only one #[pyattr] annotated #[py*] item can exist") |
| 472 | } else { |
| 473 | bail_span!(attr, "#[pymodule] doesn't accept #[{}]", wrong_name) |
| 474 | } |
| 475 | } |
| 476 | }; |
| 477 | |
| 478 | if attr_name == AttrName::Attr { |
| 479 | if !result.is_empty() { |
| 480 | bail_span!( |
| 481 | attr, |
| 482 | "#[pyattr] must be placed on top of other #[py*] items", |
| 483 | ) |
| 484 | } |
| 485 | py_attrs.push(i); |
| 486 | continue; |
| 487 | } |
no test coverage detected