use rustc_hash::FxHashMap;
use std::hash::Hash;
pub trait LogosIndex<I> {
type Output;
fn logos_get(&self, index: I) -> Self::Output;
}
pub trait LogosIndexMut<I>: LogosIndex<I> {
fn logos_set(&mut self, index: I, value: Self::Output);
}
impl<T: Clone> LogosIndex<i64> for Vec<T> {
type Output = T;
#[inline(always)]
fn logos_get(&self, index: i64) -> T {
if index < 1 {
panic!("Index {} is invalid: LOGOS uses 1-based indexing (minimum is 1)", index);
}
let idx = (index - 1) as usize;
if idx >= self.len() {
panic!("Index {} is out of bounds for seq of length {}", index, self.len());
}
unsafe { self.get_unchecked(idx).clone() }
}
}
impl<T: Clone> LogosIndexMut<i64> for Vec<T> {
#[inline(always)]
fn logos_set(&mut self, index: i64, value: T) {
if index < 1 {
panic!("Index {} is invalid: LOGOS uses 1-based indexing (minimum is 1)", index);
}
let idx = (index - 1) as usize;
if idx >= self.len() {
panic!("Index {} is out of bounds for seq of length {}", index, self.len());
}
unsafe { *self.get_unchecked_mut(idx) = value; }
}
}
impl<T: Clone> LogosIndex<i64> for [T] {
type Output = T;
#[inline(always)]
fn logos_get(&self, index: i64) -> T {
if index < 1 {
panic!("Index {} is invalid: LOGOS uses 1-based indexing (minimum is 1)", index);
}
let idx = (index - 1) as usize;
if idx >= self.len() {
panic!("Index {} is out of bounds for seq of length {}", index, self.len());
}
unsafe { self.get_unchecked(idx).clone() }
}
}
impl<T: Clone> LogosIndexMut<i64> for [T] {
#[inline(always)]
fn logos_set(&mut self, index: i64, value: T) {
if index < 1 {
panic!("Index {} is invalid: LOGOS uses 1-based indexing (minimum is 1)", index);
}
let idx = (index - 1) as usize;
if idx >= self.len() {
panic!("Index {} is out of bounds for seq of length {}", index, self.len());
}
unsafe { *self.get_unchecked_mut(idx) = value; }
}
}
impl<T: Clone> LogosIndex<i64> for &mut [T] {
type Output = T;
#[inline(always)]
fn logos_get(&self, index: i64) -> T {
<[T] as LogosIndex<i64>>::logos_get(self, index)
}
}
impl<T: Clone> LogosIndexMut<i64> for &mut [T] {
#[inline(always)]
fn logos_set(&mut self, index: i64, value: T) {
<[T] as LogosIndexMut<i64>>::logos_set(self, index, value)
}
}
impl LogosIndex<i64> for String {
type Output = String;
#[inline(always)]
fn logos_get(&self, index: i64) -> String {
if index < 1 {
panic!("Index {} is invalid: LOGOS uses 1-based indexing (minimum is 1)", index);
}
let idx = (index - 1) as usize;
match self.as_bytes().get(idx) {
Some(&b) if b.is_ascii() => {
String::from(b as char)
}
_ => {
self.chars().nth(idx)
.map(|c| c.to_string())
.unwrap_or_else(|| panic!("Index {} is out of bounds for text of length {}", index, self.chars().count()))
}
}
}
}
pub trait LogosGetChar {
fn logos_get_char(&self, index: i64) -> char;
}
impl LogosGetChar for String {
#[inline(always)]
fn logos_get_char(&self, index: i64) -> char {
if index < 1 {
panic!("Index {} is invalid: LOGOS uses 1-based indexing (minimum is 1)", index);
}
let idx = (index - 1) as usize;
match self.as_bytes().get(idx) {
Some(&b) if b.is_ascii() => b as char,
_ => {
self.chars().nth(idx)
.unwrap_or_else(|| panic!(
"Index {} is out of bounds for text of length {}",
index, self.chars().count()
))
}
}
}
}
impl<T: Clone> LogosIndex<i64> for crate::types::LogosSeq<T> {
type Output = T;
#[inline(always)]
fn logos_get(&self, index: i64) -> T {
let inner = self.borrow();
<Vec<T> as LogosIndex<i64>>::logos_get(&*inner, index)
}
}
impl<T: Clone> LogosIndexMut<i64> for crate::types::LogosSeq<T> {
#[inline(always)]
fn logos_set(&mut self, index: i64, value: T) {
let mut inner = self.borrow_mut();
<Vec<T> as LogosIndexMut<i64>>::logos_set(&mut *inner, index, value)
}
}
impl<K: Eq + Hash, V: Clone> LogosIndex<K> for crate::types::LogosMap<K, V> {
type Output = V;
#[inline(always)]
fn logos_get(&self, key: K) -> V {
let inner = self.borrow();
inner.get(&key).cloned().expect("Key not found in map")
}
}
impl<K: Eq + Hash, V: Clone> LogosIndexMut<K> for crate::types::LogosMap<K, V> {
#[inline(always)]
fn logos_set(&mut self, key: K, value: V) {
self.insert(key, value);
}
}
impl<V: Clone> LogosIndex<&str> for crate::types::LogosMap<String, V> {
type Output = V;
#[inline(always)]
fn logos_get(&self, key: &str) -> V {
let inner = self.borrow();
inner.get(key).cloned().expect("Key not found in map")
}
}
impl<V: Clone> LogosIndexMut<&str> for crate::types::LogosMap<String, V> {
#[inline(always)]
fn logos_set(&mut self, key: &str, value: V) {
self.insert(key.to_string(), value);
}
}
impl<K: Eq + Hash, V: Clone> LogosIndex<K> for FxHashMap<K, V> {
type Output = V;
#[inline(always)]
fn logos_get(&self, key: K) -> V {
self.get(&key).cloned().expect("Key not found in map")
}
}
impl<K: Eq + Hash, V: Clone> LogosIndexMut<K> for FxHashMap<K, V> {
#[inline(always)]
fn logos_set(&mut self, key: K, value: V) {
self.insert(key, value);
}
}
impl<V: Clone> LogosIndex<&str> for FxHashMap<String, V> {
type Output = V;
#[inline(always)]
fn logos_get(&self, key: &str) -> V {
self.get(key).cloned().expect("Key not found in map")
}
}
impl<V: Clone> LogosIndexMut<&str> for FxHashMap<String, V> {
#[inline(always)]
fn logos_set(&mut self, key: &str, value: V) {
self.insert(key.to_string(), value);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vec_1_based_indexing() {
let v = vec![10, 20, 30];
assert_eq!(LogosIndex::logos_get(&v, 1i64), 10);
assert_eq!(LogosIndex::logos_get(&v, 2i64), 20);
assert_eq!(LogosIndex::logos_get(&v, 3i64), 30);
}
#[test]
#[should_panic(expected = "1-based indexing")]
fn vec_zero_index_panics() {
let v = vec![10, 20, 30];
let _ = LogosIndex::logos_get(&v, 0i64);
}
#[test]
fn vec_set_1_based() {
let mut v = vec![10, 20, 30];
LogosIndexMut::logos_set(&mut v, 2i64, 99);
assert_eq!(v, vec![10, 99, 30]);
}
#[test]
fn hashmap_string_key() {
let mut m: FxHashMap<String, i64> = FxHashMap::default();
m.insert("iron".to_string(), 42);
assert_eq!(LogosIndex::logos_get(&m, "iron".to_string()), 42);
}
#[test]
fn hashmap_str_key() {
let mut m: FxHashMap<String, i64> = FxHashMap::default();
m.insert("iron".to_string(), 42);
assert_eq!(LogosIndex::logos_get(&m, "iron"), 42);
}
#[test]
fn hashmap_set_key() {
let mut m: FxHashMap<String, i64> = FxHashMap::default();
LogosIndexMut::logos_set(&mut m, "iron", 42i64);
assert_eq!(m.get("iron"), Some(&42));
}
}