//! ref: composer/src/Composer/DependencyResolver/GenericRule.php use crate::dependency_resolver::rule::Rule; use anyhow::Result; use shirabe_php_shim::{PHP_VERSION_ID, PhpMixed, RuntimeException, hash_raw, implode, unpack}; use super::{request::Request, rule::ReasonData}; pub struct GenericRule { pub(crate) literals: Vec, } impl GenericRule { pub fn new(mut literals: Vec, reason: PhpMixed, reason_data: PhpMixed) -> Self { let inner = Rule::new(reason, reason_data); literals.sort(); Self { inner, literals } } pub fn get_literals(&self) -> &Vec { &self.literals } pub fn get_hash(&self) -> Result { let joined = self .literals .iter() .map(|l| l.to_string()) .collect::>() .join(","); let algo = if PHP_VERSION_ID > 80100 { "xxh3" } else { "sha1" }; let binary = hash_raw(algo, &joined); let data = unpack("ihash", &binary); match data { Some(map) => { if let Some(val) = map.get("hash") { Ok(val.as_int().unwrap_or(0)) } else { Err(RuntimeException { message: format!("Failed unpacking: {}", joined), code: 0, } .into()) } } None => Err(RuntimeException { message: format!("Failed unpacking: {}", joined), code: 0, } .into()), } } pub fn equals(&self, rule: &dyn RuleLiterals) -> bool { self.literals == *rule.get_literals() } pub fn is_assertion(&self) -> bool { self.literals.len() == 1 } pub fn to_string(&self) -> String { let prefix = if self.inner.is_disabled() { "disabled(" } else { "(" }; let mut result = prefix.to_string(); for (i, literal) in self.literals.iter().enumerate() { if i != 0 { result.push('|'); } result.push_str(&literal.to_string()); } result.push(')'); result } } pub trait RuleLiterals { fn get_literals(&self) -> &Vec; fn is_multi_conflict_rule(&self) -> bool { false } } impl RuleLiterals for GenericRule { fn get_literals(&self) -> &Vec { &self.literals } } impl Rule for GenericRule { fn bitfield(&self) -> i64 { todo!() } fn bitfield_mut(&mut self) -> &mut i64 { todo!() } fn request(&self) -> Option<&Request> { todo!() } fn request_mut(&mut self) -> Option<&mut Request> { todo!() } fn reason_data(&self) -> Option<&ReasonData> { todo!() } fn reason_data_mut(&mut self) -> Option<&mut ReasonData> { todo!() } fn get_literals(&self) -> Vec { todo!() } fn get_hash(&self) -> PhpMixed { todo!() } fn to_string(&self) -> String { todo!() } fn equals(&self, rule: &dyn Rule) -> bool { todo!() } fn is_assertion(&self) -> bool { todo!() } }