Decorate-sort-undecorate: applies key fn to each item, sorts by resulting keys, returns reordered items. */
(&mut self, items: Vec<Val>, key: Val, chunk: &crate::modules::parser::SSAChunk, slots: &mut [Val])
| 134 | |
| 135 | /* Decorate-sort-undecorate: applies key fn to each item, sorts by resulting keys, returns reordered items. */ |
| 136 | fn sort_by_key(&mut self, items: Vec<Val>, key: Val, chunk: &crate::modules::parser::SSAChunk, slots: &mut [Val]) -> Result<Vec<Val>, VmErr> { |
| 137 | let mut keys: Vec<Val> = Vec::with_capacity(items.len()); |
| 138 | for &item in &items { |
| 139 | self.push(key); |
| 140 | self.push(item); |
| 141 | self.exec_call(1, chunk, slots)?; |
| 142 | keys.push(self.pop()?); |
| 143 | } |
| 144 | let roots_base = self.temp_roots.len(); |
| 145 | for &v in keys.iter().chain(items.iter()) { self.temp_roots.push(v); } |
| 146 | let mut sort_err: Option<VmErr> = None; |
| 147 | let order = Self::stable_sort_indices(items.len(), |a, b| { |
| 148 | if sort_err.is_some() { return core::cmp::Ordering::Equal; } |
| 149 | match self.sort_lt(keys[a], keys[b], chunk, slots) { |
| 150 | Ok(true) => core::cmp::Ordering::Less, |
| 151 | Ok(false) => match self.sort_lt(keys[b], keys[a], chunk, slots) { |
| 152 | Ok(true) => core::cmp::Ordering::Greater, |
| 153 | Ok(false) => core::cmp::Ordering::Equal, |
| 154 | Err(e) => { sort_err = Some(e); core::cmp::Ordering::Equal } |
| 155 | }, |
| 156 | Err(e) => { sort_err = Some(e); core::cmp::Ordering::Equal } |
| 157 | } |
| 158 | }); |
| 159 | self.temp_roots.truncate(roots_base); |
| 160 | if let Some(e) = sort_err { return Err(e); } |
| 161 | Ok(order.into_iter().map(|i| items[i]).collect()) |
| 162 | } |
| 163 | |
| 164 | // a < b via __lt__ when either side defines it, else the built-in comparison. |
| 165 | pub(crate) fn sort_lt(&mut self, a: Val, b: Val, chunk: &SSAChunk, slots: &mut [Val]) -> Result<bool, VmErr> { |