use crate::error::SkillError;
#[derive(Debug, Clone, PartialEq)]
pub struct SkillEmbedding(Vec<f32>);
impl SkillEmbedding {
pub fn new(vec: Vec<f32>, expected_dim: usize) -> Result<Self, SkillError> {
if vec.len() != expected_dim {
return Err(SkillError::EmbeddingDimMismatch {
expected: expected_dim,
actual: vec.len(),
});
}
Ok(Self(vec))
}
#[must_use]
pub(crate) fn from_raw(vec: Vec<f32>) -> Self {
Self(vec)
}
#[must_use]
pub fn dim(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn into_inner(self) -> Vec<f32> {
self.0
}
}
impl AsRef<[f32]> for SkillEmbedding {
fn as_ref(&self) -> &[f32] {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_valid_dimension() {
let emb = SkillEmbedding::new(vec![1.0, 0.0, 0.0], 3).unwrap();
assert_eq!(emb.dim(), 3);
}
#[test]
fn new_dimension_mismatch() {
let err = SkillEmbedding::new(vec![1.0, 0.0], 3).unwrap_err();
assert!(matches!(
err,
SkillError::EmbeddingDimMismatch {
expected: 3,
actual: 2
}
));
}
#[test]
fn from_raw_any_dimension() {
let emb = SkillEmbedding::from_raw(vec![]);
assert_eq!(emb.dim(), 0);
let emb = SkillEmbedding::from_raw(vec![1.0; 1024]);
assert_eq!(emb.dim(), 1024);
}
#[test]
fn dim_accessor() {
assert_eq!(SkillEmbedding::from_raw(vec![0.0; 7]).dim(), 7);
}
#[test]
fn as_ref_returns_slice() {
let v = vec![1.0_f32, 2.0, 3.0];
let emb = SkillEmbedding::from_raw(v.clone());
assert_eq!(emb.as_ref(), v.as_slice());
}
#[test]
fn into_inner_returns_vec() {
let v = vec![0.5_f32, 1.0];
let emb = SkillEmbedding::from_raw(v.clone());
assert_eq!(emb.into_inner(), v);
}
#[test]
fn clone_preserves_data() {
let emb = SkillEmbedding::from_raw(vec![1.0, 2.0]);
assert_eq!(emb.clone(), emb);
}
#[test]
fn new_empty_dimension_zero() {
let emb = SkillEmbedding::new(vec![], 0).unwrap();
assert_eq!(emb.dim(), 0);
}
}