chiark / gitweb /
packetframe: Fuse: retain the inner RW when broken
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 16 May 2021 12:18:20 +0000 (13:18 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 16 May 2021 21:30:35 +0000 (22:30 +0100)
We are going to want this for AsRawFd, which needs to work even when
broken since it is supposed to be infallible.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/packetframe.rs

index 58e303795e84817ba588b560d9f73de8d575bfe9..349d7ea17a4901770625a48705dc08e7076dc35f 100644 (file)
@@ -32,7 +32,7 @@ type BO = BigEndian;
 pub struct SenderError;
 
 #[derive(Debug)]
-pub struct Fuse<RW>{ inner: Result<RW, Broken> }
+pub struct Fuse<RW>{ inner: Result<RW, BrokenFuse<RW>> }
 
 /// An error saved by `Fuse` so it can be repeatedly returned.
 #[derive(Clone,Error,Debug)]
@@ -41,6 +41,12 @@ pub struct Broken {
   kind: io::ErrorKind,
 }
 
+#[derive(Debug)]
+pub struct BrokenFuse<RW> {
+  inner: Option<RW>, // always Some unless we panic crazily
+  error: Broken,
+}
+
 // ---------- read ----------
 
 #[derive(Debug)]
@@ -114,7 +120,7 @@ impl<RW> Fuse<RW> {
 
   #[throws(io::Error)]
   pub fn get(&mut self) -> &mut RW {
-    self.inner.as_mut().map_err(|broken| broken.clone())?
+    self.inner.as_mut().map_err(|broken| broken.error.clone())?
   }
 
   #[throws(io::Error)]
@@ -124,10 +130,17 @@ impl<RW> Fuse<RW> {
     let inner = self.get()?;
     let r = f(inner);
     if let Err(e) = &r {
-      self.inner = Err(Broken {
+      let error = Broken {
         msg: e.to_string(),
         kind: e.kind(),
-      });
+      };
+      let inner = mem::replace(&mut self.inner, Err(BrokenFuse {
+        inner: None,
+        error,
+      }));
+      self.inner.as_mut().map(|_|()).unwrap_err().inner = Some(
+        inner.map_err(|e| e.error).unwrap()
+      );
     }
     r?
   }