Repository: serde-rs/json (language: rust)

Issue:
[Deserialize] Split out peek logic from seed generic
Splits duplicated and somewhat complex logic depending on two generics (`Read` and `seed`) into only depending on one generic (`Read`) cutting debug mode llvm-lines output on my program by:
- `SeqAccess::next_element_seed`: 34232 -> 21752
- `MapAccess::next_key_seed`: 11225 -> 6722


Discussion / hints:

Fix patch:
diff --git a/src/de.rs b/src/de.rs
index 7959a6635..d6cb502da 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -1926,31 +1926,41 @@ impl<'de, 'a, R: Read<'de> + 'a> de::SeqAccess<'de> for SeqAccess<'a, R> {
     where
         T: de::DeserializeSeed<'de>,
     {
-        let peek = match tri!(self.de.parse_whitespace()) {
-            Some(b']') => {
-                return Ok(None);
-            }
-            Some(b',') if !self.first => {
-                self.de.eat_char();
-                tri!(self.de.parse_whitespace())
-            }
-            Some(b) => {
-                if self.first {
-                    self.first = false;
-                    Some(b)
-                } else {
-                    return Err(self.de.peek_error(ErrorCode::ExpectedListCommaOrEnd));
+        fn has_next_element<'de, 'a, R: Read<'de> + 'a>(
+            seq: &mut SeqAccess<'a, R>,
+        ) -> Result<bool> {
+            let peek = match tri!(seq.de.parse_whitespace()) {
+                Some(b']') => {
+                    return Ok(false);
                 }
+                Some(b',') if !seq.first => {
+                    seq.de.eat_char();
+                    tri!(seq.de.parse_whitespace())
+                }
+                Some(b) => {
+                    if seq.first {
+                        seq.first = false;
+                        Some(b)
+                    } else {
+                        return Err(seq.de.peek_error(ErrorCode::ExpectedListCommaOrEnd));
+                    }
+                }
+                None => {
+                    return Err(seq.de.peek_error(ErrorCode::EofWhileParsingList));
+                }
+            };
+
+            match peek {
+                Some(b']') => Err(seq.de.peek_error(ErrorCode::TrailingComma)),
+                Some(_) => Ok(true),
+                None => Err(seq.de.peek_error(ErrorCode::EofWhileParsingValue)),
             }
-            None => {
-                return Err(self.de.peek_error(ErrorCode::EofWhileParsingList));
-            }
-        };
+        }
 
-        match peek {
-            Some(b']') => Err(self.de.peek_error(ErrorCode::TrailingComma)),
-            Some(_) => Ok(Some(tri!(seed.deserialize(&mut *self.de)))),
-            None => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)),
+        if tri!(has_next_element(self)) {
+            Ok(Some(tri!(seed.deserialize(&mut *self.de))))
+        } else {
+            Ok(None)
         }
     }
 }
@@ -1973,32 +1983,40 @@ impl<'de, 'a, R: Read<'de> + 'a> de::MapAccess<'de> for MapAccess<'a, R> {
     where
         K: de::DeserializeSeed<'de>,
     {
-        let peek = match tri!(self.de.parse_whitespace()) {
-            Some(b'}') => {
-                return Ok(None);
-            }
-            Some(b',') if !self.first => {
-                self.de.eat_char();
-                tri!(self.de.parse_whitespace())
-            }
-            Some(b) => {
-                if self.first {
-                    self.first = false;
-                    Some(b)
-                } else {
-                    return Err(self.de.peek_error(ErrorCode::ExpectedObjectCommaOrEnd));
+        fn has_next_key<'de, 'a, R: Read<'de> + 'a>(map: &mut MapAccess<'a, R>) -> Result<bool> {
+            let peek = match tri!(map.de.parse_whitespace()) {
+                Some(b'}') => {
+                    return Ok(false);
                 }
+                Some(b',') if !map.first => {
+                    map.de.eat_char();
+                    tri!(map.de.parse_whitespace())
+                }
+                Some(b) => {
+                    if map.first {
+                        map.first = false;
+                        Some(b)
+                    } else {
+                        return Err(map.de.peek_error(ErrorCode::ExpectedObjectCommaOrEnd));
+                    }
+                }
+                None => {
+                    return Err(map.de.peek_error(ErrorCode::EofWhileParsingObject));
+                }
+            };
+
+            match peek {
+                Some(b'"') => Ok(true),
+                Some(b'}') => Err(map.de.peek_error(ErrorCode::TrailingComma)),
+                Some(_) => Err(map.de.peek_error(ErrorCode::KeyMustBeAString)),
+                None => Err(map.de.peek_error(ErrorCode::EofWhileParsingValue)),
             }
-            None => {
-                return Err(self.de.peek_error(ErrorCode::EofWhileParsingObject));
-            }
-        };
+        }
 
-        match peek {
-            Some(b'"') => seed.deserialize(MapKey { de: &mut *self.de }).map(Some),
-            Some(b'}') => Err(self.de.peek_error(ErrorCode::TrailingComma)),
-            Some(_) => Err(self.de.peek_error(ErrorCode::KeyMustBeAString)),
-            None => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)),
+        if tri!(has_next_key(self)) {
+            Ok(Some(tri!(seed.deserialize(MapKey { de: &mut *self.de }))))
+        } else {
+            Ok(None)
         }
     }
 


Test patch: