chiark / gitweb /
Abstract out FeedDataSource.
authorSimon Tatham <anakin@pobox.com>
Mon, 1 Jan 2024 09:47:08 +0000 (09:47 +0000)
committerSimon Tatham <anakin@pobox.com>
Mon, 1 Jan 2024 10:10:14 +0000 (10:10 +0000)
Now a FileContents doesn't _have_ to contain a FeedId; I can replace
it with an alternative trait implementation containing a fixed set of
things.

src/file.rs

index f1541a30052fdd31d84d7ff006572a0acd9b96c0..a93aa9fb428ce0fe91344808c7e605928f54829e 100644 (file)
@@ -24,6 +24,45 @@ impl FilePosition {
     }
 }
 
+trait FileDataSource {
+    fn get(&self, client: &mut Client) -> (Vec<String>, isize);
+    fn init(&self, client: &mut Client) -> Result<(), ClientError>;
+    fn try_extend(&self, client: &mut Client) -> Result<bool, ClientError>;
+    fn updated(&self, feeds_updated: &HashSet<FeedId>) -> bool;
+    fn extendable(&self) -> bool;
+}
+
+struct FeedSource {
+    id: FeedId,
+}
+
+impl FeedSource {
+    fn new(id: FeedId) -> Self { FeedSource { id } }
+}
+
+impl FileDataSource for FeedSource {
+    fn get(&self, client: &mut Client) -> (Vec<String>, isize) {
+        let feed = client.borrow_feed(&self.id);
+        let ids = feed.ids.iter().map(|x| x.clone()).collect();
+        (ids, feed.origin)
+    }
+
+    fn init(&self, client: &mut Client) -> Result<(), ClientError> {
+        client.fetch_feed(&self.id, FeedExtend::Initial)?;
+        Ok(())
+    }
+
+    fn try_extend(&self, client: &mut Client) -> Result<bool, ClientError> {
+        client.fetch_feed(&self.id, FeedExtend::Past)
+    }
+
+    fn updated(&self, feeds_updated: &HashSet<FeedId>) -> bool {
+        feeds_updated.contains(&self.id)
+    }
+
+    fn extendable(&self) -> bool { true }
+}
+
 trait FileType {
     type Item: TextFragment + Sized;
 
@@ -69,22 +108,21 @@ impl FileType for EgoNotificationFeedType {
     }
 }
 
