use crate::error::{Result, SklearsError};
pub mod stable {
pub use crate::traits::{
Estimator, Fit, FitPredict, FitTransform, PartialFit, Predict, Transform,
};
pub use crate::types::{
Array1, Array2, ArrayView1, ArrayView2, ArrayViewMut1, ArrayViewMut2, FeatureCount,
Features, Float, FloatBounds, Int, IntBounds, Labels, Numeric, Predictions, Probabilities,
Probability, SampleCount, Target,
};
pub use crate::error::{ErrorChain, ErrorContext, Result, SklearsError};
pub use crate::validation::{Validate, ValidationContext, ValidationRule};
pub use crate::dataset::{load_iris, make_blobs, make_regression, Dataset};
}
pub mod experimental {
pub use crate::async_traits::*;
pub use crate::traits::gat_traits::*;
pub use crate::traits::specialized::*;
pub use crate::traits::streaming::*;
pub use crate::plugin::{
AlgorithmPlugin, ClusteringPlugin, Plugin, PluginConfig, PluginMetadata, PluginRegistry,
TransformerPlugin,
};
pub use crate::parallel::{
ParallelConfig, ParallelCrossValidation, ParallelFit, ParallelPredict, ParallelTransform,
};
#[cfg(feature = "simd")]
pub use crate::simd::{SimdArrayOps, SimdOps};
#[cfg(feature = "arrow")]
pub use crate::arrow::{ArrowDataset, ColumnStats};
}
pub mod deprecated {
#[deprecated(since = "0.1.0", note = "Use the new Plugin system instead")]
pub fn old_plugin_system() {
}
}
pub trait StableApi {
const STABLE_SINCE: &'static str;
const HAS_EXPERIMENTAL_FEATURES: bool = false;
}
pub trait ExperimentalApi {
const INTRODUCED_IN: &'static str;
const STABILIZATION_TARGET: Option<&'static str> = None;
const KNOWN_LIMITATIONS: &'static [&'static str] = &[];
}
pub struct ApiVersionInfo {
pub core_version: &'static str,
pub min_supported_version: &'static str,
pub breaking_changes: &'static [BreakingChange],
}
#[derive(Debug, Clone)]
pub struct BreakingChange {
pub version: &'static str,
pub description: &'static str,
pub migration: Option<&'static str>,
}
pub fn api_version_info() -> ApiVersionInfo {
ApiVersionInfo {
core_version: "0.1.0",
min_supported_version: "0.1.0",
breaking_changes: &[
],
}
}
#[derive(Debug, Clone)]
pub struct PublicApiConfig {
pub enable_experimental: bool,
pub warn_deprecated: bool,
pub strict_compatibility: bool,
}
impl Default for PublicApiConfig {
fn default() -> Self {
Self {
enable_experimental: false,
warn_deprecated: true,
strict_compatibility: true,
}
}
}
pub struct PublicApiConfigBuilder {
config: PublicApiConfig,
}
impl PublicApiConfigBuilder {
pub fn new() -> Self {
Self {
config: PublicApiConfig::default(),
}
}
pub fn enable_experimental(mut self, enable: bool) -> Self {
self.config.enable_experimental = enable;
self
}
pub fn warn_deprecated(mut self, warn: bool) -> Self {
self.config.warn_deprecated = warn;
self
}
pub fn strict_compatibility(mut self, strict: bool) -> Self {
self.config.strict_compatibility = strict;
self
}
pub fn build(self) -> PublicApiConfig {
self.config
}
}
impl Default for PublicApiConfigBuilder {
fn default() -> Self {
Self::new()
}
}
impl<T: crate::traits::Estimator<crate::traits::Untrained>> StableApi for T {
const STABLE_SINCE: &'static str = "0.1.0";
}
impl<X, Output> StableApi for dyn crate::traits::Predict<X, Output> {
const STABLE_SINCE: &'static str = "0.1.0";
}
impl<X, Output> StableApi for dyn crate::traits::Transform<X, Output> {
const STABLE_SINCE: &'static str = "0.1.0";
}
impl StableApi for crate::error::SklearsError {
const STABLE_SINCE: &'static str = "0.1.0";
}
impl StableApi for crate::dataset::Dataset {
const STABLE_SINCE: &'static str = "0.1.0";
}
impl ExperimentalApi for crate::plugin::PluginRegistry {
const INTRODUCED_IN: &'static str = "0.1.0";
const STABILIZATION_TARGET: Option<&'static str> = Some("0.2.0");
const KNOWN_LIMITATIONS: &'static [&'static str] = &[
"Plugin unloading may not clean up all resources",
"Dynamic loading requires platform-specific libraries",
];
}
#[cfg(feature = "simd")]
impl ExperimentalApi for crate::simd::SimdOps {
const INTRODUCED_IN: &'static str = "0.1.0";
const STABILIZATION_TARGET: Option<&'static str> = Some("0.3.0");
const KNOWN_LIMITATIONS: &'static [&'static str] = &[
"SIMD operations may not be available on all platforms",
"Performance benefits vary by CPU architecture",
];
}
pub fn is_api_stable<T: StableApi>() -> bool {
true }
pub fn is_api_experimental<T: ExperimentalApi>() -> bool {
true }
pub fn get_api_stability<T>() -> ApiStability
where
T: 'static,
{
let _type_id = std::any::TypeId::of::<T>();
ApiStability::Unknown
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ApiStability {
Stable,
Experimental,
Deprecated,
Unknown,
}
pub fn validate_experimental_usage<T: ExperimentalApi>(config: &PublicApiConfig) -> Result<()> {
if !config.enable_experimental {
return Err(SklearsError::InvalidOperation(format!(
"Experimental API {} requires enable_experimental = true. \
This API was introduced in version {} and may change without notice.",
std::any::type_name::<T>(),
T::INTRODUCED_IN
)));
}
Ok(())
}
pub fn warn_if_deprecated<T>(config: &PublicApiConfig, api_name: &str) {
if config.warn_deprecated {
eprintln!(
"Warning: API {api_name} is deprecated and will be removed in a future version. \
Please update your code to use the recommended alternative."
);
}
}
#[allow(non_snake_case)]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_version_info() {
let info = api_version_info();
assert_eq!(info.core_version, "0.1.0");
assert_eq!(info.min_supported_version, "0.1.0");
}
#[test]
fn test_public_api_config() {
let config = PublicApiConfigBuilder::new()
.enable_experimental(true)
.warn_deprecated(false)
.strict_compatibility(false)
.build();
assert!(config.enable_experimental);
assert!(!config.warn_deprecated);
assert!(!config.strict_compatibility);
}
#[test]
fn test_api_stability_traits() {
assert!(is_api_stable::<crate::error::SklearsError>());
assert!(is_api_experimental::<crate::plugin::PluginRegistry>());
}
#[test]
fn test_experimental_validation() {
let config_disabled = PublicApiConfig {
enable_experimental: false,
..Default::default()
};
let config_enabled = PublicApiConfig {
enable_experimental: true,
..Default::default()
};
assert!(
validate_experimental_usage::<crate::plugin::PluginRegistry>(&config_disabled).is_err()
);
assert!(
validate_experimental_usage::<crate::plugin::PluginRegistry>(&config_enabled).is_ok()
);
}
#[test]
fn test_api_stability_enum() {
assert_eq!(ApiStability::Stable, ApiStability::Stable);
assert_ne!(ApiStability::Stable, ApiStability::Experimental);
}
}