From: Simon Tatham Date: Thu, 28 Dec 2023 11:06:15 +0000 (+0000) Subject: Changed my mind about using Box. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=0d428ad0f44c91d11c986c15084c6a352fc7335e;p=mastodonochrome.git Changed my mind about using Box. I think it's going to be a better idea to have each user of TextFragment separately make an enum that permits precisely the kinds of TextFragment they want. Firstly, this means we can be statically sure no rogue weird ones got in there by accident; secondly, it immediately solves all the problems of finding the ones that need special handling at render time (extensible-file indicators etc). And thirdly - this is definitely a thing I'm having trouble getting used to in Rust - if I _do_ need one particular client of TextFragment to do everything by means of a list of perfectly generic Box, I can choose to do it in _that_ client module, and text.rs doesn't have to lift a finger to support it! --- diff --git a/src/menu.rs b/src/menu.rs index ba6ce5c..069ef9e 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -6,7 +6,7 @@ use super::tui::{ }; struct Menu { - title: Box, + title: FileHeader, } pub fn main_menu() -> Box { diff --git a/src/text.rs b/src/text.rs index 33f834c..8b3cff0 100644 --- a/src/text.rs +++ b/src/text.rs @@ -15,21 +15,13 @@ pub trait TextFragment { // Some means of passing a flag to render() that says which username or // status is to be highlighted fn render(&self, width: usize) -> Vec; - - fn as_extendable_indicator_mut(&mut self) - -> Option<&mut ExtendableIndicator> { - None - } - fn as_menu_keypress_mut(&mut self) -> Option<&mut MenuKeypressLine> { - None - } } pub struct BlankLine {} impl BlankLine { - pub fn new() -> Box { - Box::new(BlankLine{}) + pub fn new() -> Self { + BlankLine{} } } @@ -59,12 +51,12 @@ impl SeparatorLine { timestamp: Option>, favourited: bool, boosted: bool, - ) -> Box { - Box::new(SeparatorLine { - timestamp, - favourited, - boosted, - }) + ) -> Self { + SeparatorLine { + timestamp, + favourited, + boosted, + } } } @@ -119,8 +111,8 @@ fn test_separator() { pub struct EditorHeaderSeparator {} impl EditorHeaderSeparator { - pub fn new() -> Box { - Box::new(EditorHeaderSeparator{}) + pub fn new() -> Self { + EditorHeaderSeparator{} } } @@ -153,22 +145,22 @@ pub struct UsernameHeader { } impl UsernameHeader { - pub fn from(account: &str, nameline: &str) -> Box { - Box::new(UsernameHeader{ + pub fn from(account: &str, nameline: &str) -> Self { + UsernameHeader{ header: "From".to_owned(), colour: 'F', account: account.to_owned(), nameline: nameline.to_owned(), - }) + } } - pub fn via(account: &str, nameline: &str) -> Box { - Box::new(UsernameHeader{ - header: "Via".to_owned(), - colour: 'f', - account: account.to_owned(), - nameline: nameline.to_owned(), - }) + pub fn via(account: &str, nameline: &str) -> Self { + UsernameHeader{ + header: "Via".to_owned(), + colour: 'f', + account: account.to_owned(), + nameline: nameline.to_owned(), + } } } @@ -291,8 +283,6 @@ impl Paragraph { self.words.splice(start..first_non_mention, vec!{}); } - pub fn into_box(self) -> Box { Box::new(self) } - pub fn is_empty(&self) -> bool { match self.words.first() { None => true, @@ -419,7 +409,7 @@ impl TextFragment for Paragraph { #[test] fn test_para_wrap() { let p = Paragraph::new().add(&ColouredString::plain( - "the quick brown fox jumps over the lazy dog")).into_box(); + "the quick brown fox jumps over the lazy dog")); assert_eq!(p.render(15), vec! { ColouredString::plain("the quick brown"), ColouredString::plain("fox jumps over"), @@ -427,7 +417,7 @@ fn test_para_wrap() { }); let p = Paragraph::new().add(&ColouredString::plain( - " one supercalifragilisticexpialidocious word")).into_box(); + " one supercalifragilisticexpialidocious word")); assert_eq!(p.render(15), vec! { ColouredString::plain(" one"), ColouredString::plain("supercalifragilisticexpialidocious"), @@ -435,7 +425,7 @@ fn test_para_wrap() { }); let p = Paragraph::new().add(&ColouredString::plain( - " supercalifragilisticexpialidocious word")).into_box(); + " supercalifragilisticexpialidocious word")); assert_eq!(p.render(15), vec! { ColouredString::plain(" supercalifragilisticexpialidocious"), ColouredString::plain("word"), @@ -443,14 +433,14 @@ fn test_para_wrap() { let p = Paragraph::new().add(&ColouredString::plain( "the quick brown fox jumps over the lazy dog")) - .set_wrap(false).into_box(); + .set_wrap(false); assert_eq!(p.render(15), vec! { ColouredString::plain("the quick brown fox jumps over the lazy dog"), }); let p = Paragraph::new().add(&ColouredString::plain( "the quick brown fox jumps over the lazy dog")) - .set_indent(4, 2).into_box(); + .set_indent(4, 2); assert_eq!(p.render(15), vec! { ColouredString::plain(" the quick"), ColouredString::plain(" brown fox"), @@ -464,10 +454,10 @@ pub struct FileHeader { } impl FileHeader { - pub fn new(text: ColouredString) -> Box { - Box::new(FileHeader{ - text: text, - }) + pub fn new(text: ColouredString) -> Self { + FileHeader{ + text: text, + } } } @@ -777,10 +767,10 @@ pub struct ExtendableIndicator { } impl ExtendableIndicator { - pub fn new() -> Box { - Box::new(ExtendableIndicator{ - primed: false - }) + pub fn new() -> Self { + ExtendableIndicator{ + primed: false + } } pub fn set_primed(&mut self, primed: bool) { self.primed = primed; } @@ -808,11 +798,6 @@ impl TextFragment for ExtendableIndicator { ColouredString::plain(""), } } - - fn as_extendable_indicator_mut(&mut self) - -> Option<&mut ExtendableIndicator> { - Some(self) - } } #[test] @@ -827,7 +812,7 @@ fn test_extendable() { ColouredString::plain(""), }); - ei.as_extendable_indicator_mut().unwrap().set_primed(true); + ei.set_primed(true); assert_eq!(ei.render(40), vec! { ColouredString::plain(""), @@ -843,16 +828,16 @@ pub struct InReplyToLine { } impl InReplyToLine { - pub fn new(post: &Vec) -> Box { + pub fn new(post: &Vec) -> Self { let mut para = Paragraph::new().add(&ColouredString::plain("Re: ")); let currlen = para.words.len(); for cpara in post { para.push_para(cpara); } para.delete_mention_words_from(currlen); - Box::new(InReplyToLine { - para: para - }) + InReplyToLine { + para: para + } } } @@ -916,7 +901,7 @@ impl NotificationLog { pub fn new( timestamp: DateTime, account: &str, nameline: &str, ntype: NotificationLogType, post: Option<&Vec>) - -> Box { + -> Self { let mut para = Paragraph::new(); @@ -935,11 +920,11 @@ impl NotificationLog { para.delete_mention_words_from(currlen); } - Box::new(NotificationLog { - timestamp: timestamp, - account_desc: format!("{} ({})", nameline, account), - para: para, - }) + NotificationLog { + timestamp: timestamp, + account_desc: format!("{} ({})", nameline, account), + para: para, + } } } @@ -1013,10 +998,10 @@ pub struct UserListEntry { impl UserListEntry { pub fn new(account: &str, nameline: &str) - -> Box { - Box::new(UserListEntry { - account_desc: format!("{} ({})", nameline, account), - }) + -> Self { + UserListEntry { + account_desc: format!("{} ({})", nameline, account), + } } } @@ -1046,7 +1031,7 @@ pub struct Media { impl Media { pub fn new(url: &str, description: &str) - -> Box { + -> Self { let mut paras = description .split('\n') .map(|x| Paragraph::new() @@ -1054,10 +1039,10 @@ impl Media { .add(&ColouredString::uniform(x, 'm'))) .collect(); trim_para_list(&mut paras); - Box::new(Media { - url: url.to_owned(), - description: paras, - }) + Media { + url: url.to_owned(), + description: paras, + } } } @@ -1122,7 +1107,7 @@ pub struct FileStatusLine { message: Option, } -struct FileStatusLineFinal { +pub struct FileStatusLineFinal { fs: FileStatusLine, priwidth: Vec<(usize, usize)>, // min priority, total width of those keys } @@ -1157,7 +1142,7 @@ impl FileStatusLine { self } - fn finalise(self) -> FileStatusLineFinal { + pub fn finalise(self) -> FileStatusLineFinal { let mut bypri = BTreeMap::new(); for (kp, pri) in &self.keypresses { // [key]:desc @@ -1191,10 +1176,6 @@ impl FileStatusLine { priwidth: priwidth } } - - pub fn into_box(self) -> Box { - Box::new(self.finalise()) - } } #[test] @@ -1322,7 +1303,7 @@ fn test_filestatus_render() { .add(OurKey::Pr('b'), "Badger", 10) .add(OurKey::Pr('c'), "Critical", 1000) .add(OurKey::Pr('d'), "Dull", 1) - .into_box(); + .finalise(); assert_eq!(fs.render(80), vec! { ColouredString::general( @@ -1367,7 +1348,7 @@ fn test_filestatus_render() { let fs = FileStatusLine::new() .set_proportion(1, 11) .add(OurKey::Pr('K'), "Keypress", 10) - .into_box(); + .finalise(); assert_eq!(fs.render(19), vec! { ColouredString::general( @@ -1384,7 +1365,7 @@ fn test_filestatus_render() { let fs = FileStatusLine::new() .message("weasel") .add(OurKey::Pr('K'), "Keypress", 10) - .into_box(); + .finalise(); assert_eq!(fs.render(21), vec! { ColouredString::general( @@ -1408,20 +1389,20 @@ pub struct MenuKeypressLine { impl MenuKeypressLine { pub fn new(key: OurKey, description: ColouredString) - -> Box { + -> Self { // +2 for [] around the key name let lwid = UnicodeWidthStr::width(&key_to_string(key) as &str) + 2; let rwid = description.width(); - Box::new(MenuKeypressLine { - keypress: Keypress { - key: key, - description: description, - }, - lwid: lwid, - lmaxwid: lwid, - rmaxwid: rwid, - }) + MenuKeypressLine { + keypress: Keypress { + key: key, + description: description, + }, + lwid: lwid, + lmaxwid: lwid, + rmaxwid: rwid, + } } pub fn get_widths(&self) -> (usize, usize) { (self.lmaxwid, self.rmaxwid) } @@ -1454,10 +1435,6 @@ impl TextFragment for MenuKeypressLine { line.truncate(width).to_owned() } } - - fn as_menu_keypress_mut(&mut self) -> Option<&mut MenuKeypressLine> { - Some(self) - } } #[test] @@ -1478,7 +1455,7 @@ fn test_menu_keypress() { " k K "), }); - mk.as_menu_keypress_mut().unwrap().ensure_widths(5, 0); + mk.ensure_widths(5, 0); assert_eq!(mk.render(40), vec! { ColouredString::general(