rulewright 0.1.2

Executable engineering standards for Rust workspaces
Documentation
use ra_ap_syntax::{
    AstNode,
    ast::{self, HasAttrs, HasName, HasVisibility, VisibilityKind},
};

pub(super) use super::super::support::{is_inside_trait, is_item_or_impl_fn};

pub(super) fn is_fully_public(node: &impl HasVisibility) -> bool {
    node.visibility()
        .is_some_and(|visibility| matches!(visibility.kind(), VisibilityKind::Pub))
}

#[expect(
    clippy::needless_pass_by_value,
    reason = "ra_ap_syntax traversal callbacks yield owned paths and this helper is a callback target"
)]
pub(super) fn path_names(path: ast::Path) -> Vec<String> {
    super::super::support::path_names(&path)
}

#[expect(
    clippy::needless_pass_by_value,
    reason = "ra_ap_syntax traversal callbacks yield owned paths for last-segment checks"
)]
pub(super) fn path_last_is(path: ast::Path, expected: &str) -> bool {
    path.segment()
        .and_then(|segment| segment.name_ref())
        .is_some_and(|name| name.text() == expected)
}

pub(super) fn path_matches(path: ast::Path, expected: &[&str]) -> bool {
    path_names(path)
        .iter()
        .map(String::as_str)
        .eq(expected.iter().copied())
}

#[expect(
    clippy::needless_pass_by_value,
    reason = "ra_ap_syntax traversal callbacks yield owned types for name extraction"
)]
pub(super) fn type_name(ty: ast::Type) -> Option<String> {
    super::super::support::type_name(&ty)
}

pub(super) fn has_cfg_feature(node: &impl HasAttrs) -> bool {
    node.attrs().any(|attr| {
        attr.simple_name().is_some_and(|name| name == "cfg")
            && attr
                .syntax()
                .descendants_with_tokens()
                .filter_map(ra_ap_syntax::NodeOrToken::into_token)
                .any(|token| token.text() == "feature")
    })
}

pub(super) fn field_types(list: ast::FieldList) -> Vec<ast::Type> {
    match list {
        ast::FieldList::RecordFieldList(fields) => {
            fields.fields().filter_map(|field| field.ty()).collect()
        }

        ast::FieldList::TupleFieldList(fields) => {
            fields.fields().filter_map(|field| field.ty()).collect()
        }
    }
}

pub(super) fn enclosing_impl(function: &ast::Fn) -> Option<ast::Impl> {
    function
        .syntax()
        .ancestors()
        .skip(1)
        .find_map(ast::Impl::cast)
}

pub(super) fn name_text(node: &impl HasName) -> Option<String> {
    node.name().map(|name| name.text().to_string())
}