-struct FileContents<Type: FileType> {
-    id: FeedId,
+struct FileContents<Type: FileType, Source: FileDataSource> {
+    source: Source,
     header: FileHeader,
     extender: Option<ExtendableIndicator>,
     origin: isize,
     items: Vec<Type::Item>,
 }
 
-impl<Type: FileType> FileContents<Type> {
+impl<Type: FileType, Source: FileDataSource> FileContents<Type,Source> {
     fn update_items(&mut self, client: &mut Client) {
         // FIXME: if the feed has been extended rather than created,
         // we should be able to make less effort than this
 
-        let feed = client.borrow_feed(&self.id);
-        let ids: Vec<_> = feed.ids.iter().map(|x| x.clone()).collect();
-        self.origin = feed.origin;
+        let (ids, origin) = self.source.get(client);
+        self.origin = origin;
 
         self.items.clear();
         for id in ids {
@@ -127,23 +165,29 @@ impl<Type: FileType> FileContents<Type> {
     }
 }
 
-struct File<Type: FileType> {
-    contents: FileContents<Type>,
+struct File<Type: FileType, Source: FileDataSource> {
+    contents: FileContents<Type, Source>,
     rendered: HashMap<isize, Vec<ColouredString>>,
     pos: FilePosition,
     last_size: Option<(usize, usize)>,
 }
 
-impl<Type: FileType> File<Type> {
-    fn new(client: &mut Client, id: FeedId, desc: ColouredString) ->
+impl<Type: FileType, Source: FileDataSource> File<Type, Source> {
+    fn new(client: &mut Client, source: Source, desc: ColouredString) ->
         Result<Self, ClientError>
     {
-        client.fetch_feed(&id, FeedExtend::Initial)?;
+        source.init(client)?;
+
+        let extender = if source.extendable() {
+            Some(ExtendableIndicator::new())
+        } else {
+            None
+        };
 
         let mut contents = FileContents {
-            id: id,
+            source: source,
             header: FileHeader::new(desc),
-            extender: Some(ExtendableIndicator::new()),
+            extender,
             origin: 0,
             items: Vec::new(),
         };
@@ -350,7 +394,9 @@ impl<Type: FileType> File<Type> {
     }
 }
 
-impl<Type: FileType> ActivityState for File<Type> {
+impl<Type: FileType, Source: FileDataSource>
+    ActivityState for File<Type, Source>
+{
     fn resize(&mut self, w: usize, h: usize) {
         if self.last_size != Some((w, h)) {
             self.last_size = Some((w, h));
@@ -456,8 +502,7 @@ impl<Type: FileType> ActivityState for File<Type> {
             },
             Pr('0') | Home => {
                 if self.at_top() && self.contents.extender.is_some() {
-                    let action = match client.fetch_feed(&self.contents.id,
-                                                         FeedExtend::Past) {
+                    let action = match self.contents.source.try_extend(client) {
                         Ok(any_new) => {
                             self.rendered.remove(&self.contents.first_index());
                             if let Some(i) = self.contents.extender_index() {
@@ -501,7 +546,7 @@ impl<Type: FileType> ActivityState for File<Type> {
 
     fn handle_feed_updates(&mut self, feeds_updated: &HashSet<FeedId>,
                            client: &mut Client) {
-        if feeds_updated.contains(&self.contents.id) {
+        if self.contents.source.updated(feeds_updated) {
             self.contents.update_items(client);
             self.ensure_enough_rendered();
         }
@@ -511,8 +556,8 @@ impl<Type: FileType> ActivityState for File<Type> {
 pub fn home_timeline(client: &mut Client) ->
     Result<Box<dyn ActivityState>, ClientError>
 {
-    let file = File::<StatusFeedType>::new(
-        client, FeedId::Home, ColouredString::general(
+    let file = File::<StatusFeedType, _>::new(
+        client, FeedSource::new(FeedId::Home), ColouredString::general(
             "Home timeline   <H>",
             "HHHHHHHHHHHHHHHHHKH"))?;
     Ok(Box::new(file))
@@ -521,8 +566,8 @@ pub fn home_timeline(client: &mut Client) ->
 pub fn local_timeline(client: &mut Client) ->
     Result<Box<dyn ActivityState>, ClientError>
 {
-    let file = File::<StatusFeedType>::new(
-        client, FeedId::Local, ColouredString::general(
+    let file = File::<StatusFeedType, _>::new(
+        client, FeedSource::new(FeedId::Local), ColouredString::general(
             "Local public timeline   <L>",
             "HHHHHHHHHHHHHHHHHHHHHHHHHKH"))?;
     Ok(Box::new(file))
@@ -531,8 +576,8 @@ pub fn local_timeline(client: &mut Client) ->
 pub fn public_timeline(client: &mut Client) ->
     Result<Box<dyn ActivityState>, ClientError>
 {
-    let file = File::<StatusFeedType>::new(
-        client, FeedId::Public, ColouredString::general(
+    let file = File::<StatusFeedType, _>::new(
+        client, FeedSource::new(FeedId::Public), ColouredString::general(
             "Public timeline   <P>",
             "HHHHHHHHHHHHHHHHHHHKH"))?;
     Ok(Box::new(file))
@@ -541,8 +586,8 @@ pub fn public_timeline(client: &mut Client) ->
 pub fn mentions(client: &mut Client) ->
     Result<Box<dyn ActivityState>, ClientError>
 {
-    let file = File::<NotificationStatusFeedType>::new(
-        client, FeedId::Mentions, ColouredString::general(
+    let file = File::<NotificationStatusFeedType, _>::new(
+        client, FeedSource::new(FeedId::Mentions), ColouredString::general(
             "Mentions   [ESC][R]",
             "HHHHHHHHHHHHKKKHHKH"))?;
     Ok(Box::new(file))
@@ -551,8 +596,8 @@ pub fn mentions(client: &mut Client) ->
 pub fn ego_log(client: &mut Client) ->
     Result<Box<dyn ActivityState>, ClientError>
 {
-    let file = File::<EgoNotificationFeedType>::new(
-        client, FeedId::Ego, ColouredString::general(
+    let file = File::<EgoNotificationFeedType, _>::new(
+        client, FeedSource::new(FeedId::Ego), ColouredString::general(
             "Ego Log   [ESC][L][L][E]",
             "HHHHHHHHHHHKKKHHKHHKHHKH"))?;
     Ok(Box::new(file))