Add normalize on formating

This commit is contained in:
2023-05-28 02:25:48 +02:00
parent 65299c067a
commit 06feabbdce
6 changed files with 161 additions and 62 deletions

View File

@@ -168,7 +168,7 @@ where
let total_pages = items_page.total_pages; let total_pages = items_page.total_pages;
let footer = format!("\n\nСтраница 1/{total_pages}"); let footer = format!("\n\nСтраница 1/{total_pages}");
let formated_items = items_page.format_items((4096 - footer.len()).try_into().unwrap()); let formated_items = items_page.format_items(4096 - footer.len());
let message_text = format!("{formated_items}{footer}"); let message_text = format!("{formated_items}{footer}");
@@ -260,7 +260,7 @@ where
let total_pages = items_page.total_pages; let total_pages = items_page.total_pages;
let footer = format!("\n\nСтраница {page}/{total_pages}"); let footer = format!("\n\nСтраница {page}/{total_pages}");
let formated_items = items_page.format_items((4096 - footer.len()).try_into().unwrap()); let formated_items = items_page.format_items(4096 - footer.len());
let message_text = format!("{formated_items}{footer}"); let message_text = format!("{formated_items}{footer}");

View File

@@ -137,7 +137,7 @@ where
}, },
}; };
let item_message = item.format(4096); let item_message = item.format(4096).result;
bot.send_message(cq.from.id, item_message) bot.send_message(cq.from.id, item_message)
.reply_markup(InlineKeyboardMarkup { .reply_markup(InlineKeyboardMarkup {

View File

@@ -191,7 +191,7 @@ where
let total_pages = items_page.total_pages; let total_pages = items_page.total_pages;
let footer = format!("\n\nСтраница {page}/{total_pages}"); let footer = format!("\n\nСтраница {page}/{total_pages}");
let formated_items = items_page.format_items((4096 - footer.len()).try_into().unwrap()); let formated_items = items_page.format_items(4096 - footer.len());
let message_text = format!("{formated_items}{footer}"); let message_text = format!("{formated_items}{footer}");

View File

@@ -177,7 +177,7 @@ async fn update_log_pagination_handler(
let total_pages = items_page.total_pages; let total_pages = items_page.total_pages;
let footer = format!("\n\nСтраница {page}/{total_pages}"); let footer = format!("\n\nСтраница {page}/{total_pages}");
let formated_items = items_page.format_items((4096 - footer.len()).try_into().unwrap()); let formated_items = items_page.format_items(4096 - footer.len());
let message_text = format!("{header}{formated_items}{footer}"); let message_text = format!("{header}{formated_items}{footer}");

View File

@@ -7,10 +7,18 @@ use super::types::{
TranslatorBook, TranslatorBook,
}; };
const NO_LIMIT: u32 = 4096; const NO_LIMIT: usize = 4096;
#[derive(Clone)]
pub struct FormatResult {
pub result: String,
pub current_size: usize,
pub max_size: usize,
}
pub trait Format { pub trait Format {
fn format(&self, max_size: u32) -> String; fn format(&self, max_size: usize) -> FormatResult;
} }
pub trait FormatInline { pub trait FormatInline {
@@ -51,8 +59,8 @@ fn format_authors(authors: Vec<BookAuthor>, count: usize) -> String {
match !authors.is_empty() { match !authors.is_empty() {
true => { true => {
let formated_authors = authors.clone()[..min(count, authors.len())] let formated_authors = authors[..min(count, authors.len())]
.into_iter() .iter()
.map(|author| author.format_inline()) .map(|author| author.format_inline())
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
@@ -71,8 +79,8 @@ fn format_translators(translators: Vec<Translator>, count: usize) -> String {
match !translators.is_empty() { match !translators.is_empty() {
true => { true => {
let formated_translators = translators.clone()[..min(count, translators.len())] let formated_translators = translators[..min(count, translators.len())]
.into_iter() .iter()
.map(|translator| translator.format_inline()) .map(|translator| translator.format_inline())
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
@@ -91,9 +99,9 @@ fn format_sequences(sequences: Vec<Sequence>, count: usize) -> String {
match !sequences.is_empty() { match !sequences.is_empty() {
true => { true => {
let formated_sequences: String = sequences.clone()[..min(count, sequences.len())] let formated_sequences: String = sequences[..min(count, sequences.len())]
.into_iter() .iter()
.map(|sequence| sequence.format(NO_LIMIT)) .map(|sequence| sequence.format(NO_LIMIT).result)
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
@@ -111,8 +119,8 @@ fn format_genres(genres: Vec<BookGenre>, count: usize) -> String {
match !genres.is_empty() { match !genres.is_empty() {
true => { true => {
let formated_genres: String = genres.clone()[..min(count, genres.len())] let formated_genres: String = genres[..min(count, genres.len())]
.into_iter() .iter()
.map(|genre| genre.format()) .map(|genre| genre.format())
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
@@ -125,7 +133,7 @@ fn format_genres(genres: Vec<BookGenre>, count: usize) -> String {
} }
impl Format for Author { impl Format for Author {
fn format(&self, _max_size: u32) -> String { fn format(&self, _max_size: usize) -> FormatResult {
let Author { let Author {
id, id,
last_name, last_name,
@@ -141,23 +149,37 @@ impl Format for Author {
false => "".to_string(), false => "".to_string(),
}; };
format!("{title}{link}{annotation}") let result = format!("{title}{link}{annotation}");
let result_len = result.len();
FormatResult {
result,
current_size: result_len,
max_size: result_len
}
} }
} }
impl Format for Sequence { impl Format for Sequence {
fn format(&self, _max_size: u32) -> String { fn format(&self, _max_size: usize) -> FormatResult {
let Sequence { id, name, .. } = self; let Sequence { id, name, .. } = self;
let title = format!("📚 {name}"); let title = format!("📚 {name}");
let link = format!("/s_{id}"); let link = format!("/s_{id}");
format!("{title} {link}") let result = format!("{title} {link}");
let result_len = result.len();
FormatResult {
result,
current_size: result_len,
max_size: result_len
}
} }
} }
impl Format for Translator { impl Format for Translator {
fn format(&self, _max_size: u32) -> String { fn format(&self, _max_size: usize) -> FormatResult {
let Translator { let Translator {
id, id,
last_name, last_name,
@@ -173,7 +195,14 @@ impl Format for Translator {
false => "".to_string(), false => "".to_string(),
}; };
format!("{title}{link}{annotation}") let result = format!("{title}{link}{annotation}");
let result_len = result.len();
FormatResult {
result,
current_size: result_len,
max_size: result_len
}
} }
} }
@@ -254,18 +283,30 @@ struct FormatVectorsResult {
translators: String, translators: String,
sequences: String, sequences: String,
genres: String, genres: String,
max_result_size: usize,
} }
impl FormatVectorsResult { impl FormatVectorsResult {
fn len(&self) -> usize { fn len(&self) -> usize {
self.authors.len() + self.translators.len() + self.sequences.len() + self.genres.len() self.authors.len() + self.translators.len() + self.sequences.len() + self.genres.len()
} }
fn with_max_result_size(self, max_result_size: usize) -> Self {
let Self { authors, translators, sequences, genres, .. } = self;
Self {
authors,
translators,
sequences,
genres,
max_result_size
}
}
} }
impl Book { impl Book {
fn format_vectors(&self, max_size: u32) -> FormatVectorsResult { fn format_vectors(&self, max_size: usize) -> FormatVectorsResult {
let max_size_u: usize = max_size.try_into().unwrap();
let mut counts = FormatVectorsCounts { let mut counts = FormatVectorsCounts {
authors: self.authors.len(), authors: self.authors.len(),
translators: self.translators.len(), translators: self.translators.len(),
@@ -278,9 +319,12 @@ impl Book {
translators: format_translators(self.translators.clone(), counts.translators), translators: format_translators(self.translators.clone(), counts.translators),
sequences: format_sequences(self.sequences.clone(), counts.sequences), sequences: format_sequences(self.sequences.clone(), counts.sequences),
genres: format_genres(self.genres.clone(), counts.genres), genres: format_genres(self.genres.clone(), counts.genres),
max_result_size: 0
}; };
while result.len() > max_size_u && counts.can_sub() { let max_result_size = result.len();
while result.len() > max_size && counts.can_sub() {
counts = counts.sub(); counts = counts.sub();
result = FormatVectorsResult { result = FormatVectorsResult {
@@ -288,15 +332,16 @@ impl Book {
translators: format_translators(self.translators.clone(), counts.translators), translators: format_translators(self.translators.clone(), counts.translators),
sequences: format_sequences(self.sequences.clone(), counts.sequences), sequences: format_sequences(self.sequences.clone(), counts.sequences),
genres: format_genres(self.genres.clone(), counts.genres), genres: format_genres(self.genres.clone(), counts.genres),
max_result_size: 0
}; };
} }
result result.with_max_result_size(max_result_size)
} }
} }
impl Format for Book { impl Format for Book {
fn format(&self, max_size: u32) -> String { fn format(&self, max_size: usize) -> FormatResult {
let book_title = { let book_title = {
let Book { title, lang, .. } = self; let Book { title, lang, .. } = self;
@@ -319,29 +364,36 @@ impl Format for Book {
let download_command = (StartDownloadData { id: self.id }).to_string(); let download_command = (StartDownloadData { id: self.id }).to_string();
let download_links = format!("Скачать:\n📥{download_command}"); let download_links = format!("Скачать:\n📥{download_command}");
let required_data_len: u32 = format!("{book_title}{annotations}{download_links}").len().try_into().unwrap(); let required_data_len: usize = format!("{book_title}{annotations}{download_links}").len();
let FormatVectorsResult { authors, translators, sequences, genres } = self.format_vectors( let FormatVectorsResult { authors, translators, sequences, genres, max_result_size } = self.format_vectors(
max_size - required_data_len max_size - required_data_len
); );
format!("{book_title}{annotations}{authors}{translators}{sequences}{genres}{download_links}") let result = format!("{book_title}{annotations}{authors}{translators}{sequences}{genres}{download_links}");
let result_len = result.len();
FormatResult {
result,
current_size: result_len,
max_size: max_result_size + required_data_len
}
} }
} }
impl Format for SearchBook { impl Format for SearchBook {
fn format(&self, max_size: u32) -> String { fn format(&self, max_size: usize) -> FormatResult {
self.clone().as_book().format(max_size) self.clone().as_book().format(max_size)
} }
} }
impl Format for AuthorBook { impl Format for AuthorBook {
fn format(&self, max_size: u32) -> String { fn format(&self, max_size: usize) -> FormatResult {
self.clone().as_book().format(max_size) self.clone().as_book().format(max_size)
} }
} }
impl Format for TranslatorBook { impl Format for TranslatorBook {
fn format(&self, max_size: u32) -> String { fn format(&self, max_size: usize) -> FormatResult {
self.clone().as_book().format(max_size) self.clone().as_book().format(max_size)
} }
} }

View File

@@ -1,6 +1,6 @@
use serde::Deserialize; use serde::Deserialize;
use super::formaters::Format; use super::formaters::{Format, FormatResult};
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
@@ -76,16 +76,63 @@ impl<T> Page<T>
where where
T: Format + Clone, T: Format + Clone,
{ {
pub fn format_items(&self, max_size: u32) -> String { pub fn format_items(&self, max_size: usize) -> String {
let items_count: u32 = self.items.len().try_into().unwrap(); let separator = "\n\n\n";
let item_size: u32 = (max_size - 3 * items_count) / items_count; let separator_len: usize = separator.len();
let items_count: usize = self.items.len();
let item_size: usize = (max_size - separator_len * items_count) / items_count;
let format_result: Vec<FormatResult> = self.items
.clone()
.into_iter()
.map(|item| item.format(item_size))
.collect();
let has_any_spliced = {
format_result
.clone()
.into_iter()
.any(|item| item.current_size != item.max_size)
};
if !has_any_spliced {
return format_result
.into_iter()
.map(|item| item.result)
.collect::<Vec<String>>()
.join(separator);
}
let mut free_symbols: usize = format_result
.clone()
.into_iter()
.filter(|item| item.current_size == item.max_size)
.map(|item| item_size - item.current_size)
.collect::<Vec<usize>>()
.into_iter()
.sum();
self.items self.items
.clone() .clone()
.into_iter() .into_iter()
.map(|item| item.format(item_size)) .enumerate()
.map(|(index, item)| {
let already_formated_result = &format_result[index];
if already_formated_result.current_size == already_formated_result.max_size {
already_formated_result.result.clone()
} else {
let new_item_size = item_size + free_symbols;
let new_formated_result = item.format(new_item_size);
free_symbols = new_item_size - new_formated_result.current_size;
new_formated_result.result
}
})
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n\n\n") .join(separator)
} }
} }
@@ -106,7 +153,7 @@ pub struct AuthorAnnotation {
} }
pub trait AsBook<T> { pub trait AsBook<T> {
fn as_book(self) -> T; fn as_book(&self) -> T;
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
@@ -129,8 +176,8 @@ pub struct Book {
} }
impl AsBook<Book> for Book { impl AsBook<Book> for Book {
fn as_book(self) -> Book { fn as_book(&self) -> Self {
self self.clone()
} }
} }
@@ -149,16 +196,16 @@ pub struct SearchBook {
} }
impl AsBook<Book> for SearchBook { impl AsBook<Book> for SearchBook {
fn as_book(self) -> Book { fn as_book(&self) -> Book {
Book { Book {
id: self.id, id: self.id,
title: self.title, title: self.title.clone(),
lang: self.lang, lang: self.lang.clone(),
available_types: self.available_types, available_types: self.available_types.clone(),
annotation_exists: self.annotation_exists, annotation_exists: self.annotation_exists,
authors: self.authors, authors: self.authors.clone(),
translators: self.translators, translators: self.translators.clone(),
sequences: self.sequences, sequences: self.sequences.clone(),
genres: vec![], genres: vec![],
pages: None pages: None
} }
@@ -179,16 +226,16 @@ pub struct AuthorBook {
} }
impl AsBook<Book> for AuthorBook { impl AsBook<Book> for AuthorBook {
fn as_book(self) -> Book { fn as_book(&self) -> Book {
Book { Book {
id: self.id, id: self.id,
title: self.title, title: self.title.clone(),
lang: self.lang, lang: self.lang.clone(),
available_types: self.available_types, available_types: self.available_types.clone(),
annotation_exists: self.annotation_exists, annotation_exists: self.annotation_exists,
authors: vec![], authors: vec![],
translators: self.translators, translators: self.translators.clone(),
sequences: self.sequences, sequences: self.sequences.clone(),
genres: vec![], genres: vec![],
pages: None pages: None
} }
@@ -209,16 +256,16 @@ pub struct TranslatorBook {
} }
impl AsBook<Book> for TranslatorBook { impl AsBook<Book> for TranslatorBook {
fn as_book(self) -> Book { fn as_book(&self) -> Book {
Book { Book {
id: self.id, id: self.id,
title: self.title, title: self.title.clone(),
lang: self.lang, lang: self.lang.clone(),
available_types: self.available_types, available_types: self.available_types.clone(),
annotation_exists: self.annotation_exists, annotation_exists: self.annotation_exists,
authors: self.authors, authors: self.authors.clone(),
translators: vec![], translators: vec![],
sequences: self.sequences, sequences: self.sequences.clone(),
genres: vec![], genres: vec![],
pages: None pages: None
} }