about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2023-06-22 20:25:28 +0300
committerVika <vika@fireburn.ru>2023-06-22 20:25:28 +0300
commitff358723da641af9f4ae1f742eb1b382f4630220 (patch)
tree32a2319a0bea909b9d267e44fa3a632991ddda12
parent0285e630f3cae1ee2df2c7c465998b1ce669944f (diff)
StorageError: use std::borrow::Cow for msg field
This allows avoiding an unnecessary allocation whenever the error
message is static.
-rw-r--r--kittybox-rs/src/database/file/mod.rs19
-rw-r--r--kittybox-rs/src/database/memory.rs10
-rw-r--r--kittybox-rs/src/database/mod.rs28
3 files changed, 36 insertions, 21 deletions
diff --git a/kittybox-rs/src/database/file/mod.rs b/kittybox-rs/src/database/file/mod.rs
index 9319b67..531f7b1 100644
--- a/kittybox-rs/src/database/file/mod.rs
+++ b/kittybox-rs/src/database/file/mod.rs
@@ -3,6 +3,7 @@ use crate::database::{filter_post, ErrorKind, Result, settings, Storage, Storage
 use async_trait::async_trait;
 use futures::{stream, StreamExt, TryStreamExt};
 use serde_json::json;
+use std::borrow::Cow;
 use std::collections::HashMap;
 use std::io::ErrorKind as IOErrorKind;
 use std::path::{Path, PathBuf};
@@ -19,7 +20,7 @@ impl From<std::io::Error> for StorageError {
                 IOErrorKind::AlreadyExists => ErrorKind::Conflict,
                 _ => ErrorKind::Backend,
             },
-            "file I/O error",
+            Cow::Owned(format!("file I/O error: {}", &source)),
             Box::new(source),
         )
     }
