Get most things semi-working except the final sort
[?]
Jan 16, 2022, 4:02 AM
QEKHTVB7CH754NUMHJ3AKVGRNKW3KOAKMALS7B3ZNKCUEH6GP4HQCDependencies
- [2]
LLFG625IShould be all the database functions I need - [3]
HMOBTVJ4Initialize crate and add expected dependencies - [4]
AV73DYWQInitial functions for using sqlite in async environment - [5]
5Y7ZXB53Start picker UI - [6]
C376NCOVPrevent flooding the website (still need to better mimic browser requests) - [7]
G5YNDTPHCargo clippy - [8]
LPVC545KGet the scraper part of this program working - [9]
AVLXUT3RMake the boxed errors Send - [10]
RNW6D777Minor tidy - [11]
KUANIPWFAdd function for adding name to database - [12]
YCWYAX6KFunctions for scraping names integrated enough to test (they don't work yet) - [*]
PQ4BG3ZJThe web scrape functions
Change contents
- edit in src/pick.rs at line 1
use crate::gather; - replacement in src/pick.rs at line 6
event::{Event, EventStream},event::{Event, EventStream, KeyCode}, - replacement in src/pick.rs at line 8
ExecutableCommand, QueueableCommand,terminal, ExecutableCommand, QueueableCommand, - replacement in src/pick.rs at line 10
use futures::stream::{self, Stream, StreamExt};use futures::stream::{self, StreamExt};use std::borrow::Borrow;use tokio::sync::mpsc; - replacement in src/pick.rs at line 14
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;}} - replacement in src/pick.rs at line 66
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)};} - edit in src/pick.rs at line 102
terminal::disable_raw_mode()?; - edit in src/pick.rs at line 104
}struct CompareContext<'a, W> {db: &'a AsyncConnection,events: &'a mut stream::Abortable<EventStream>,out: &'a mut W,needs_newline: bool, - edit in src/pick.rs at line 112
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);}}} - edit in src/pick.rs at line 150
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),}}} - replacement in src/names_database.rs at line 131
async fn insert_preference(pub async fn insert_preference( - replacement in src/main.rs at line 1
use clap::{Parser, Subcommand};use clap::Parser; - edit in src/main.rs at line 6
use names_database::AsyncConnection; - replacement in src/main.rs at line 14[3.166]→[3.166:216](∅→∅),[3.216]→[3.0:29](∅→∅),[3.29]→[3.244:331](∅→∅),[3.244]→[3.244:331](∅→∅),[3.331]→[3.30:37](∅→∅),[3.37]→[3.988:1019](∅→∅),[3.1019]→[3.121:128](∅→∅)
#[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>, - replacement in src/main.rs at line 23[3.112]→[3.395:427](∅→∅),[3.1398]→[3.395:427](∅→∅),[3.427]→[3.1399:1402](∅→∅),[3.466]→[3.1399:1402](∅→∅),[3.1402]→[3.428:444](∅→∅),[3.444]→[3.345:410](∅→∅),[3.226]→[3.1548:1569](∅→∅),[3.410]→[3.1548:1569](∅→∅),[3.534]→[3.1548:1569](∅→∅),[3.1548]→[3.1548:1569](∅→∅),[3.1569]→[3.227:268](∅→∅),[3.268]→[3.575:779](∅→∅),[3.575]→[3.575:779](∅→∅),[3.779]→[2.5272:5371](∅→∅)
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) - replacement in src/main.rs at line 32
Ok(())}}?;Ok(()) - edit in src/gather.rs at line 28
dbg!(fetch.current_letter, &fetch.form);