use core::cell::Ref;
use core::cmp::Reverse;
use satellite_bitcoin::generic::fixed_list::FixedList;
use satellite_bitcoin::generic::fixed_list_unchecked::FixedRefList;
use satellite_lang::prelude::Owner;
use satellite_lang::ZeroCopy;
use super::error::StateShardError;
use super::shard_indices::IntoShardIndices;
pub fn select_with<T, S, const MAX_TOTAL_SHARDS: usize, const MAX_SELECTED_SHARDS: usize>(
shards: &FixedRefList<Ref<S>, MAX_TOTAL_SHARDS>,
spec: T,
) -> super::error::Result<FixedList<usize, MAX_SELECTED_SHARDS>>
where
T: IntoShardIndices<MAX_SELECTED_SHARDS>,
S: ZeroCopy + Owner,
{
let indexes = spec
.into_indices()
.map_err(|_| StateShardError::TooManyShardsSelected)?;
let mut selected = FixedList::new();
for &idx in indexes.as_slice() {
if idx >= shards.len() {
return Err(StateShardError::OutOfBounds.into());
}
if selected.iter().any(|&existing| existing == idx) {
return Err(StateShardError::DuplicateShardSelection.into());
}
selected
.push(idx)
.map_err(|_| StateShardError::TooManyShardsSelected)?;
}
Ok(selected)
}
pub fn select_min_by<F, S, const MAX_TOTAL_SHARDS: usize>(
shards: &FixedRefList<Ref<S>, MAX_TOTAL_SHARDS>,
key_fn: F,
) -> super::error::Result<Option<usize>>
where
F: Fn(&S) -> u128,
S: ZeroCopy + Owner,
{
if shards.is_empty() {
return Ok(None);
}
let mut best_idx: Option<usize> = None;
let mut best_key: u128 = u128::MAX;
for (idx, shard_ref) in shards.iter().enumerate() {
let key = key_fn(&*shard_ref);
if key < best_key {
best_key = key;
best_idx = Some(idx);
}
}
Ok(best_idx)
}
pub fn select_max_by<F, S, const MAX_TOTAL_SHARDS: usize>(
shards: &FixedRefList<Ref<S>, MAX_TOTAL_SHARDS>,
key_fn: F,
) -> super::error::Result<Option<usize>>
where
F: Fn(&S) -> u64,
S: ZeroCopy + Owner,
{
if shards.is_empty() {
return Ok(None);
}
let mut best_idx: Option<usize> = None;
let mut best_key: u64 = 0;
for (idx, shard_ref) in shards.iter().enumerate() {
let key = key_fn(&*shard_ref);
if key > best_key {
best_key = key;
best_idx = Some(idx);
}
}
Ok(best_idx)
}
pub fn select_multiple_by<P, S, const MAX_TOTAL_SHARDS: usize, const MAX_SELECTED_SHARDS: usize>(
shards: &FixedRefList<Ref<S>, MAX_TOTAL_SHARDS>,
predicate: P,
) -> super::error::Result<FixedList<usize, MAX_SELECTED_SHARDS>>
where
P: Fn(&S) -> bool,
S: ZeroCopy + Owner,
{
let mut indices = Vec::new();
for (idx, shard_ref) in shards.iter().enumerate() {
if predicate(&*shard_ref) {
indices.push(idx);
}
}
select_with(shards, indices)
}
pub fn select_multiple_sorted<
K,
P,
S,
const MAX_TOTAL_SHARDS: usize,
const MAX_SELECTED_SHARDS: usize,
>(
shards: &FixedRefList<Ref<S>, MAX_TOTAL_SHARDS>,
key_fn: K,
predicate: P,
) -> super::error::Result<FixedList<usize, MAX_SELECTED_SHARDS>>
where
K: Fn(&S) -> u64,
P: Fn(u64) -> bool,
S: ZeroCopy + Owner,
{
let mut indices: Vec<usize> = (0..shards.len()).collect();
indices.sort_by_key(|&i| {
let key = key_fn(&*shards.get(i).unwrap());
Reverse(key)
});
let mut selected = Vec::new();
let mut accumulated: u64 = 0;
for &idx in &indices {
accumulated += key_fn(&*shards.get(idx).unwrap());
selected.push(idx);
if predicate(accumulated) {
return select_with(shards, selected);
}
}
select_with(shards, indices)
}