QEKHTVB7CH754NUMHJ3AKVGRNKW3KOAKMALS7B3ZNKCUEH6GP4HQC LLFG625ISXV7P2LUOFUMFIM5V5RJDKWCL47XX43X2CGILVAUQPVQC 5Y7ZXB53EMG34VZI5VQIZ77TZKBB4V6BGIILFZ5ZY73QYK4V2YHQC G5YNDTPHPYRZZIGWLX2ZLVFRJ3B2NGAPVESSMTO7YEABDFIIE66AC AV73DYWQ2UVZJYTN3UIW3TDMWNAETLXZRD7VHKTQLFQGHKJ5KI6QC HMOBTVJ4FEPZWMUV2JDPZYH3EFCW6ED5M6KKNKQJQZVKTDAKTVFQC YCWYAX6K2DJKT7FO4IAYL6HJOIJLYFKAPGLFJ5XMYSYAS42LP3FQC LPVC545KD6R5KNOTDPFDOD5FVA3KFBZARKVOLLXJXW3YK3RMNZKQC KUANIPWFDXDFKJ2LH4FQ6APYOPLNYJ5LVGLSBSC75WUUZPFHILCAC RNW6D77774CYWWM7JIFXI5TGKBOU6ADJIEZB5N2FXGDCTLUXEQZQC AVLXUT3ROXQ2PLLTB5XHPBY2BI5PQRRFJTG2GGZTL7K4VEZZXF3AC PQ4BG3ZJU5SY6XQDJ3SURLAOWGXGXLONIRZNUJXZVMHLYXWOORXQC pub async fn pick(db: &AsyncConnection, count: u16) -> DynResult<()> {
pub async fn pick(db: &AsyncConnection,count: u16,gather: Option<gather::Gender>,) -> DynResult<()> {let (ntx, mut nrx) = mpsc::channel(256);if let Some(gender) = gather {let tg = ntx.clone();let gdb = db.clone();tokio::spawn(async move {let mut incoming = gather::all_names(gender);while let Some(name) = incoming.recv().await {let (id, fresh) = match gdb.add_name(name.clone()).await {Ok(r) => r,Err(_) => break,};if fresh {match tg.send((name, id)).await {Ok(_) => (),Err(_) => break,}};}});}{let db = db.clone();tokio::spawn(async move {for name in db.list_names().await.ok().into_iter().flat_map(Vec::into_iter){match ntx.send(name).await {Ok(_) => (),Err(_) => break,}}});}let mut shortlist = Vec::with_capacity(count as usize * 2);for _ in 0..(count * 2) {if let Some(name) = nrx.recv().await {shortlist.push(name);} else {break;}}
let (mut input, done) = events();
terminal::enable_raw_mode()?;let (mut input, _done) = events();let mut comparator = CompareContext {db,events: &mut input,out: &mut stderr,needs_newline: false,};'sponge: loop {'fetch: while shortlist.len() < count as usize * 2 {match nrx.recv().await {Some(name) => {shortlist.push(name);}None => {break 'fetch;}}}if shortlist.len() < count.into() {break 'sponge;}let mut i: *mut (String, i64) = &mut shortlist[0];let j: *mut (String, i64) = {let len = shortlist.len() - 1;&mut shortlist[len]};let pivot: *mut (String, i64) = &mut shortlist[count as usize];while i < pivot {i = unsafe { comparator.partition(i, j, pivot).await? };}unsafe {shortlist.truncate(1 + i.offset_from(&shortlist[0]) as usize)};}
impl<'a, W: std::io::Write> CompareContext<'a, W> {async unsafe fn partition(&mut self,lo: *mut (String, i64),hi: *mut (String, i64),mut pivot: *mut (String, i64),) -> DynResult<*mut (String, i64)> {let mut i = lo.offset(-1);let mut j = hi.offset(1);loop {loop {i = i.offset(1);match self.compare(&*i, &*pivot).await? {std::cmp::Ordering::Less => (),_ => break,}}loop {j = j.offset(-1);match self.compare(&*j, &*pivot).await? {std::cmp::Ordering::Greater => (),_ => break,}}if i >= j {return Ok(j);} else {if pivot == i {pivot = j;} else if pivot == j {pivot = i;}i.swap(j);}}}
async fn compare(&mut self,a: &(String, i64),b: &(String, i64),) -> DynResult<std::cmp::Ordering> {let (a, b) = (a, b);match self.db.compare(a.1, b.1).await? {None => {if self.needs_newline {self.out.queue(cursor::MoveToNextLine(1))?;} else {self.needs_newline = true;}print_pair(self.out, a.0.borrow(), b.0.borrow())?;let (result, better, worse) = loop {if let Event::Key(key) =self.events.next().await.ok_or_else(|| {<std::io::ErrorKind as Into<std::io::Error>>::into(std::io::ErrorKind::BrokenPipe,)})??{match key.code {KeyCode::Left => {break (std::cmp::Ordering::Greater, a.1, b.1);}KeyCode::Right => {break (std::cmp::Ordering::Less, b.1, a.1);}KeyCode::Esc => {return Err(<std::io::ErrorKind as Into<std::io::Error,>>::into(std::io::ErrorKind::Interrupted).into());}KeyCode::Char('c') => {if key.modifiers.contains(crossterm::event::KeyModifiers::CONTROL,) {return Err(<std::io::ErrorKind as Into<std::io::Error,>>::into(std::io::ErrorKind::Interrupted,).into());}}_ => (),}}};let tdb = self.db.clone();tokio::spawn(async move {tdb.insert_preference(better, worse).await});Ok(result)}Some(c) => Ok(c),}}}
#[clap(subcommand)]command: Commands,}#[derive(Debug, Subcommand)]enum Commands {Gather {#[clap(arg_enum)]gender: gather::Gender,},Pick {count: u16,},
count: u16,#[clap(long, arg_enum)]gather: Option<gather::Gender>,
args.command.run(&db).await}impl Commands {async fn run(&self, db: &AsyncConnection) -> DynResult<()> {match self {Self::Gather { gender } => {let mut incoming = gather::all_names(*gender);while let Some(name) = incoming.recv().await {db.add_name(name).await?;}}Self::Pick { count } => {pick::pick(db, *count).await?;}
match pick::pick(&db, args.count, args.gather).await {Ok(r) => Ok(r),Err(e) => {use crossterm::ExecutableCommand;let mut stderr = std::io::stderr();stderr.execute(crossterm::cursor::Show).ok();crossterm::terminal::disable_raw_mode().ok();Err(e)