From 14e4c95fe7b5c602c0a064aa6e05c031c05acc29 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Mon, 24 Jul 2023 13:44:52 +0200 Subject: [PATCH] Add a diagram of class --- README.md | 20 ++++++++++++-------- doc/class-uml.png | Bin 0 -> 74183 bytes doc/goals.md | 14 ++++++++++++++ src/lib.rs | 2 ++ 4 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 doc/class-uml.png create mode 100644 doc/goals.md diff --git a/README.md b/README.md index 50167ed..0af39e2 100644 --- a/README.md +++ b/README.md @@ -26,22 +26,19 @@ println!( ); ``` +[See more examples in the example/ folder](./example/) + ## About the name This library does not aim at implementing a specific RFC, but to be a swiss-army knife to decode and encode ("codec") what is generaly considered an email (generally abbreviated "eml"), hence the name: **eml-codec**. ## Goals -- Maintainability - modifying the code does not create regression and is possible for someone exterior to the project. Keep cyclomatic complexity low. -- Composability - build your own parser by picking the relevant passes, avoid work that is not needed. +- Maintainability - modifying the code does not create regression and is possible for someone exterior to the project. - Compatibility - always try to parse something, do not panic or return an error. - Exhaustivity - serve as a common project to encode knowledge about emails (existing mime types, existing headers, etc.). -## Non goals - - - Parsing optimization that would make more complicated to understand the logic. - - Optimization for a specific use case, to the detriment of other use cases. - - Pipelining/streaming/buffering as the parser can arbitrarily backtrack + our result contains reference to the whole buffer, eml-codec must keep the whole buffer in memory. Avoiding the sequential approach would certainly speed-up a little bit the parsing, but it's too much work to implement currently. +[See more about this library goals in the doc/ folder](./doc/goals.md) ## Missing / known bugs @@ -55,7 +52,9 @@ Current known limitations/bugs: ## Design -Speak about parser combinators. +High-level overview of the datastructures (inspired by the UML class diagram conventions): + +![Diagram of class made on Draw.io](./doc/class-uml.png) ## Testing strategy @@ -101,8 +100,13 @@ IANA ## State of the art / alternatives +*The following review is not an objective, neutral, impartial review. Instead, it's a temptative +to explain why I wrote this + `stalwartlab/mail_parser` +[See more about this library goals in the sota/ folder](./doc/sota.md) + ## Support `eml-codec`, as part of the [Aerogramme project](https://nlnet.nl/project/Aerogramme/), was funded through the NGI Assure Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 957073. diff --git a/doc/class-uml.png b/doc/class-uml.png new file mode 100644 index 0000000000000000000000000000000000000000..82a419e3ae89494b1db111dd8eefb0852f7e45a2 GIT binary patch literal 74183 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 E1=9z7qW}N^ literal 0 HcmV?d00001 diff --git a/doc/goals.md b/doc/goals.md new file mode 100644 index 0000000..3860c3e --- /dev/null +++ b/doc/goals.md @@ -0,0 +1,14 @@ +## Goals + +- Maintainability - modifying the code does not create regression and is possible for someone exterior to the project. Keep cyclomatic complexity low. +- Composability - build your own parser by picking the relevant passes, avoid work that is not needed. +- Compatibility - always try to parse something, do not panic or return an error. +- Exhaustivity - serve as a common project to encode knowledge about emails (existing mime types, existing headers, etc.). + +## Non goals + + - Parsing optimization that would make more complicated to understand the logic. + - Optimization for a specific use case, to the detriment of other use cases. + - Pipelining/streaming/buffering as the parser can arbitrarily backtrack + our result contains reference to the whole buffer, eml-codec must keep the whole buffer in memory. Avoiding the sequential approach would certainly speed-up a little bit the parsing, but it's too much work to implement currently. + + diff --git a/src/lib.rs b/src/lib.rs index 9201079..f952bf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![doc = include_str!("../README.md")] + mod error; mod header; mod imf;