Repository: shuttle-hq/synth (language: rust)

Issue:
Clippy is unhappy
**Required Functionality**
Running `cargo clippy` at the root of the project yields various errors (turned into warnings once #36 gets closed).

**Proposed Solution**
Apply the fixes suggested by Clippy. Most of them look pretty straightforward to solve and shouldn't cause any issue. However, I'm not sure all of them would be accepted. For example, one of the suggestions is to rename ParseState::EOF, at core/src/schema/mod.rs, to ParseState::Eof. Clippy also suggests changing the signature of some functions/methods to conform with conventions. I suggest we either fix these last issues or explicitly allow them with #allow[] macros.

(Optional) To prevent these issues from appearing again, we should also consider running Clippy in the CI pipeline, although contributors should be aware of that, in order to prevent their commits to fail.

**Use case**
Following Clippy's suggestions would improve readability and, in some cases, slightly improve performance.



Discussion / hints:

Fix patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 769fff08..69b1f03a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -19,3 +19,5 @@ To run the test suite - just run `cargo test` at the root of the repository.
 We use the [Angular Commit Guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit). We expect all commits to conform to these guidelines.
 
 Furthermore, commits should be squashed before being merged to master.
+
+Also, make sure your commits don't trigger any warnings from Clippy by running: `cargo clippy --tests --all-targets`. If you have a good reason to contradict Clippy, insert an #allow[] macro, so that it won't complain.
diff --git a/core/src/compile/mod.rs b/core/src/compile/mod.rs
index d784f27b..adc1b5e5 100644
--- a/core/src/compile/mod.rs
+++ b/core/src/compile/mod.rs
@@ -296,7 +296,7 @@ impl Scope {
     }
 
     #[inline]
-    fn as_within(mut self, scope: &str) -> Self {
+    fn into_within(mut self, scope: &str) -> Self {
         self.within(scope);
         self
     }
@@ -308,7 +308,7 @@ impl Scope {
     }
 
     #[inline]
-    fn as_at(mut self, attribute: &str) -> Self {
+    fn into_at(mut self, attribute: &str) -> Self {
         self.at(attribute);
         self
     }
@@ -541,7 +541,7 @@ impl<'a> NamespaceCompiler<'a> {
                 .ordering
                 .iter()
                 .filter(|attr| !scope.children.get(*attr).unwrap().compiled.is_built())
-                .map(|attr| next_scope.clone().as_at(attr))
+                .map(|attr| next_scope.clone().into_at(attr))
                 .collect();
             stage_2!(
                 "{}: {} dependencies left",
@@ -667,7 +667,7 @@ impl<'c, 'a: 'c> Compiler<'a> for ContentCompiler<'c, 'a> {
                 || failed!(target: Release, Compilation => "dependency not satisfied: {}", field),
             )?
             .into_model();
-        let as_scope = Scope::new_root().as_within(field);
+        let as_scope = Scope::new_root().into_within(field);
         match self
             .vtable
             .get_mut(&self.scope)
@@ -934,7 +934,7 @@ where
     }
 
     fn issue(&mut self, what: &Scope, to: &Scope) -> Result<Option<View<G>>> {
-        let (root, relative_what) = what.relativize(&to);
+        let (root, relative_what) = what.relativize(to);
         let relative_to = to.as_in(&root).unwrap();
         self.get_mut(&root)
             .with_context(|| anyhow!(
@@ -954,7 +954,7 @@ pub struct Crawler<'t, 'a> {
 
 impl<'t, 'a: 't> Crawler<'t, 'a> {
     fn as_at(&mut self, field: &str, content: &'a Content) -> Crawler<'_, 'a> {
-        let position = self.position.clone().as_at(field);
+        let position = self.position.clone().into_at(field);
         stage_1!("entering {}", position);
         Crawler {
             cursor: self.cursor.entry(field).or_init(content),
diff --git a/core/src/compile/utils.rs b/core/src/compile/utils.rs
index becbf746..ac73c6af 100644
--- a/core/src/compile/utils.rs
+++ b/core/src/compile/utils.rs
@@ -420,6 +420,7 @@ where
 
     type Return = G::Return;
 
+    #[allow(clippy::needless_collect)]
     fn next<R: Rng>(&mut self, rng: &mut R) -> GeneratorState<Self::Yield, Self::Return> {
         if self.is_complete {
             debug!("> scoped generator cycle BEGIN");
@@ -465,7 +466,7 @@ pub mod tests {
         let mut rng = rand::thread_rng();
         let initial_buf_len = 100;
         // Single view
-        for threshold in vec![0, 1, 10] {
+        for threshold in [0, 1, 10] {
             let seed = 1.yield_token();
             let (mut driver, mut cursor) = channel(seed);
             let mut view = cursor.view();
@@ -487,7 +488,7 @@ pub mod tests {
             );
         }
         // Multiple views
-        for threshold in vec![0, 1, 10] {
+        for threshold in [0, 1, 10] {
             struct TestView<G>
             where
                 G: Generator,
@@ -514,7 +515,7 @@ pub mod tests {
                 driver.next(&mut rng);
             }
             cursor.mark();
-            while view_pos.len() > 0 {
+            while !view_pos.is_empty() {
                 let i: usize = (rng.next_u32() as usize) % view_pos.len();
                 view_pos[i].pos += 1;
                 view_pos[i]
diff --git a/core/src/graph/array.rs b/core/src/graph/array.rs
index 27b62beb..96b28bad 100644
--- a/core/src/graph/array.rs
+++ b/core/src/graph/array.rs
@@ -28,12 +28,12 @@ impl Generator for RandomArray {
     }
 }
 
+type ArrayNodeInner = AndThenTry<OwnedDevaluize<Box<Graph>, u64>, Box<dyn Fn(u64) -> RandomArray>, RandomArray>;
+
 derive_generator! {
     yield Token,
     return Result<Value, Error>,
-    pub struct ArrayNode(
-    AndThenTry<OwnedDevaluize<Box<Graph>, u64>, Box<dyn Fn(u64) -> RandomArray>, RandomArray>
-    );
+    pub struct ArrayNode(ArrayNodeInner);
 }
 
 impl ArrayNode {
diff --git a/core/src/graph/mod.rs b/core/src/graph/mod.rs
index d6a4c8d5..cc109acf 100644
--- a/core/src/graph/mod.rs
+++ b/core/src/graph/mod.rs
@@ -640,11 +640,15 @@ pub mod tests {
         let range = RangeStep::new(-2.5, 1.0, 1.5);
         let dist = UniformRangeStep::try_from(range).unwrap();
         let mut rng = thread_rng();
+        let error_margin = f64::EPSILON;
         for _ in 1..1000 {
-            let sample = dist.sample(&mut rng);
+            let sample: f64 = dist.sample(&mut rng);
             // Not using pattern matching here because of  <https://github.com/rust-lang/rust/issues/41620>.
             // As of 2020-12-01 it causes a linter warning which will be a compiler error in future releases.
-            if sample == -2.5 || sample == -1.0 || sample == 0.5 {
+            if (sample - -2.5).abs() < error_margin || 
+                (sample - -1.0).abs() < error_margin || 
+                (sample - 0.5).abs() < error_margin 
+            {
             } else {
                 panic!("Generated '{}' which should not happen", sample)
             }
diff --git a/core/src/graph/number.rs b/core/src/graph/number.rs
index fd927235..2aef0e79 100644
--- a/core/src/graph/number.rs
+++ b/core/src/graph/number.rs
@@ -84,6 +84,15 @@ impl<N> Incrementing<N> {
     }
 }
 
+impl<N> Default for Incrementing<N>
+where
+    N: Zero + One,
+{
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
 impl<N> Generator for Incrementing<N>
 where
     N: CheckedAdd + Copy,
diff --git a/core/src/graph/series.rs b/core/src/graph/series.rs
index 12ceb87a..01572404 100644
--- a/core/src/graph/series.rs
+++ b/core/src/graph/series.rs
@@ -30,7 +30,7 @@ impl TryFrom<&SeriesContent> for SeriesNode {
         let fmt = series_content.format.as_ref().unwrap_or(&default_pattern);
         let sn = match &series_content.variant {
             SeriesVariant::Incrementing(incrementing) => {
-                let incrementing_series = SeriesVariant::inc(&incrementing, &fmt)?;
+                let incrementing_series = SeriesVariant::inc(incrementing, fmt)?;
                 let sf = SeriesFormatter {
                     inner: incrementing_series,
                     format: fmt.clone(),
@@ -43,7 +43,7 @@ impl TryFrom<&SeriesContent> for SeriesNode {
                 )
             }
             SeriesVariant::Poisson(poisson) => {
-                let poisson_series = SeriesVariant::poisson(&poisson, &fmt)?;
+                let poisson_series = SeriesVariant::poisson(poisson, fmt)?;
                 let sf = SeriesFormatter {
                     inner: poisson_series,
                     format: fmt.clone(),
@@ -56,7 +56,7 @@ impl TryFrom<&SeriesContent> for SeriesNode {
                 )
             }
             SeriesVariant::Cyclical(cyclical) => {
-                let cyclical_series = SeriesVariant::cyclical(&cyclical, &fmt)?;
+                let cyclical_series = SeriesVariant::cyclical(cyclical, fmt)?;
                 let sf = SeriesFormatter {
                     inner: cyclical_series,
                     format: fmt.clone(),
@@ -69,7 +69,7 @@ impl TryFrom<&SeriesContent> for SeriesNode {
                 )
             }
             SeriesVariant::Zip(zip) => {
-                let zip_series = SeriesVariant::zip(&zip, &fmt)?;
+                let zip_series = SeriesVariant::zip(zip, fmt)?;
                 let sf = SeriesFormatter {
                     inner: zip_series,
                     format: fmt.clone(),
@@ -350,7 +350,7 @@ pub mod tests {
     fn test_poisson() {
         let initial = ndt("2000-01-01 15:15:15");
         let mut poisson = PoissonSeries {
-            current: initial.clone().into(),
+            current: initial,
             rate: Duration::days(365),
         };
 
@@ -368,8 +368,8 @@ pub mod tests {
     fn test_cyclical() {
         let initial = ndt("2000-01-01 00:00:00");
         let mut cyclical = CyclicalSeries {
-            start: initial.clone().into(),
-            current: initial.clone().into(),
+            start: initial,
+            current: initial,
             period: Duration::weeks(1),
             min_rate: Duration::minutes(10),
             max_rate: Duration::hours(2),
diff --git a/core/src/graph/string/faker.rs b/core/src/graph/string/faker.rs
index 0030894b..f1f7b68b 100644
--- a/core/src/graph/string/faker.rs
+++ b/core/src/graph/string/faker.rs
@@ -157,7 +157,7 @@ lazy_static! {
 fn address(rng: &mut dyn RngCore, args: &FakerArgs) -> String {
     // Here we get a single locale
     let args = &FakerArgs {
-        locales: vec![args.locales.first().unwrap_or(&Locale::EN).clone()],
+        locales: vec![*args.locales.first().unwrap_or(&Locale::EN)],
     };
 
     let number = (FAKE_MAP.get("building_number").unwrap())(rng, args);
@@ -178,7 +178,7 @@ impl RandFaker {
             None => Err(anyhow!(
                 "Generator '{}' does not exist {}",
                 generator.as_ref(),
-                suggest_closest(FAKE_MAP.keys(), &generator.as_ref())
+                suggest_closest(FAKE_MAP.keys(), generator.as_ref())
                     .unwrap_or_else(|| "".to_string())
             )),
             Some(generator) => Ok(Self {
diff --git a/core/src/graph/string/serialized.rs b/core/src/graph/string/serialized.rs
index f128fc27..da9770f7 100644
--- a/core/src/graph/string/serialized.rs
+++ b/core/src/graph/string/serialized.rs
@@ -8,7 +8,7 @@ use std::ops::DerefMut;
 
 // This is not great but I don't want Serialized to be generic
 enum SerializerType {
-    JSON,
+    Json,
 }
 
 pub struct Serialized {
@@ -20,13 +20,13 @@ impl Serialized {
     pub fn new_json(inner: Graph) -> Self {
         Self {
             inner: Box::new(inner.try_aggregate()),
-            serializer: SerializerType::JSON,
+            serializer: SerializerType::Json,
         }
     }
 
     fn serialize<S: Serialize>(&self, s: &S) -> String {
         match self.serializer {
-            SerializerType::JSON => {
+            SerializerType::Json => {
                 format!(
                     "{}",
                     serde_json::to_value(&s).expect("this should always serialize")
diff --git a/core/src/schema/content/object.rs b/core/src/schema/content/object.rs
index b80cab91..3988b109 100644
--- a/core/src/schema/content/object.rs
+++ b/core/src/schema/content/object.rs
@@ -129,6 +129,10 @@ impl ObjectContent {
     pub fn len(&self) -> usize {
         self.fields.len()
     }
+
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
diff --git a/core/src/schema/content/one_of.rs b/core/src/schema/content/one_of.rs
index b803a12d..692f6403 100644
--- a/core/src/schema/content/one_of.rs
+++ b/core/src/schema/content/one_of.rs
@@ -77,7 +77,7 @@ impl OneOfContent {
             .find(|variant| *variant.content == candidate)
         {
             None => self.add_variant(candidate),
-            Some(master) => master.weight.0 = master.weight.0 + 1.0,
+            Some(master) => master.weight.0 += 1.0,
         }
     }
 
diff --git a/core/src/schema/content/series.rs b/core/src/schema/content/series.rs
index 3119b162..3a1b8bb4 100644
--- a/core/src/schema/content/series.rs
+++ b/core/src/schema/content/series.rs
@@ -91,10 +91,10 @@ impl SeriesVariant {
         let mut children = Vec::new();
         for child in &zip.series {
             let series = match child {
-                SeriesVariant::Incrementing(inc) => TimeSeries::Incrementing(Self::inc(&inc, fmt)?),
-                SeriesVariant::Poisson(poi) => TimeSeries::Poisson(Self::poisson(&poi, fmt)?),
-                SeriesVariant::Cyclical(cyc) => TimeSeries::Cyclical(Self::cyclical(&cyc, fmt)?),
-                SeriesVariant::Zip(zip) => TimeSeries::Zip(Self::zip(&zip, fmt)?),
+                SeriesVariant::Incrementing(inc) => TimeSeries::Incrementing(Self::inc(inc, fmt)?),
+                SeriesVariant::Poisson(poi) => TimeSeries::Poisson(Self::poisson(poi, fmt)?),
+                SeriesVariant::Cyclical(cyc) => TimeSeries::Cyclical(Self::cyclical(cyc, fmt)?),
+                SeriesVariant::Zip(zip) => TimeSeries::Zip(Self::zip(zip, fmt)?),
             };
             children.push(series);
         }
diff --git a/core/src/schema/content/string.rs b/core/src/schema/content/string.rs
index 2fa5ca36..b1825eac 100644
--- a/core/src/schema/content/string.rs
+++ b/core/src/schema/content/string.rs
@@ -173,7 +173,7 @@ impl FakerContent {
 #[serde(rename_all = "lowercase")]
 #[serde(tag = "serializer")]
 pub enum SerializedContent {
-    JSON(JsonContent),
+    Json(JsonContent),
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
@@ -447,7 +447,7 @@ pub mod datetime_content {
     }
 
     impl SerdeDateTimeContent {
-        pub(super) fn to_datetime_content(self) -> Result<DateTimeContent> {
+        pub(super) fn into_datetime_content(self) -> Result<DateTimeContent> {
             debug!("interpreting a shadow datetime content {:?}", self);
 
             let src = &self.format;
@@ -465,8 +465,8 @@ pub mod datetime_content {
                     return Err(failed!(
                         target: Release,
                         "begin is after end: begin={}, end={}",
-                        fmt.format(&begin).unwrap(), // should be alright exactly at this point
-                        fmt.format(&end).unwrap()
+                        fmt.format(begin).unwrap(), // should be alright exactly at this point
+                        fmt.format(end).unwrap()
                     ));
                 }
             }
@@ -523,7 +523,7 @@ impl<'de> Deserialize<'de> for DateTimeContent {
         D: serde::Deserializer<'de>,
     {
         datetime_content::SerdeDateTimeContent::deserialize(deserializer)
-            .and_then(|inter| inter.to_datetime_content().map_err(D::Error::custom))
+            .and_then(|inter| inter.into_datetime_content().map_err(D::Error::custom))
     }
 }
 
@@ -557,11 +557,11 @@ impl Compile for StringContent {
                     .clone()
                     .unwrap_or_else(|| ChronoValue::default_of(ChronoValue::origin(), *type_));
                 let end = end.clone().unwrap_or(begin.clone() + Duration::weeks(52));
-                RandomDateTime::new(begin..end, &format).into()
+                RandomDateTime::new(begin..end, format).into()
             }
             StringContent::Categorical(cat) => RandomString::from(cat.clone()).into(),
             StringContent::Serialized(sc) => match sc {
-                SerializedContent::JSON(serialized_json_content) => {
+                SerializedContent::Json(serialized_json_content) => {
                     let inner = serialized_json_content.content.compile(compiler)?;
                     RandomString::from(Serialized::new_json(inner)).into()
                 }
diff --git a/core/src/schema/inference/mod.rs b/core/src/schema/inference/mod.rs
index c8ee4f3d..5951a40f 100644
--- a/core/src/schema/inference/mod.rs
+++ b/core/src/schema/inference/mod.rs
@@ -467,6 +467,7 @@ pub mod tests {
             "step": 1
             }
         });
+        let error_margin = f64::EPSILON;
 
         OptionalMergeStrategy
             .try_merge(&mut master, &"15".parse().unwrap())
@@ -506,9 +507,9 @@ pub mod tests {
 
         match master {
             NumberContent::F64(number_content::F64::Range(RangeStep { low, high, step })) => {
-                assert_eq!(low, -13.6);
-                assert_eq!(high, 20.6);
-                assert_eq!(step, 1.);
+                assert!((low - -13.6).abs() < error_margin);
+                assert!((high - 20.6).abs() < error_margin);
+                assert!((step - 1.).abs() < error_margin);
             }
             _ => unreachable!(),
         }
diff --git a/core/src/schema/mod.rs b/core/src/schema/mod.rs
index 80d8e464..076e75f6 100644
--- a/core/src/schema/mod.rs
+++ b/core/src/schema/mod.rs
@@ -185,7 +185,7 @@ impl FieldRef {
 enum ParseState {
     Collection,
     Chunk,
-    EOF,
+    Eof,
 }
 
 struct Lexer {
@@ -207,11 +207,11 @@ impl Lexer {
     }
 
     fn peak(&self) -> &Token {
-        self.tokens.front().unwrap_or(&Token::EOF)
+        self.tokens.front().unwrap_or(&Token::Eof)
     }
 
     fn eat_next(&mut self) -> Token {
-        self.tokens.pop_front().unwrap_or(Token::EOF)
+        self.tokens.pop_front().unwrap_or(Token::Eof)
     }
 }
 
@@ -235,12 +235,12 @@ impl Parser {
     }
 
     fn parse(mut self) -> Result<FieldRef> {
-        while self.state != ParseState::EOF {
+        while self.state != ParseState::Eof {
             let token = self.lex.eat_next();
             match self.state {
                 ParseState::Collection => self.parse_coll(token)?,
                 ParseState::Chunk => self.parse_chunk(token)?,
-                ParseState::EOF => {
+                ParseState::Eof => {
                     unreachable!();
                 }
             };
@@ -267,7 +267,7 @@ impl Parser {
                 }
                 self.state = ParseState::Chunk;
             }
-            Token::EOF => {
+            Token::Eof => {
                 if self.collection.is_empty() {
                     return Err(failed!(
                         target: Release,
@@ -275,7 +275,7 @@ impl Parser {
                         "cannot have an empty collection name"
                     ));
                 }
-                self.state = ParseState::EOF;
+                self.state = ParseState::Eof;
             }
             Token::Quote => {
                 return Err(
@@ -292,7 +292,7 @@ impl Parser {
                 self.curr_chunk.push_str(&c);
             }
             Token::Dot => {
-                if self.lex.peak() == &Token::EOF {
+                if self.lex.peak() == &Token::Eof {
                     return Err(
                         failed!(target: Release, BadRequest => "cannot have a field ref that ends in a '.'"),
                     );
@@ -313,14 +313,14 @@ impl Parser {
                 }
                 self.parse_quote_content()?;
             }
-            Token::EOF => {
+            Token::Eof => {
                 if self.curr_chunk.is_empty() {
                     return Err(
                         failed!(target: Release, BadRequest => "cannot have an empty chunk in field ref"),
                     );
                 }
                 self.field_chunks.push(self.curr_chunk.clone());
-                self.state = ParseState::EOF;
+                self.state = ParseState::Eof;
             }
         }
         Ok(())
@@ -332,7 +332,7 @@ impl Parser {
             match self.lex.eat_next() {
                 Token::Char(c) => self.curr_chunk.push_str(&c),
                 Token::Dot => self.curr_chunk.push('.'),
-                Token::EOF => {
+                Token::Eof => {
                     return Err(
                         failed!(target: Release, BadRequest => "cannot have unclosed quotes"),
                     )
@@ -355,7 +355,7 @@ impl Parser {
 enum Token {
     Char(String),
     Dot,
-    EOF,
+    Eof,
     Quote,
 }
 
diff --git a/core/src/schema/optionalise.rs b/core/src/schema/optionalise.rs
index be2446a7..036bcc08 100644
--- a/core/src/schema/optionalise.rs
+++ b/core/src/schema/optionalise.rs
@@ -75,7 +75,7 @@ pub mod tests {
         ns.optionalise(optionalise).unwrap();
 
         let unoptionalise = Optionalise {
-            at: field.clone(),
+            at: field,
             optional: false,
         };
         ns.optionalise(unoptionalise).unwrap();
@@ -88,7 +88,7 @@ pub mod tests {
         let mut ns = USER_NAMESPACE.clone();
         let field = FieldRef::new("users.address.numbers".to_string()).unwrap();
         let optionalise = Optionalise {
-            at: field.clone(),
+            at: field,
             optional: true,
         };
         ns.optionalise(optionalise.clone()).unwrap();
@@ -106,7 +106,7 @@ pub mod tests {
             optional: true,
         };
         let unoptionalise = Optionalise {
-            at: field.clone(),
+            at: field,
             optional: false,
         };
         assert!(ns.optionalise(optionalise).is_err());
@@ -122,7 +122,7 @@ pub mod tests {
             optional: true,
         };
         let unoptionalise = Optionalise {
-            at: field.clone(),
+            at: field,
             optional: false,
         };
         assert!(ns.optionalise(optionalise).is_err());
diff --git a/core/src/schema/s_override.rs b/core/src/schema/s_override.rs
index f0e7ed78..1f1cabe8 100644
--- a/core/src/schema/s_override.rs
+++ b/core/src/schema/s_override.rs
@@ -214,8 +214,7 @@ pub mod tests {
                 content,
             }) => match content.as_mut() {
                 Content::OneOf(one_of_content) => {
-                    let variants = one_of_content.iter().collect::<Vec<_>>();
-                    assert_eq!(variants.len(), 3);
+                    assert_eq!(one_of_content.iter().count(), 3);
                 }
                 _ => unreachable!(),
             },
diff --git a/dist/playground/src/app.rs b/dist/playground/src/app.rs
index e443659d..84d5911d 100644
--- a/dist/playground/src/app.rs
+++ b/dist/playground/src/app.rs
@@ -45,9 +45,7 @@ impl State {
                 GeneratorState::Yielded(yielded) => {
                     if stream.len() > self.max_size {
                         warn!("aborting: too large");
-                        let text = format!(
-                            "generated too many tokens: try generating less data by controlling (for example) the `length` parameter of arrays or using the `?size=` query parameter"
-                        );
+                        let text = "generated too many tokens: try generating less data by controlling (for example) the `length` parameter of arrays or using the `?size=` query parameter".to_string();
                         let body = ErrorResponseBody {
                             kind: "illegal",
                             text: Some(text),
@@ -87,7 +85,7 @@ impl std::fmt::Display for ErrorResponseBody {
             f,
             "{}: {}",
             self.kind,
-            self.text.as_ref().map(|s| s.as_str()).unwrap_or("unknown")
+            self.text.as_deref().unwrap_or("unknown")
         )
     }
 }
@@ -132,18 +130,16 @@ async fn put_compile(mut req: Request<State>) -> tide::Result {
                 };
                 let resp = Response::builder(400).body(Body::from_json(&body)?).build();
                 Ok(resp)
+            } else if let Some(app_err) = err.downcast_ref::<ErrorResponseBody>() {
+                let resp = Response::builder(400)
+                    .body(Body::from_json(&app_err)?)
+                    .build();
+                Ok(resp)
             } else {
-                if let Some(app_err) = err.downcast_ref::<ErrorResponseBody>() {
-                    let resp = Response::builder(400)
-                        .body(Body::from_json(&app_err)?)
-                        .build();
-                    Ok(resp)
-                } else {
-                    let resp = Response::builder(500)
-                        .body(Body::from_string(err.to_string()))
-                        .build();
-                    Ok(resp)
-                }
+                let resp = Response::builder(500)
+                    .body(Body::from_string(err.to_string()))
+                    .build();
+                Ok(resp)
             }
         }
     }
@@ -166,7 +162,7 @@ pub async fn serve(args: ServeCmd) -> Result<()> {
     let mut app = tide::with_state(state);
     let mut root = app.at(&mount);
 
-    root.put(|req: Request<State>| put_compile(req));
+    root.put(put_compile);
 
     let cors = CorsMiddleware::new()
         .allow_methods(allow_methods.parse::<HeaderValue>().unwrap())
@@ -199,10 +195,7 @@ pub mod tests {
         let as_value: Value = serde_json::from_str(&as_str)?;
         match as_value {
             Value::Array(arr) if arr.len() == 10 => {
-                let all_objects = arr.into_iter().all(|elt| match elt {
-                    Value::Object(_obj) => true,
-                    _ => false,
-                });
+                let all_objects = arr.into_iter().all(|elt| matches!(elt, Value::Object(_)));
                 assert!(all_objects);
             }
             _ => panic!("incorrectly generated: {}", as_str),
diff --git a/synth/src/cli/export.rs b/synth/src/cli/export.rs
index 6b246792..38fe731b 100644
--- a/synth/src/cli/export.rs
+++ b/synth/src/cli/export.rs
@@ -93,7 +93,7 @@ pub(crate) fn create_and_insert_values<T: DataSource>(params: ExportParams, data
                     .as_array()
                     .expect("This is always a collection (sampler contract)");
 
-                insert_data(datasource, collection_name.clone(), &collection_json)?;
+                insert_data(datasource, collection_name.clone(), collection_json)?;
             }
 
             Ok(())
@@ -104,7 +104,7 @@ pub(crate) fn create_and_insert_values<T: DataSource>(params: ExportParams, data
     }
 }
 
-fn insert_data<T: DataSource>(datasource: &T, collection_name: String, collection_json: &Vec<Value>)
+fn insert_data<T: DataSource>(datasource: &T, collection_name: String, collection_json: &[Value])
     -> Result<()> {
     task::block_on(
         datasource.insert_data(
diff --git a/synth/src/cli/import.rs b/synth/src/cli/import.rs
index ace033b7..ea0ecd34 100644
--- a/synth/src/cli/import.rs
+++ b/synth/src/cli/import.rs
@@ -104,7 +104,7 @@ fn collection_from_value(value: &Value) -> Result<Content> {
     match value {
         Value::Array(values) => {
             let fst = values.get(0).unwrap_or(&Value::Null);
-            let mut as_content = Namespace::collection(&fst);
+            let mut as_content = Namespace::collection(fst);
             OptionalMergeStrategy.try_merge(&mut as_content, value)?;
             Ok(as_content)
         }
diff --git a/synth/src/cli/import_utils.rs b/synth/src/cli/import_utils.rs
index 352c8846..90eadb55 100644
--- a/synth/src/cli/import_utils.rs
+++ b/synth/src/cli/import_utils.rs
@@ -21,7 +21,7 @@ struct FieldContentWrapper(FieldContent);
 pub(crate) fn build_namespace_import<T: DataSource + RelationalDataSource>(datasource: &T)
     -> Result<Namespace> {
     let table_names = task::block_on(datasource.get_table_names())
-        .with_context(|| format!("Failed to get table names"))?;
+        .with_context(|| "Failed to get table names".to_string())?;
 
     let mut namespace = Namespace::default();
 
@@ -41,14 +41,14 @@ pub(crate) fn build_namespace_import<T: DataSource + RelationalDataSource>(datas
 }
 
 fn populate_namespace_collections<T: DataSource + RelationalDataSource>(
-    namespace: &mut Namespace, table_names: &Vec<String>, datasource: &T) -> Result<()> {
+    namespace: &mut Namespace, table_names: &[String], datasource: &T) -> Result<()> {
     for table_name in table_names.iter() {
         info!("Building {} collection...", table_name);
 
         let column_infos = task::block_on(datasource.get_columns_infos(table_name))?;
 
         namespace.put_collection(
-            &Name::from_str(&table_name)?,
+            &Name::from_str(table_name)?,
             Collection::try_from((datasource, column_infos))?.collection,
         )?;
     }
@@ -57,7 +57,7 @@ fn populate_namespace_collections<T: DataSource + RelationalDataSource>(
 }
 
 fn populate_namespace_primary_keys<T: DataSource + RelationalDataSource>(
-    namespace: &mut Namespace, table_names: &Vec<String>, datasource: &T) -> Result<()> {
+    namespace: &mut Namespace, table_names: &[String], datasource: &T) -> Result<()> {
     for table_name in table_names.iter() {
         let primary_keys = task::block_on(datasource.get_primary_keys(table_name))?;
 
@@ -97,15 +97,15 @@ fn populate_namespace_foreign_keys<T: DataSource + RelationalDataSource>(
 }
 
 fn populate_namespace_values<T: DataSource + RelationalDataSource>(
-    namespace: &mut Namespace, table_names: &Vec<String>, datasource: &T) -> Result<()> {
+    namespace: &mut Namespace, table_names: &[String], datasource: &T) -> Result<()> {
     task::block_on(datasource.set_seed())?;
 
     for table in table_names {
-        let values = task::block_on(datasource.get_deterministic_samples(&table))?;
+        let values = task::block_on(datasource.get_deterministic_samples(table))?;
 
         namespace.try_update(
             OptionalMergeStrategy,
-            &Name::from_str(&table).unwrap(),
+            &Name::from_str(table).unwrap(),
             &Value::from(values),
         )?;
     }
diff --git a/synth/src/cli/mod.rs b/synth/src/cli/mod.rs
index 86eb1065..a14f06c9 100644
--- a/synth/src/cli/mod.rs
+++ b/synth/src/cli/mod.rs
@@ -168,9 +168,8 @@ impl Cli {
         PathBuf::from(".synth").join("config.toml").exists()
     }
 
-    fn workspace_initialised_from_path(&self, init_path: &PathBuf) -> bool {
-        let config_path = init_path.join(".synth").join("config.toml");
-        Path::new(&config_path).exists()
+    fn workspace_initialised_from_path(&self, init_path: &Path) -> bool {
+        init_path.join(".synth").join("config.toml").exists()
     }
 
     fn import(
diff --git a/synth/src/cli/mongo.rs b/synth/src/cli/mongo.rs
index 85db083d..8e04bd3f 100644
--- a/synth/src/cli/mongo.rs
+++ b/synth/src/cli/mongo.rs
@@ -90,7 +90,7 @@ impl ImportStrategy for MongoImportStrategy {
     }
 
     fn import_collection(self, name: &Name) -> Result<Content> {
-        self.import()?.collections.remove(name).ok_or(anyhow!(
+        self.import()?.collections.remove(name).ok_or_else(|| anyhow!(
             "Could not find table '{}' in MongoDb database.",
             name
         ))
@@ -178,7 +178,7 @@ impl ExportStrategy for MongoExportStrategy {
                 for (collection_name, collection_json) in namespace_json {
                     self.insert_data(
                         collection_name,
-                        &collection_json
+                        collection_json
                             .as_array()
                             .expect("This is always a collection (sampler contract)"),
                         &mut client,
@@ -197,7 +197,7 @@ impl MongoExportStrategy {
     fn insert_data(
         &self,
         collection_name: String,
-        collection: &Vec<Value>,
+        collection: &[Value],
         client: &mut Client,
     ) -> Result<()> {
         let db_name = parse_db_name(&self.uri)?;
@@ -232,7 +232,7 @@ impl MongoExportStrategy {
 
 fn parse_db_name(uri: &str) -> Result<&str> {
     // this may require a parser instead of `split`
-    uri.split("/").last().ok_or(anyhow!(
+    uri.split('/').last().ok_or_else(|| anyhow!(
         "Cannot export data. No database name specified in the uri"
     ))
 }
diff --git a/synth/src/cli/store.rs b/synth/src/cli/store.rs
index 5a59b75f..1910242d 100644
--- a/synth/src/cli/store.rs
+++ b/synth/src/cli/store.rs
@@ -149,7 +149,7 @@ pub mod tests {
         let store = Store::with_dir(path.clone());
         let ns = Namespace::default();
         let name = Name::from_str("users").unwrap();
-        store.save_ns(name.clone(), ns.clone())?;
+        store.save_ns(name, ns.clone())?;
 
         let saved_ns = store.get_ns(path.join("users"))?;
         assert_eq!(saved_ns, ns);
diff --git a/synth/src/datasource/mysql_datasource.rs b/synth/src/datasource/mysql_datasource.rs
index 57253e38..43b3fbb0 100644
--- a/synth/src/datasource/mysql_datasource.rs
+++ b/synth/src/datasource/mysql_datasource.rs
@@ -244,10 +244,7 @@ fn extract_column_char_max_len(index: usize, row: MySqlRow) -> Result<Option<i32
     let character_maximum_length = match row.try_get::<Option<i32>, usize>(index) {
         Ok(c) => c,
         Err(_) => {
-            match row.try_get::<Option<u64>, usize>(index)? {
-                None => None,
-                Some(c) => Some(c as i32)
-            }
+            row.try_get::<Option<u64>, usize>(index)?.map(|c| c as i32)
         }
     };
 
@@ -304,9 +301,9 @@ fn try_match_value(row: &MySqlRow, column: &MySqlColumn) -> Result<Value> {
         "bigint" => Value::Number(Number::from(row.try_get::<i64, &str>(column.name())?)),
         "serial" => Value::Number(Number::from(row.try_get::<u64, &str>(column.name())?)),
         "float" => Value::Number(Number::from_f64(row.try_get::<f32, &str>(column.name())? as f64)
-            .ok_or(anyhow!("Failed to convert float data type"))?),
+            .ok_or_else(|| anyhow!("Failed to convert float data type"))?),
         "double" => Value::Number(Number::from_f64(row.try_get::<f64, &str>(column.name())?)
-            .ok_or(anyhow!("Failed to convert double data type"))?),
+            .ok_or_else(|| anyhow!("Failed to convert double data type"))?),
         "numeric" | "decimal" => {
             let as_decimal = row.try_get::<Decimal, &str>(column.name())?;
 
diff --git a/synth/src/datasource/postgres_datasource.rs b/synth/src/datasource/postgres_datasource.rs
index 8467e1fe..c0c1146a 100644
--- a/synth/src/datasource/postgres_datasource.rs
+++ b/synth/src/datasource/postgres_datasource.rs
@@ -307,9 +307,9 @@ fn try_match_value(row: &PgRow, column: &PgColumn) -> Result<Value> {
         "int4" => Value::Number(Number::from(row.try_get::<i32, &str>(column.name())?)),
         "int8" => Value::Number(Number::from(row.try_get::<i64, &str>(column.name())?)),
         "float4" => Value::Number(Number::from_f64(row.try_get::<f32, &str>(column.name())? as f64)
-            .ok_or(anyhow!("Failed to convert float4 data type"))?), // TODO test f32, f64
+            .ok_or_else(|| anyhow!("Failed to convert float4 data type"))?), // TODO test f32, f64
         "float8" => Value::Number(Number::from_f64(row.try_get::<f64, &str>(column.name())?)
-            .ok_or(anyhow!("Failed to convert float8 data type"))?),
+            .ok_or_else(|| anyhow!("Failed to convert float8 data type"))?),
         "numeric" => {
             let as_decimal = row.try_get::<Decimal, &str>(column.name())?;
 


Test patch:
diff --git a/.github/workflows/synth-test.yml b/.github/workflows/synth-test.yml
index b6a63937..bfc7b183 100644
--- a/.github/workflows/synth-test.yml
+++ b/.github/workflows/synth-test.yml
@@ -23,4 +23,16 @@ jobs:
           toolchain: nightly-2021-05-17
       - run: |
           cargo +nightly-2021-05-17 test
+  clippy_test:
+    runs-on: runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [ ubuntu-latest, windows-latest ]
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          toolchain: nightly-2021-05-17
+          components: clippy
+      - run: cargo clippy --tests --all-targets -- -D warnings