(module main)

(enum Reading
  Missing
  (Value i32)
  (Offset i32))

(enum WideReading
  Missing
  (Value i64))

(enum RatioReading
  Missing
  (Value f64))

(enum FlagReading
  Missing
  (Value bool))

(enum LabelReading
  Missing
  (Value string))

(struct PayloadRecord
  (reading Reading)
  (wide WideReading)
  (ratio RatioReading)
  (flag FlagReading)
  (label LabelReading))

(fn value ((payload i32)) -> Reading
  (Reading.Value payload))

(fn echo_reading ((reading Reading)) -> Reading
  reading)

(fn local_reading ((payload i32)) -> Reading
  (let reading Reading (Reading.Value payload))
  reading)

(fn call_reading ((payload i32)) -> Reading
  (echo_reading (local_reading payload)))

(fn reading_code ((reading Reading)) -> i32
  (match reading
    ((Reading.Missing)
      0)
    ((Reading.Value payload)
      payload)
    ((Reading.Offset payload)
      (+ payload 100))))

(fn wide_value ((payload i64)) -> WideReading
  (WideReading.Value payload))

(fn echo_wide ((reading WideReading)) -> WideReading
  reading)

(fn local_wide ((payload i64)) -> WideReading
  (let reading WideReading (WideReading.Value payload))
  reading)

(fn call_wide ((payload i64)) -> WideReading
  (echo_wide (local_wide payload)))

(fn wide_code ((reading WideReading)) -> i64
  (match reading
    ((WideReading.Missing)
      0i64)
    ((WideReading.Value payload)
      payload)))

(fn ratio_value ((payload f64)) -> RatioReading
  (RatioReading.Value payload))

(fn ratio_code ((reading RatioReading)) -> f64
  (match reading
    ((RatioReading.Missing)
      0.0)
    ((RatioReading.Value payload)
      payload)))

(fn flag_value ((payload bool)) -> FlagReading
  (FlagReading.Value payload))

(fn flag_code ((reading FlagReading)) -> bool
  (match reading
    ((FlagReading.Missing)
      false)
    ((FlagReading.Value payload)
      payload)))

(fn label_value ((payload string)) -> LabelReading
  (LabelReading.Value payload))

(fn echo_label ((reading LabelReading)) -> LabelReading
  reading)

(fn local_label ((payload string)) -> LabelReading
  (let reading LabelReading (LabelReading.Value payload))
  reading)

(fn call_label ((payload string)) -> LabelReading
  (echo_label (local_label payload)))

(fn label_text ((reading LabelReading)) -> string
  (match reading
    ((LabelReading.Missing)
      "")
    ((LabelReading.Value payload)
      payload)))

(fn pack_record ((reading Reading) (wide WideReading) (ratio RatioReading) (flag FlagReading) (label LabelReading)) -> PayloadRecord
  (PayloadRecord (reading reading) (wide wide) (ratio ratio) (flag flag) (label label)))

(fn make_record () -> PayloadRecord
  (pack_record (Reading.Offset 5) (WideReading.Value 4294967296i64) (RatioReading.Value 3.5) (FlagReading.Value true) (LabelReading.Value "hello")))

(fn echo_record ((record PayloadRecord)) -> PayloadRecord
  record)

(fn local_record () -> PayloadRecord
  (let record PayloadRecord (make_record))
  (echo_record record))

(fn record_reading_code ((record PayloadRecord)) -> i32
  (reading_code (. record reading)))

(fn record_wide_code ((record PayloadRecord)) -> i64
  (wide_code (. record wide)))

(fn record_ratio_code ((record PayloadRecord)) -> f64
  (ratio_code (. record ratio)))

(fn record_flag_code ((record PayloadRecord)) -> bool
  (flag_code (. record flag)))

(fn record_label_text ((record PayloadRecord)) -> string
  (label_text (. record label)))

(test "i32 enum constructor equality"
  (= (Reading.Value 7) (value 7)))

(test "i32 enum equality compares payload"
  (if (= (Reading.Value 7) (Reading.Value 8))
    false
    true))

(test "i32 enum payloadless equality"
  (= (Reading.Missing) (echo_reading (Reading.Missing))))

(test "i32 enum local return call flow"
  (= (call_reading 9) (Reading.Value 9)))

(test "i64 enum constructor equality"
  (= (WideReading.Value 4294967296i64) (wide_value 4294967296i64)))

(test "i64 enum local return call flow"
  (= (call_wide 4294967297i64) (WideReading.Value 4294967297i64)))

(test "f64 enum constructor equality"
  (= (RatioReading.Value 3.5) (ratio_value 3.5)))

(test "f64 enum equality compares payload"
  (if (= (RatioReading.Value 3.5) (RatioReading.Value 4.5))
    false
    true))

(test "bool enum constructor equality"
  (= (FlagReading.Value true) (flag_value true)))

(test "bool enum match value"
  (flag_code (FlagReading.Value true)))

(test "string enum constructor equality"
  (= (LabelReading.Value "hello") (label_value "hello")))

(test "string enum equality compares payload"
  (if (= (LabelReading.Value "left") (LabelReading.Value "right"))
    false
    true))

(test "string enum local return call flow"
  (= (call_label "hello") (LabelReading.Value "hello")))

(test "struct field enum i32 flow"
  (= (record_reading_code (local_record)) 105))

(test "struct field enum i64 flow"
  (= (record_wide_code (local_record)) 4294967296i64))

(test "struct field enum f64 flow"
  (= (record_ratio_code (local_record)) 3.5))

(test "struct field enum bool flow"
  (record_flag_code (local_record)))

(test "struct field enum string flow"
  (= (record_label_text (local_record)) "hello"))

(fn main () -> i32
  (record_reading_code (local_record)))
