-
Notifications
You must be signed in to change notification settings - Fork 0
Closed
Description
Implement standard Rust traits to improve API ergonomics and Rust ecosystem integration.
Objectives
- Implement Clone, PartialEq, Eq, Hash traits
- Add FromIterator and IntoIterator
- Implement Index and IndexMut
- Add AsRef and Deref traits
- Improve API usability
Traits to Implement
1. Clone
impl Clone for CStringArray {
fn clone(&self) -> Self {
Self::from_cstrings(self.strings.clone())
.expect("clone from non-empty array")
}
}Use cases:
let arr1 = CStringArray::new(vec!["a".to_string()]).unwrap();
let arr2 = arr1.clone();2. PartialEq + Eq
impl PartialEq for CStringArray {
fn eq(&self, other: &Self) -> bool {
self.strings == other.strings
}
}
impl Eq for CStringArray {}Use cases:
let arr1 = CStringArray::new(vec!["a".to_string()]).unwrap();
let arr2 = CStringArray::new(vec!["a".to_string()]).unwrap();
assert_eq!(arr1, arr2);3. Hash
impl Hash for CStringArray {
fn hash<H: Hasher>(&self, state: &mut H) {
self.strings.hash(state);
}
}Use cases:
let mut map = HashMap::new();
let arr = CStringArray::new(vec!["key".to_string()]).unwrap();
map.insert(arr, "value");4. FromIterator
impl FromIterator<String> for CStringArray {
fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
let strings: Vec<String> = iter.collect();
Self::new(strings).expect("FromIterator from non-empty iterator")
}
}
impl FromIterator<CString> for CStringArray {
fn from_iter<I: IntoIterator<Item = CString>>(iter: I) -> Self {
let strings: Vec<CString> = iter.collect();
Self::from_cstrings(strings).expect("FromIterator from non-empty iterator")
}
}Use cases:
let arr: CStringArray = vec!["a", "b", "c"]
.into_iter()
.map(String::from)
.collect();5. IntoIterator
impl IntoIterator for CStringArray {
type Item = CString;
type IntoIter = std::vec::IntoIter<CString>;
fn into_iter(self) -> Self::IntoIter {
self.strings.into_iter()
}
}
impl<'a> IntoIterator for &'a CStringArray {
type Item = &'a CString;
type IntoIter = std::slice::Iter<'a, CString>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}Use cases:
let arr = CStringArray::new(vec!["a".to_string()]).unwrap();
for s in &arr {
println!("{}", s.to_str().unwrap());
}
for s in arr {
println!("{}", s.to_str().unwrap());
}6. Index
impl Index<usize> for CStringArray {
type Output = CString;
fn index(&self, index: usize) -> &Self::Output {
&self.strings[index]
}
}Use cases:
let arr = CStringArray::new(vec!["a".to_string()]).unwrap();
let first = &arr[0];7. AsRef
impl AsRef<[CString]> for CStringArray {
fn as_ref(&self) -> &[CString] {
&self.strings
}
}Use cases:
fn process_strings(strings: &[CString]) { }
let arr = CStringArray::new(vec!["a".to_string()]).unwrap();
process_strings(arr.as_ref());8. Default (optional)
Note: Current API doesn't allow empty arrays. Could add a separate EmptyCStringArray type or relax constraint.
Implementation Plan
1. Add trait implementations to src/traits.rs
Create organized sections:
// Comparison traits
impl PartialEq for CStringArray { }
impl Eq for CStringArray {}
impl Hash for CStringArray { }
// Clone trait
impl Clone for CStringArray { }
// Iterator traits
impl FromIterator<String> for CStringArray { }
impl FromIterator<CString> for CStringArray { }
impl IntoIterator for CStringArray { }
impl<'a> IntoIterator for &'a CStringArray { }
// Indexing traits
impl Index<usize> for CStringArray { }
// Conversion traits
impl AsRef<[CString]> for CStringArray { }2. Add comprehensive tests
#[test]
fn test_clone() {
let arr1 = CStringArray::new(vec!["a".to_string()]).unwrap();
let arr2 = arr1.clone();
assert_eq!(arr1, arr2);
assert_ne!(arr1.as_ptr(), arr2.as_ptr());
}
#[test]
fn test_equality() {
let arr1 = CStringArray::new(vec!["a".to_string()]).unwrap();
let arr2 = CStringArray::new(vec!["a".to_string()]).unwrap();
let arr3 = CStringArray::new(vec!["b".to_string()]).unwrap();
assert_eq!(arr1, arr2);
assert_ne!(arr1, arr3);
}
#[test]
fn test_hash() {
let mut map = HashMap::new();
let arr = CStringArray::new(vec!["key".to_string()]).unwrap();
map.insert(arr.clone(), "value");
assert_eq!(map.get(&arr), Some(&"value"));
}
#[test]
fn test_from_iterator() {
let arr: CStringArray = vec!["a", "b", "c"]
.into_iter()
.map(String::from)
.collect();
assert_eq!(arr.len(), 3);
}
#[test]
fn test_into_iterator() {
let arr = CStringArray::new(vec!["a".to_string()]).unwrap();
let collected: Vec<_> = arr.into_iter().collect();
assert_eq!(collected.len(), 1);
}
#[test]
fn test_index() {
let arr = CStringArray::new(vec!["a".to_string(), "b".to_string()]).unwrap();
assert_eq!(arr[0].to_str().unwrap(), "a");
assert_eq!(arr[1].to_str().unwrap(), "b");
}
#[test]
#[should_panic]
fn test_index_out_of_bounds() {
let arr = CStringArray::new(vec!["a".to_string()]).unwrap();
let _ = &arr[10];
}
#[test]
fn test_as_ref() {
let arr = CStringArray::new(vec!["a".to_string()]).unwrap();
let slice: &[CString] = arr.as_ref();
assert_eq!(slice.len(), 1);
}3. Update documentation
Add examples to lib.rs:
/// # Trait Implementations
///
/// ## Cloning
/// ```
/// let arr1 = CStringArray::new(vec!["a".to_string()]).unwrap();
/// let arr2 = arr1.clone();
/// ```
///
/// ## Equality
/// ```
/// let arr1 = CStringArray::new(vec!["a".to_string()]).unwrap();
/// let arr2 = CStringArray::new(vec!["a".to_string()]).unwrap();
/// assert_eq!(arr1, arr2);
/// ```
Benefits
- Ergonomics: More idiomatic Rust API
- Integration: Works with standard library collections
- Usability: Indexing with [] instead of get()
- Iteration: for loops without calling iter()
- Comparison: Can use in HashMaps, BTreeSets
- Professional: Follows Rust API guidelines
Breaking Changes
None - all additions are backward compatible.
Success Criteria
- All 8 trait implementations completed
- Comprehensive test coverage
- Documentation with examples
- No clippy warnings
- All existing tests pass
- REUSE 3.3 compliant
References
- Rust API Guidelines: https://rust-lang.github.io/api-guidelines/
- Standard Library Traits: https://doc.rust-lang.org/std/
- Common Rust Traits: https://stevedonovan.github.io/rustifications/2018/09/08/common-rust-traits.html
Metadata
Metadata
Assignees
Labels
No labels