use anyhow::{anyhow, Result};
use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use crate::data::datatable::DataValue;
pub mod ansi;
pub mod astronomy;
pub mod base_conversion;
pub mod bigint;
pub mod bitwise;
pub mod bitwise_string;
pub mod case_convert;
pub mod chemistry;
pub mod comparison;
pub mod constants;
pub mod convert;
pub mod date_time;
pub mod financial;
pub mod format;
pub mod format_number;
pub mod geometry;
pub mod group_num;
pub mod hash;
pub mod integer_limits;
pub mod math;
pub mod mathematics;
pub mod number_words;
pub mod particle_charges;
pub mod physics;
pub mod random;
pub mod roman;
pub mod solar_system;
pub mod statistics;
pub mod string_fun;
pub mod string_methods;
pub mod string_utils;
pub mod text_processing;
pub mod trigonometry;
pub mod type_checking;
pub mod utility;
pub mod vector;
pub use string_methods::MethodFunction;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FunctionCategory {
Constant, Mathematical, Statistical, Astronomical, Chemical, Date, String, Aggregate, Conversion, BigNumber, TableFunction, Bitwise, Terminal, }
impl fmt::Display for FunctionCategory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FunctionCategory::Constant => write!(f, "Constant"),
FunctionCategory::Mathematical => write!(f, "Mathematical"),
FunctionCategory::Statistical => write!(f, "Statistical"),
FunctionCategory::Astronomical => write!(f, "Astronomical"),
FunctionCategory::Chemical => write!(f, "Chemical"),
FunctionCategory::Date => write!(f, "Date"),
FunctionCategory::String => write!(f, "String"),
FunctionCategory::Aggregate => write!(f, "Aggregate"),
FunctionCategory::Conversion => write!(f, "Conversion"),
FunctionCategory::BigNumber => write!(f, "BigNumber"),
FunctionCategory::TableFunction => write!(f, "TableFunction"),
FunctionCategory::Bitwise => write!(f, "Bitwise"),
FunctionCategory::Terminal => write!(f, "Terminal"),
}
}
}
#[derive(Debug, Clone)]
pub enum ArgCount {
Fixed(usize),
Range(usize, usize),
Variadic,
}
impl ArgCount {
#[must_use]
pub fn is_valid(&self, count: usize) -> bool {
match self {
ArgCount::Fixed(n) => count == *n,
ArgCount::Range(min, max) => count >= *min && count <= *max,
ArgCount::Variadic => true,
}
}
#[must_use]
pub fn description(&self) -> String {
match self {
ArgCount::Fixed(0) => "no arguments".to_string(),
ArgCount::Fixed(1) => "1 argument".to_string(),
ArgCount::Fixed(n) => format!("{n} arguments"),
ArgCount::Range(min, max) => format!("{min} to {max} arguments"),
ArgCount::Variadic => "any number of arguments".to_string(),
}
}
}
#[derive(Debug, Clone)]
pub struct FunctionSignature {
pub name: &'static str,
pub category: FunctionCategory,
pub arg_count: ArgCount,
pub description: &'static str,
pub returns: &'static str,
pub examples: Vec<&'static str>,
}
pub trait SqlFunction: Send + Sync {
fn signature(&self) -> FunctionSignature;
fn evaluate(&self, args: &[DataValue]) -> Result<DataValue>;
fn validate_args(&self, args: &[DataValue]) -> Result<()> {
let sig = self.signature();
if !sig.arg_count.is_valid(args.len()) {
return Err(anyhow!(
"{}() expects {}, got {}",
sig.name,
sig.arg_count.description(),
args.len()
));
}
Ok(())
}
}
pub struct FunctionRegistry {
functions: HashMap<String, Box<dyn SqlFunction>>,
by_category: HashMap<FunctionCategory, Vec<String>>,
methods: HashMap<String, Arc<dyn MethodFunction>>,
}
impl FunctionRegistry {
#[must_use]
pub fn new() -> Self {
let mut registry = Self {
functions: HashMap::new(),
by_category: HashMap::new(),
methods: HashMap::new(),
};
registry.register_constants();
registry.register_astronomical_functions();
registry.register_chemical_functions();
registry.register_mathematical_functions();
registry.register_statistical_functions();
registry.register_geometry_functions();
registry.register_physics_functions();
registry.register_date_time_functions();
registry.register_string_methods();
registry.register_financial_functions();
registry.register_bigint_functions();
registry.register_conversion_functions();
registry.register_hash_functions();
registry.register_comparison_functions();
registry.register_aggregate_functions();
registry.register_random_functions();
registry.register_format_functions();
registry.register_type_checking_functions();
registry.register_utility_functions();
registry.register_bitwise_functions();
registry.register_ansi_functions();
registry.register_vector_functions();
registry
}
pub fn register(&mut self, func: Box<dyn SqlFunction>) {
let sig = func.signature();
let name = sig.name.to_uppercase();
let category = sig.category;
self.functions.insert(name.clone(), func);
self.by_category.entry(category).or_default().push(name);
}
#[must_use]
pub fn get(&self, name: &str) -> Option<&dyn SqlFunction> {
self.functions
.get(&name.to_uppercase())
.map(std::convert::AsRef::as_ref)
}
#[must_use]
pub fn contains(&self, name: &str) -> bool {
self.functions.contains_key(&name.to_uppercase())
}
#[must_use]
pub fn autocomplete(&self, prefix: &str) -> Vec<FunctionSignature> {
let prefix_upper = prefix.to_uppercase();
self.functions
.iter()
.filter(|(name, _)| name.starts_with(&prefix_upper))
.map(|(_, func)| func.signature())
.collect()
}
#[must_use]
pub fn get_by_category(&self, category: FunctionCategory) -> Vec<FunctionSignature> {
self.by_category
.get(&category)
.map(|names| {
names
.iter()
.filter_map(|name| self.functions.get(name))
.map(|func| func.signature())
.collect()
})
.unwrap_or_default()
}
#[must_use]
pub fn all_functions(&self) -> Vec<FunctionSignature> {
self.functions
.values()
.map(|func| func.signature())
.collect()
}
pub fn register_method(&mut self, method: Arc<dyn MethodFunction>) {
let method_name = method.method_name().to_uppercase();
self.methods.insert(method_name, method);
}
#[must_use]
pub fn get_method(&self, name: &str) -> Option<Arc<dyn MethodFunction>> {
if let Some(method) = self.methods.get(&name.to_uppercase()) {
return Some(Arc::clone(method));
}
for method in self.methods.values() {
if method.handles_method(name) {
return Some(Arc::clone(method));
}
}
None
}
#[must_use]
pub fn has_method(&self, name: &str) -> bool {
self.get_method(name).is_some()
}
#[must_use]
pub fn generate_markdown_docs(&self) -> String {
use std::fmt::Write;
let mut doc = String::new();
writeln!(&mut doc, "# SQL CLI Function Reference\n").unwrap();
writeln!(
&mut doc,
"This document is auto-generated from the function registry.\n"
)
.unwrap();
let mut categories: Vec<FunctionCategory> = self.by_category.keys().copied().collect();
categories.sort_by_key(|c| format!("{c:?}"));
for category in categories {
let functions = self.get_by_category(category);
if functions.is_empty() {
continue;
}
writeln!(&mut doc, "## {category} Functions\n").unwrap();
let mut functions = functions;
functions.sort_by_key(|f| f.name);
for func in functions {
writeln!(&mut doc, "### {}()\n", func.name).unwrap();
writeln!(&mut doc, "**Description:** {}\n", func.description).unwrap();
writeln!(
&mut doc,
"**Arguments:** {}\n",
func.arg_count.description()
)
.unwrap();
writeln!(&mut doc, "**Returns:** {}\n", func.returns).unwrap();
if !func.examples.is_empty() {
writeln!(&mut doc, "**Examples:**").unwrap();
writeln!(&mut doc, "```sql").unwrap();
for example in &func.examples {
writeln!(&mut doc, "{example}").unwrap();
}
writeln!(&mut doc, "```\n").unwrap();
}
}
}
doc
}
#[must_use]
pub fn generate_function_help(&self, name: &str) -> Option<String> {
self.get(name).map(|func| {
let sig = func.signature();
let mut help = String::new();
use std::fmt::Write;
writeln!(&mut help, "Function: {}()", sig.name).unwrap();
writeln!(&mut help, "Category: {}", sig.category).unwrap();
writeln!(&mut help, "Description: {}", sig.description).unwrap();
writeln!(&mut help, "Arguments: {}", sig.arg_count.description()).unwrap();
writeln!(&mut help, "Returns: {}", sig.returns).unwrap();
if !sig.examples.is_empty() {
writeln!(&mut help, "\nExamples:").unwrap();
for example in &sig.examples {
writeln!(&mut help, " {example}").unwrap();
}
}
help
})
}
#[must_use]
pub fn list_functions(&self) -> String {
use std::fmt::Write;
let mut list = String::new();
writeln!(&mut list, "Available SQL Functions:\n").unwrap();
let mut categories: Vec<FunctionCategory> = self.by_category.keys().copied().collect();
categories.sort_by_key(|c| format!("{c:?}"));
for category in categories {
let functions = self.get_by_category(category);
if functions.is_empty() {
continue;
}
writeln!(&mut list, "{category} Functions:").unwrap();
let mut functions = functions;
functions.sort_by_key(|f| f.name);
for func in functions {
writeln!(
&mut list,
" {:20} - {}",
format!("{}()", func.name),
func.description
)
.unwrap();
}
writeln!(&mut list).unwrap();
}
list
}
fn register_constants(&mut self) {
use constants::{
EFunction, HbarFunction, MassElectronFunction, MeFunction, PhiFunction,
PiDigitFunction, PiDigitsFunction, PiFunction, TauFunction,
};
self.register(Box::new(PiFunction));
self.register(Box::new(PiDigitsFunction)); self.register(Box::new(PiDigitFunction)); self.register(Box::new(EFunction));
self.register(Box::new(MeFunction)); self.register(Box::new(MassElectronFunction)); self.register(Box::new(TauFunction));
self.register(Box::new(PhiFunction));
self.register(Box::new(HbarFunction));
}
fn register_astronomical_functions(&mut self) {
use astronomy::{
AuFunction, DistJupiterFunction, DistMarsFunction, DistMercuryFunction,
DistNeptuneFunction, DistSaturnFunction, DistUranusFunction, DistVenusFunction,
LightYearFunction, MassEarthFunction, MassJupiterFunction, MassMarsFunction,
MassMercuryFunction, MassMoonFunction, MassNeptuneFunction, MassSaturnFunction,
MassSunFunction, MassUranusFunction, MassVenusFunction, ParsecFunction,
RadiusEarthFunction, RadiusJupiterFunction, RadiusMarsFunction, RadiusMercuryFunction,
RadiusMoonFunction, RadiusNeptuneFunction, RadiusSaturnFunction, RadiusSunFunction,
RadiusUranusFunction, RadiusVenusFunction,
};
use solar_system::{
DensitySolarBodyFunction, DistanceSolarBodyFunction, EscapeVelocitySolarBodyFunction,
GravitySolarBodyFunction, MassSolarBodyFunction, MoonsSolarBodyFunction,
OrbitalPeriodSolarBodyFunction, RadiusSolarBodyFunction,
RotationPeriodSolarBodyFunction,
};
self.register(Box::new(MassEarthFunction));
self.register(Box::new(MassSunFunction));
self.register(Box::new(MassMoonFunction));
self.register(Box::new(AuFunction)); self.register(Box::new(LightYearFunction));
self.register(Box::new(ParsecFunction));
self.register(Box::new(MassMercuryFunction));
self.register(Box::new(MassVenusFunction));
self.register(Box::new(MassMarsFunction));
self.register(Box::new(MassJupiterFunction));
self.register(Box::new(MassSaturnFunction));
self.register(Box::new(MassUranusFunction));
self.register(Box::new(MassNeptuneFunction));
self.register(Box::new(RadiusSunFunction));
self.register(Box::new(RadiusEarthFunction));
self.register(Box::new(RadiusMoonFunction));
self.register(Box::new(RadiusMercuryFunction));
self.register(Box::new(RadiusVenusFunction));
self.register(Box::new(RadiusMarsFunction));
self.register(Box::new(RadiusJupiterFunction));
self.register(Box::new(RadiusSaturnFunction));
self.register(Box::new(RadiusUranusFunction));
self.register(Box::new(RadiusNeptuneFunction));
self.register(Box::new(DistMercuryFunction));
self.register(Box::new(DistVenusFunction));
self.register(Box::new(DistMarsFunction));
self.register(Box::new(DistJupiterFunction));
self.register(Box::new(DistSaturnFunction));
self.register(Box::new(DistUranusFunction));
self.register(Box::new(DistNeptuneFunction));
self.register(Box::new(MassSolarBodyFunction));
self.register(Box::new(RadiusSolarBodyFunction));
self.register(Box::new(DistanceSolarBodyFunction));
self.register(Box::new(OrbitalPeriodSolarBodyFunction));
self.register(Box::new(GravitySolarBodyFunction));
self.register(Box::new(DensitySolarBodyFunction));
self.register(Box::new(EscapeVelocitySolarBodyFunction));
self.register(Box::new(RotationPeriodSolarBodyFunction));
self.register(Box::new(MoonsSolarBodyFunction));
}
fn register_chemical_functions(&mut self) {
use chemistry::{
AtomicMassFunction, AtomicNumberFunction, AvogadroFunction, MoleculeFormulaFunction,
NeutronsFunction,
};
self.register(Box::new(AvogadroFunction));
self.register(Box::new(AtomicMassFunction));
self.register(Box::new(AtomicNumberFunction));
self.register(Box::new(NeutronsFunction));
self.register(Box::new(MoleculeFormulaFunction));
}
fn register_string_methods(&mut self) {
use case_convert::{
ToCamelCaseFunction, ToConstantCaseFunction, ToKebabCaseFunction, ToPascalCaseFunction,
ToSnakeCaseFunction,
};
use number_words::{ToOrdinal, ToOrdinalWords, ToWords};
use string_fun::{
InitCapFunction, MorseCodeFunction, PigLatinFunction, ProperFunction, ReverseFunction,
Rot13Function, ScrambleFunction, SoundexFunction,
};
use string_utils::{LPadFunction, RPadFunction, RepeatFunction};
use text_processing::{CleanText, ExtractWords, StripPunctuation, Tokenize, WordCount};
string_methods::register_string_methods(self);
self.register(Box::new(RepeatFunction));
self.register(Box::new(LPadFunction));
self.register(Box::new(RPadFunction));
self.register(Box::new(ToSnakeCaseFunction));
self.register(Box::new(ToCamelCaseFunction));
self.register(Box::new(ToPascalCaseFunction));
self.register(Box::new(ToKebabCaseFunction));
self.register(Box::new(ToConstantCaseFunction));
self.register(Box::new(ReverseFunction));
self.register(Box::new(InitCapFunction));
self.register(Box::new(ProperFunction));
self.register(Box::new(Rot13Function));
self.register(Box::new(SoundexFunction));
self.register(Box::new(PigLatinFunction));
self.register(Box::new(MorseCodeFunction));
self.register(Box::new(ScrambleFunction));
self.register(Box::new(ToWords));
self.register(Box::new(ToOrdinal));
self.register(Box::new(ToOrdinalWords));
self.register(Box::new(StripPunctuation));
self.register(Box::new(Tokenize));
self.register(Box::new(CleanText));
self.register(Box::new(ExtractWords));
self.register(Box::new(WordCount));
}
fn register_geometry_functions(&mut self) {
use geometry::{
CircleAreaFunction, CircleCircumferenceFunction, Distance2DFunction,
PythagorasFunction, SphereSurfaceAreaFunction, SphereVolumeFunction,
TriangleAreaFunction,
};
self.register(Box::new(PythagorasFunction));
self.register(Box::new(CircleAreaFunction));
self.register(Box::new(CircleCircumferenceFunction));
self.register(Box::new(SphereVolumeFunction));
self.register(Box::new(SphereSurfaceAreaFunction));
self.register(Box::new(TriangleAreaFunction));
self.register(Box::new(Distance2DFunction));
}
fn register_hash_functions(&mut self) {
use hash::{Md5Function, Sha1Function, Sha256Function, Sha512Function};
self.register(Box::new(Md5Function));
self.register(Box::new(Sha1Function));
self.register(Box::new(Sha256Function));
self.register(Box::new(Sha512Function));
}
fn register_comparison_functions(&mut self) {
comparison::register_comparison_functions(self);
}
fn register_mathematical_functions(&mut self) {
use base_conversion::{
FromBase, FromBinary, FromHex, FromOctal, ToBase, ToBinary, ToHex, ToOctal,
};
use integer_limits::{
ByteMax, ByteMin, CharMax, CharMin, Int16Max, Int16Min, Int32Max, Int32Min, Int64Max,
Int64Min, Int8Max, Int8Min, IntMax, IntMin, LongMax, LongMin, ShortMax, ShortMin,
Uint16Max, Uint32Max, Uint8Max,
};
use mathematics::{
IsPrimeFunction, NextPrimeFunction, NthPrimeFunction, PrevPrimeFunction,
PrimeCountFunction, PrimeFunction, PrimePiFunction,
};
use trigonometry::{
AcosFunction, AsinFunction, Atan2Function, AtanFunction, CosFunction, CoshFunction,
CotFunction, SinFunction, SinhFunction, TanFunction, TanhFunction,
};
self.register(Box::new(PrimeFunction));
self.register(Box::new(NthPrimeFunction)); self.register(Box::new(IsPrimeFunction));
self.register(Box::new(PrimeCountFunction));
self.register(Box::new(PrimePiFunction)); self.register(Box::new(NextPrimeFunction));
self.register(Box::new(PrevPrimeFunction));
self.register(Box::new(SinFunction));
self.register(Box::new(CosFunction));
self.register(Box::new(TanFunction));
self.register(Box::new(CotFunction));
self.register(Box::new(AsinFunction));
self.register(Box::new(AcosFunction));
self.register(Box::new(AtanFunction));
self.register(Box::new(Atan2Function));
self.register(Box::new(SinhFunction));
self.register(Box::new(CoshFunction));
self.register(Box::new(TanhFunction));
self.register(Box::new(ToBase));
self.register(Box::new(FromBase));
self.register(Box::new(ToBinary));
self.register(Box::new(FromBinary));
self.register(Box::new(ToHex));
self.register(Box::new(FromHex));
self.register(Box::new(ToOctal));
self.register(Box::new(FromOctal));
self.register(Box::new(Int8Min));
self.register(Box::new(Int8Max));
self.register(Box::new(Uint8Max));
self.register(Box::new(Int16Min));
self.register(Box::new(Int16Max));
self.register(Box::new(Uint16Max));
self.register(Box::new(Int32Min));
self.register(Box::new(Int32Max));
self.register(Box::new(Uint32Max));
self.register(Box::new(Int64Min));
self.register(Box::new(Int64Max));
self.register(Box::new(ByteMin));
self.register(Box::new(ByteMax));
self.register(Box::new(CharMin));
self.register(Box::new(CharMax));
self.register(Box::new(ShortMin));
self.register(Box::new(ShortMax));
self.register(Box::new(IntMin));
self.register(Box::new(IntMax));
self.register(Box::new(LongMin));
self.register(Box::new(LongMax));
math::register_math_functions(self);
}
fn register_physics_functions(&mut self) {
physics::register_physics_functions(self);
use particle_charges::{
ChargeDownQuarkFunction, ChargeElectronFunction, ChargeMuonFunction,
ChargeNeutronFunction, ChargePositronFunction, ChargeProtonFunction, ChargeTauFunction,
ChargeUpQuarkFunction,
};
self.register(Box::new(ChargeElectronFunction));
self.register(Box::new(ChargeProtonFunction));
self.register(Box::new(ChargeNeutronFunction));
self.register(Box::new(ChargeUpQuarkFunction));
self.register(Box::new(ChargeDownQuarkFunction));
self.register(Box::new(ChargePositronFunction));
self.register(Box::new(ChargeMuonFunction));
self.register(Box::new(ChargeTauFunction));
}
fn register_date_time_functions(&mut self) {
date_time::register_date_time_functions(self);
}
fn register_financial_functions(&mut self) {
financial::register_financial_functions(self);
}
fn register_conversion_functions(&mut self) {
use convert::ConvertFunction;
use roman::{FromRoman, ToRoman};
self.register(Box::new(ConvertFunction));
self.register(Box::new(ToRoman));
self.register(Box::new(FromRoman));
}
fn register_statistical_functions(&mut self) {
use statistics::{
CorrelationFunction, KurtosisFunction, MedianFunction, ModeFunction,
PercentileFunction, SkewFunction, VarPopFunction, VarSampFunction, VarianceFunction,
};
self.register(Box::new(MedianFunction));
self.register(Box::new(PercentileFunction));
self.register(Box::new(ModeFunction));
self.register(Box::new(VarianceFunction));
self.register(Box::new(VarSampFunction));
self.register(Box::new(VarPopFunction));
self.register(Box::new(CorrelationFunction));
self.register(Box::new(SkewFunction));
self.register(Box::new(KurtosisFunction));
}
fn register_aggregate_functions(&mut self) {
use group_num::GroupNumFunction;
self.register(Box::new(GroupNumFunction::new()));
}
fn register_random_functions(&mut self) {
use random::{RandIntFunction, RandRangeFunction, RandomFunction};
self.register(Box::new(RandomFunction));
self.register(Box::new(RandIntFunction));
self.register(Box::new(RandRangeFunction));
}
fn register_format_functions(&mut self) {
use format::{
CenterFunction, FormatDateFunction, FormatNumberFunction, LPadFunction, RPadFunction,
};
use format_number::{FormatBytesFunction, FormatCurrencyFunction, RenderNumberFunction};
self.register(Box::new(FormatNumberFunction));
self.register(Box::new(FormatDateFunction));
self.register(Box::new(LPadFunction));
self.register(Box::new(RPadFunction));
self.register(Box::new(CenterFunction));
self.register(Box::new(RenderNumberFunction));
self.register(Box::new(FormatCurrencyFunction));
self.register(Box::new(FormatBytesFunction));
}
fn register_type_checking_functions(&mut self) {
use type_checking::{
IsBoolFunction, IsDateFunction, IsFloatFunction, IsIntegerFunction, IsNotNullFunction,
IsNullFunction, IsNumericFunction,
};
self.register(Box::new(IsDateFunction));
self.register(Box::new(IsBoolFunction));
self.register(Box::new(IsNumericFunction));
self.register(Box::new(IsIntegerFunction));
self.register(Box::new(IsFloatFunction));
self.register(Box::new(IsNullFunction));
self.register(Box::new(IsNotNullFunction));
}
fn register_utility_functions(&mut self) {
use utility::{
AsciiFunction, CharFunction, DecodeFunction, EncodeFunction, OrdFunction,
ToDecimalFunction, ToIntFunction, ToStringFunction, UnicodeFunction,
};
self.register(Box::new(AsciiFunction));
self.register(Box::new(OrdFunction));
self.register(Box::new(CharFunction));
self.register(Box::new(ToIntFunction));
self.register(Box::new(ToDecimalFunction));
self.register(Box::new(ToStringFunction));
self.register(Box::new(EncodeFunction));
self.register(Box::new(DecodeFunction));
self.register(Box::new(UnicodeFunction));
}
fn register_bigint_functions(&mut self) {
use bigint::{
BigAddFunction, BigFactorialFunction, BigIntFunction, BigMulFunction, BigPowFunction,
BitAndFunction, BitOrFunction, BitShiftFunction, BitXorFunction, FromBinaryFunction,
FromHexFunction, ToBinaryFunction, ToHexFunction,
};
self.register(Box::new(BigIntFunction));
self.register(Box::new(BigAddFunction));
self.register(Box::new(BigMulFunction));
self.register(Box::new(BigPowFunction));
self.register(Box::new(BigFactorialFunction));
self.register(Box::new(BitAndFunction));
self.register(Box::new(BitOrFunction));
self.register(Box::new(BitXorFunction));
self.register(Box::new(BitShiftFunction));
self.register(Box::new(ToBinaryFunction));
self.register(Box::new(FromBinaryFunction));
self.register(Box::new(ToHexFunction));
self.register(Box::new(FromHexFunction));
}
fn register_bitwise_functions(&mut self) {
bitwise::register_bitwise_functions(self);
self.register(Box::new(bitwise_string::BitAndStr));
self.register(Box::new(bitwise_string::BitOrStr));
self.register(Box::new(bitwise_string::BitXorStr));
self.register(Box::new(bitwise_string::BitNotStr));
self.register(Box::new(bitwise_string::BitFlip));
self.register(Box::new(bitwise_string::BitCount));
self.register(Box::new(bitwise_string::BitRotateLeft));
self.register(Box::new(bitwise_string::BitRotateRight));
self.register(Box::new(bitwise_string::BitShiftLeft));
self.register(Box::new(bitwise_string::BitShiftRight));
self.register(Box::new(bitwise_string::HammingDistance));
}
fn register_ansi_functions(&mut self) {
use ansi::{
AnsiBgFunction, AnsiBlinkFunction, AnsiBoldFunction, AnsiColorFunction,
AnsiItalicFunction, AnsiReverseFunction, AnsiRgbBgFunction, AnsiRgbFunction,
AnsiStrikethroughFunction, AnsiUnderlineFunction,
};
self.register(Box::new(AnsiColorFunction));
self.register(Box::new(AnsiBgFunction));
self.register(Box::new(AnsiRgbFunction));
self.register(Box::new(AnsiRgbBgFunction));
self.register(Box::new(AnsiBoldFunction));
self.register(Box::new(AnsiItalicFunction));
self.register(Box::new(AnsiUnderlineFunction));
self.register(Box::new(AnsiBlinkFunction));
self.register(Box::new(AnsiReverseFunction));
self.register(Box::new(AnsiStrikethroughFunction));
}
fn register_vector_functions(&mut self) {
use vector::{
ClosestPointOnLineFunction, LineIntersectFunction, LineReflectPointFunction,
PointLineDistanceFunction, SegmentIntersectFunction, VecAddFunction, VecAngleFunction,
VecCrossFunction, VecDistanceFunction, VecDotFunction, VecFunction, VecMagFunction,
VecNormalizeFunction, VecScaleFunction, VecSubFunction,
};
self.register(Box::new(VecFunction));
self.register(Box::new(VecAddFunction));
self.register(Box::new(VecSubFunction));
self.register(Box::new(VecScaleFunction));
self.register(Box::new(VecDotFunction));
self.register(Box::new(VecMagFunction));
self.register(Box::new(VecNormalizeFunction));
self.register(Box::new(VecDistanceFunction));
self.register(Box::new(VecCrossFunction));
self.register(Box::new(VecAngleFunction));
self.register(Box::new(LineIntersectFunction));
self.register(Box::new(SegmentIntersectFunction));
self.register(Box::new(ClosestPointOnLineFunction));
self.register(Box::new(PointLineDistanceFunction));
self.register(Box::new(LineReflectPointFunction));
}
}
impl Default for FunctionRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_registry_creation() {
let registry = FunctionRegistry::new();
assert!(registry.contains("PI"));
assert!(registry.contains("MASS_EARTH"));
assert!(registry.contains("ME"));
}
#[test]
fn test_case_insensitive_lookup() {
let registry = FunctionRegistry::new();
assert!(registry.get("pi").is_some());
assert!(registry.get("PI").is_some());
assert!(registry.get("Pi").is_some());
}
#[test]
fn test_autocomplete() {
let registry = FunctionRegistry::new();
let mass_functions = registry.autocomplete("MASS");
assert!(!mass_functions.is_empty());
let names: Vec<&str> = mass_functions.iter().map(|sig| sig.name).collect();
assert!(names.contains(&"MASS_EARTH"));
assert!(names.contains(&"MASS_SUN"));
}
}