aboutsummaryrefslogtreecommitdiff
path: root/entries/skairunner/src/main.rs
diff options
context:
space:
mode:
authorBraxton Hall2022-11-15 22:03:12 +0000
committerGitHub2022-11-15 22:03:12 +0000
commit36ddffec9fc05b0a3c99d30efa4d5b26bbde8c13 (patch)
treed6d81a76f86940161b80ec141c8e20e2b5d1756d /entries/skairunner/src/main.rs
parent6e7238a32e858ba0f297d65f66cd118434bc9d6a (diff)
parentf94507758c5786099025a82056c251ed9c9b8b17 (diff)
Merge pull request #85 from skairunner/sky/grpcnacci
skairunner: Make fibonacci generator
Diffstat (limited to 'entries/skairunner/src/main.rs')
-rw-r--r--entries/skairunner/src/main.rs117
1 files changed, 117 insertions, 0 deletions
diff --git a/entries/skairunner/src/main.rs b/entries/skairunner/src/main.rs
new file mode 100644
index 0000000..f9a5b4f
--- /dev/null
+++ b/entries/skairunner/src/main.rs
@@ -0,0 +1,117 @@
+use std::collections::HashMap;
+
+/// According to the protobuf specifications, 2^29-1 is the largest field number allowed.
+/// 1 is the smallest field number allowed.
+const MAX_FIELD_NUMBER: i32 = 536_870_911;
+
+const PROTOBUF_TYPES: &[&'static str] = &[
+ "double", "float", "int32", "int64", "uint32", "uint64", "sint64", "fixed32", "fixed64",
+ "sfixed32", "sfixed64", "bool", "string", "bytes",
+];
+
+/// According to protobuf specifications,
+/// fields 19000 thru 19999 are used by the compiler
+/// and are therefore illegal.
+fn field_number_is_illegal(n: i32) -> bool {
+ 19000 <= n && n <= 19999 || n <= 0
+}
+
+/// Create a valid memo object initialized with f(0) and f(1)
+fn init_memo() -> HashMap<i32, i32> {
+ let mut memo = HashMap::new();
+ memo.insert(0, 0);
+ memo.insert(1, 1);
+ memo
+}
+
+/// Generate the fibonacci sequence number of f(n),
+/// referencing the memo and updating it if needed.
+fn fib(n: i32, memo: &mut HashMap<i32, i32>) -> Option<i32> {
+ if let Some(number) = memo.get(&n) {
+ return Some(*number);
+ }
+ let f_n = memo.get(&(n - 1))? + memo.get(&(n - 2))?;
+ memo.insert(n, f_n);
+
+ Some(f_n)
+}
+
+/// Format prev and prevprev
+fn format_submessage(n: i32, memo: &mut HashMap<i32, i32>, name: &str) -> String {
+ let number = fib(n, memo);
+ match number {
+ None => String::new(),
+ Some(number) => {
+ if field_number_is_illegal(number) {
+ String::new()
+ } else {
+ format!(" Fibonacci{} {} = {};\n", n, name, number)
+ }
+ }
+ }
+}
+
+/// Generate a Fibonacci message.
+fn message_frame(n: i32, memo: &mut HashMap<i32, i32>) -> String {
+ let n_0 = fib(n, memo)
+ .map(|number| {
+ if field_number_is_illegal(number) {
+ format!(
+ " // There should be a fibonacci number here, but {} is illegal",
+ number
+ )
+ } else {
+ // Pick a semi-random type for the fib field
+ let type_name = PROTOBUF_TYPES[number as usize % PROTOBUF_TYPES.len()];
+ format!(" {} number = {};", type_name, number)
+ }
+ })
+ .unwrap_or_default();
+
+ let (n_minus_2, n_minus_1) = if n == 3 {
+ (String::new(), format_submessage(n - 1, memo, "prev"))
+ } else if n != 2 {
+ (
+ format_submessage(n - 2, memo, "prevprev"),
+ format_submessage(n - 1, memo, "prev"),
+ )
+ } else {
+ (String::new(), String::new())
+ };
+
+ format!(
+ "message Fibonacci{} {{\n\
+ {}{}{}
+}}",
+ n, n_minus_2, n_minus_1, n_0
+ )
+}
+
+fn main() {
+ let mut memo = init_memo();
+ let mut i = 1;
+ println!("syntax = \"proto3\";\n");
+ loop {
+ if fib(i, &mut memo) >= Some(MAX_FIELD_NUMBER) {
+ break;
+ }
+ println!("{}\n", message_frame(i, &mut memo));
+ i += 1;
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_small_fibs() {
+ let mut memo = init_memo();
+ assert_eq!(fib(0, &mut memo), Some(0));
+ assert_eq!(fib(1, &mut memo), Some(1));
+ assert_eq!(fib(2, &mut memo), Some(1));
+ assert_eq!(fib(3, &mut memo), Some(2));
+ assert_eq!(fib(4, &mut memo), Some(3));
+ assert_eq!(fib(5, &mut memo), Some(5));
+ }
+}