@@ -29,7 +30,7 @@ impl From<tokio::time::error::Elapsed> for StorageError {
     fn from(source: tokio::time::error::Elapsed) -> Self {
         Self::with_source(
             ErrorKind::Backend,
-            "timeout on I/O operation",
+            Cow::Borrowed("timeout on I/O operation"),
             Box::new(source),
         )
     }
@@ -135,7 +136,7 @@ fn modify_post(post: &serde_json::Value, update: &serde_json::Value) -> Result<s
                     .or_default()
                     .extend(v.clone());
             } else {
-                return Err(StorageError::new(
+                return Err(StorageError::from_static(
                     ErrorKind::BadRequest,
                     "Malformed update object",
                 ));
@@ -147,7 +148,7 @@ fn modify_post(post: &serde_json::Value, update: &serde_json::Value) -> Result<s
             if let Some(v) = v.as_array() {
                 add_keys.insert(k.to_string(), v.clone());
             } else {
-                return Err(StorageError::new(
+                return Err(StorageError::from_static(
                     ErrorKind::BadRequest,
                     "Malformed update object",
                 ));
@@ -160,7 +161,7 @@ fn modify_post(post: &serde_json::Value, update: &serde_json::Value) -> Result<s
             if let Some(v) = v.as_array() {
                 add_keys.insert(k.to_string(), v.clone());
             } else {
-                return Err(StorageError::new(
+                return Err(StorageError::from_static(
                     ErrorKind::BadRequest,
                     "Malformed update object",
                 ));
@@ -358,7 +359,7 @@ impl Storage for FileStorage {
                     let orig = path.clone();
                     // We're supposed to have a parent here.
                     let basedir = link.parent().ok_or_else(|| {
-                        StorageError::new(
+                        StorageError::from_static(
                             ErrorKind::Backend,
                             "Failed to calculate parent directory when creating a symlink",
                         )
@@ -551,7 +552,7 @@ impl Storage for FileStorage {
                         Err(err) => {
                             return Err(StorageError::with_source(
                                 ErrorKind::Other,
-                                "Feed assembly error",
+                                Cow::Owned(format!("Feed assembly error: {}", &err)),
                                 Box::new(err),
                             ));
                         }
@@ -560,7 +561,7 @@ impl Storage for FileStorage {
                 hydrate_author(&mut feed, user, self).await;
                 Ok(Some(feed))
             } else {
-                Err(StorageError::new(
+                Err(StorageError::from_static(
                     ErrorKind::PermissionDenied,
                     "specified user cannot access this post",
                 ))
@@ -599,7 +600,7 @@ impl Storage for FileStorage {
         let settings: HashMap<&str, serde_json::Value> = serde_json::from_str(&content)?;
         match settings.get(S::ID) {
             Some(value) => Ok(serde_json::from_value::<S>(value.clone())?),
-            None => Err(StorageError::new(ErrorKind::Backend, "Setting not set"))
+            None => Err(StorageError::from_static(ErrorKind::Backend, "Setting not set"))
         }
     }
 
diff --git a/kittybox-rs/src/database/memory.rs b/kittybox-rs/src/database/memory.rs
index 2fb55e5..9d79ecc 100644
--- a/kittybox-rs/src/database/memory.rs
+++ b/kittybox-rs/src/database/memory.rs
@@ -46,7 +46,7 @@ impl Storage for MemoryStorage {
         let key: &str = match post["properties"]["uid"][0].as_str() {
             Some(uid) => uid,
             None => {
-                return Err(StorageError::new(
+                return Err(StorageError::from_static(
                     ErrorKind::Other,
                     "post doesn't have a UID",
                 ))
@@ -108,7 +108,7 @@ impl Storage for MemoryStorage {
                         .or_default()
                         .extend(v.clone());
                 } else {
-                    return Err(StorageError::new(
+                    return Err(StorageError::from_static(
                         ErrorKind::BadRequest,
                         "Malformed update object",
                     ));
@@ -120,7 +120,7 @@ impl Storage for MemoryStorage {
                 if v.is_array() {
                     add_keys.insert(k.to_string(), v.clone());
                 } else {
-                    return Err(StorageError::new(
+                    return Err(StorageError::from_static(
                         ErrorKind::BadRequest,
                         "Malformed update object",
                     ));
@@ -139,7 +139,7 @@ impl Storage for MemoryStorage {
                 if let Some(new_post) = mapping.get(url) {
                     post = new_post
                 } else {
-                    return Err(StorageError::new(
+                    return Err(StorageError::from_static(
                         ErrorKind::NotFound,
                         "The post you have requested is not found in the database.",
                     ));
@@ -191,7 +191,7 @@ impl Storage for MemoryStorage {
                 post,
             );
         } else {
-            return Err(StorageError::new(
+            return Err(StorageError::from_static(
                 ErrorKind::NotFound,
                 "The designated post wasn't found in the database.",
             ));
diff --git a/kittybox-rs/src/database/mod.rs b/kittybox-rs/src/database/mod.rs
index db0e360..ea4205c 100644
--- a/kittybox-rs/src/database/mod.rs
+++ b/kittybox-rs/src/database/mod.rs
@@ -1,4 +1,6 @@
 #![warn(missing_docs)]
+use std::borrow::Cow;
+
 use async_trait::async_trait;
 
 mod file;
@@ -122,7 +124,7 @@ pub mod settings {
 /// Error signalled from the database.
 #[derive(Debug)]
 pub struct StorageError {
-    msg: String,
+    msg: std::borrow::Cow<'static, str>,
     source: Option<Box<dyn std::error::Error + Send + Sync>>,
     kind: ErrorKind,
 }
@@ -137,7 +139,7 @@ impl std::error::Error for StorageError {
 impl From<serde_json::Error> for StorageError {
     fn from(err: serde_json::Error) -> Self {
         Self {
-            msg: format!("{}", err),
+            msg: std::borrow::Cow::Owned(format!("{}", err)),
             source: Some(Box::new(err)),
             kind: ErrorKind::JsonParsing,
         }
@@ -171,21 +173,33 @@ impl serde::Serialize for StorageError {
 }
 impl StorageError {
     /// Create a new StorageError of an ErrorKind with a message.
-    fn new(kind: ErrorKind, msg: &str) -> Self {
+    pub fn new(kind: ErrorKind, msg: String) -> Self {
         Self {
-            msg: msg.to_string(),
+            msg: Cow::Owned(msg),
             source: None,
             kind,
         }
     }
+    /// Create a new StorageError of an ErrorKind with a message from
+    /// a static string.
+    ///
+    /// This saves an allocation for a new string and is the preferred
+    /// way in case the error message doesn't change.
+    pub fn from_static(kind: ErrorKind, msg: &'static str) -> Self {
+        Self {
+            msg: Cow::Borrowed(msg),
+            source: None,
+            kind
+        }
+    }
     /// Create a StorageError using another arbitrary Error as a source.
-    fn with_source(
+    pub fn with_source(
         kind: ErrorKind,
-        msg: &str,
+        msg: std::borrow::Cow<'static, str>,
         source: Box<dyn std::error::Error + Send + Sync>,
     ) -> Self {
         Self {
-            msg: msg.to_string(),
+            msg,
             source: Some(source),
             kind,
         }