use crate::types::{ClassInfo, MAX_INHERITANCE_DEPTH};
use std::sync::Arc;
use super::ELOQUENT_MODEL_FQN;
pub(in crate::virtual_members::laravel) fn walks_parent_chain(
class: &ClassInfo,
class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>,
predicate: fn(&str) -> bool,
) -> bool {
if predicate(&class.name) {
return true;
}
let mut current_parent = class.parent_class.clone();
let mut depth = 0u32;
while let Some(ref parent_name) = current_parent {
depth += 1;
if depth > MAX_INHERITANCE_DEPTH {
break;
}
if predicate(parent_name) {
return true;
}
match class_loader(parent_name) {
Some(parent) => {
if predicate(&parent.name) {
return true;
}
current_parent = parent.parent_class.clone();
}
None => break,
}
}
false
}
pub(in crate::virtual_members::laravel) fn is_eloquent_model(class_name: &str) -> bool {
class_name == ELOQUENT_MODEL_FQN
}
pub fn extends_eloquent_model(
class: &ClassInfo,
class_loader: &dyn Fn(&str) -> Option<Arc<ClassInfo>>,
) -> bool {
walks_parent_chain(class, class_loader, is_eloquent_model)
}
pub(crate) fn camel_to_snake(s: &str) -> String {
let mut result = String::with_capacity(s.len() + 4);
let chars: Vec<char> = s.chars().collect();
for (i, &c) in chars.iter().enumerate() {
if c.is_uppercase() {
if i > 0 {
let prev = chars[i - 1];
if prev.is_lowercase() || prev.is_ascii_digit() {
result.push('_');
} else if prev.is_uppercase() {
if let Some(&next) = chars.get(i + 1)
&& next.is_lowercase()
{
result.push('_');
}
}
}
for lc in c.to_lowercase() {
result.push(lc);
}
} else {
result.push(c);
}
}
result
}
pub(crate) fn snake_to_camel(s: &str) -> String {
let mut result = String::with_capacity(s.len());
let mut capitalize_next = false;
for c in s.chars() {
if c == '_' {
capitalize_next = true;
} else if capitalize_next {
for uc in c.to_uppercase() {
result.push(uc);
}
capitalize_next = false;
} else {
result.push(c);
}
}
result
}
pub(in crate::virtual_members::laravel) fn snake_to_pascal(s: &str) -> String {
let mut result = String::with_capacity(s.len());
let mut capitalize_next = true;
for c in s.chars() {
if c == '_' {
capitalize_next = true;
} else if capitalize_next {
for uc in c.to_uppercase() {
result.push(uc);
}
capitalize_next = false;
} else {
result.push(c);
}
}
result
}
pub(crate) fn legacy_accessor_method_name(property_name: &str) -> String {
let pascal = snake_to_pascal(property_name);
format!("get{pascal}Attribute")
}
pub(crate) fn accessor_method_candidates(property_name: &str) -> Vec<String> {
vec![
legacy_accessor_method_name(property_name),
snake_to_camel(property_name),
]
}
#[cfg(test)]
#[path = "helpers_tests.rs"]
mod tests;