(* Generated by coq-of-rust *)
Require Import CoqOfRust.CoqOfRust.

(*
fn main() {
    #[derive(Debug)]
    struct Person {
        name: String,
        age: Box<u8>,
    }

    let person = Person {
        name: String::from("Alice"),
        age: Box::new(20),
    };

    // `name` is moved out of person, but `age` is referenced
    let Person { name, ref age } = person;

    println!("The person's age is {}", age);

    println!("The person's name is {}", name);

    // Error! borrow of partially moved value: `person` partial move occurs
    //println!("The person struct is {:?}", person);

    // `person` cannot be used but `person.age` can be used as it is not moved
    println!("The person's age from person struct is {}", person.age);
}
*)
Definition main (ε : list Value.t) (τ : list Ty.t) (α : list Value.t) : M :=
  match ε, τ, α with
  | [], [], [] =>
    ltac:(M.monadic
      (M.read (|
        let~ person :=
          M.alloc (|
            Value.StructRecord
              "scoping_rules_ownership_and_rules_partial_moves::main::Person"
              [
                ("name",
                  M.call_closure (|
                    M.get_trait_method (|
                      "core::convert::From",
                      Ty.path "alloc::string::String",
                      [ Ty.apply (Ty.path "&") [] [ Ty.path "str" ] ],
                      "from",
                      []
                    |),
                    [ M.read (| Value.String "Alice" |) ]
                  |));
                ("age",
                  M.call_closure (|
                    M.get_associated_function (|
                      Ty.apply
                        (Ty.path "alloc::boxed::Box")
                        []
                        [ Ty.path "u8"; Ty.path "alloc::alloc::Global" ],
                      "new",
                      []
                    |),
                    [ Value.Integer IntegerKind.U8 20 ]
                  |))
              ]
          |) in
        M.match_operator (|
          person,
          [
            fun γ =>
              ltac:(M.monadic
                (let γ0_0 :=
                  M.SubPointer.get_struct_record_field (|
                    γ,
                    "scoping_rules_ownership_and_rules_partial_moves::main::Person",
                    "name"
                  |) in
                let γ0_1 :=
                  M.SubPointer.get_struct_record_field (|
                    γ,
                    "scoping_rules_ownership_and_rules_partial_moves::main::Person",
                    "age"
                  |) in
                let name := M.copy (| γ0_0 |) in
                let age := M.alloc (| γ0_1 |) in
                let~ _ :=
                  let~ _ :=
                    M.alloc (|
                      M.call_closure (|
                        M.get_function (| "std::io::stdio::_print", [] |),
                        [
                          M.call_closure (|
                            M.get_associated_function (|
                              Ty.path "core::fmt::Arguments",
                              "new_v1",
                              []
                            |),
                            [
                              M.alloc (|
                                Value.Array
                                  [
                                    M.read (| Value.String "The person's age is " |);
                                    M.read (| Value.String "
" |)
                                  ]
                              |);
                              M.alloc (|
                                Value.Array
                                  [
                                    M.call_closure (|
                                      M.get_associated_function (|
                                        Ty.path "core::fmt::rt::Argument",
                                        "new_display",
                                        [
                                          Ty.apply
                                            (Ty.path "&")
                                            []
                                            [
                                              Ty.apply
                                                (Ty.path "alloc::boxed::Box")
                                                []
                                                [ Ty.path "u8"; Ty.path "alloc::alloc::Global" ]
                                            ]
                                        ]
                                      |),
                                      [ age ]
                                    |)
                                  ]
                              |)
                            ]
                          |)
                        ]
                      |)
                    |) in
                  M.alloc (| Value.Tuple [] |) in
                let~ _ :=
                  let~ _ :=
                    M.alloc (|
                      M.call_closure (|
                        M.get_function (| "std::io::stdio::_print", [] |),
                        [
                          M.call_closure (|
                            M.get_associated_function (|
                              Ty.path "core::fmt::Arguments",
                              "new_v1",
                              []
                            |),
                            [
                              M.alloc (|
                                Value.Array
                                  [
                                    M.read (| Value.String "The person's name is " |);
                                    M.read (| Value.String "
" |)
                                  ]
                              |);
                              M.alloc (|
                                Value.Array
                                  [
                                    M.call_closure (|
                                      M.get_associated_function (|
                                        Ty.path "core::fmt::rt::Argument",
                                        "new_display",
                                        [ Ty.path "alloc::string::String" ]
                                      |),
                                      [ name ]
                                    |)
                                  ]
                              |)
                            ]
                          |)
                        ]
                      |)
                    |) in
                  M.alloc (| Value.Tuple [] |) in
                let~ _ :=
                  let~ _ :=
                    M.alloc (|
                      M.call_closure (|
                        M.get_function (| "std::io::stdio::_print", [] |),
                        [
                          M.call_closure (|
                            M.get_associated_function (|
                              Ty.path "core::fmt::Arguments",
                              "new_v1",
                              []
                            |),
                            [
                              M.alloc (|
                                Value.Array
                                  [
                                    M.read (|
                                      Value.String "The person's age from person struct is "
                                    |);
                                    M.read (| Value.String "
" |)
                                  ]
                              |);
                              M.alloc (|
                                Value.Array
                                  [
                                    M.call_closure (|
                                      M.get_associated_function (|
                                        Ty.path "core::fmt::rt::Argument",
                                        "new_display",
                                        [
                                          Ty.apply
                                            (Ty.path "alloc::boxed::Box")
                                            []
                                            [ Ty.path "u8"; Ty.path "alloc::alloc::Global" ]
                                        ]
                                      |),
                                      [
                                        M.SubPointer.get_struct_record_field (|
                                          person,
                                          "scoping_rules_ownership_and_rules_partial_moves::main::Person",
                                          "age"
                                        |)
                                      ]
                                    |)
                                  ]
                              |)
                            ]
                          |)
                        ]
                      |)
                    |) in
                  M.alloc (| Value.Tuple [] |) in
                M.alloc (| Value.Tuple [] |)))
          ]
        |)
      |)))
  | _, _, _ => M.impossible "wrong number of arguments"
  end.

Axiom Function_main : M.IsFunction "scoping_rules_ownership_and_rules_partial_moves::main" main.

Module main.
  (* StructRecord
    {
      name := "Person";
      const_params := [];
      ty_params := [];
      fields :=
        [
          ("name", Ty.path "alloc::string::String");
          ("age",
            Ty.apply
              (Ty.path "alloc::boxed::Box")
              []
              [ Ty.path "u8"; Ty.path "alloc::alloc::Global" ])
        ];
    } *)
  
  Module Impl_core_fmt_Debug_for_scoping_rules_ownership_and_rules_partial_moves_main_Person.
    Definition Self : Ty.t :=
      Ty.path "scoping_rules_ownership_and_rules_partial_moves::main::Person".
    
    (*     Debug *)
    Definition fmt (ε : list Value.t) (τ : list Ty.t) (α : list Value.t) : M :=
      match ε, τ, α with
      | [], [], [ self; f ] =>
        ltac:(M.monadic
          (let self := M.alloc (| self |) in
          let f := M.alloc (| f |) in
          M.call_closure (|
            M.get_associated_function (|
              Ty.path "core::fmt::Formatter",
              "debug_struct_field2_finish",
              []
            |),
            [
              M.read (| f |);
              M.read (| Value.String "Person" |);
              M.read (| Value.String "name" |);
              M.SubPointer.get_struct_record_field (|
                M.read (| self |),
                "scoping_rules_ownership_and_rules_partial_moves::main::Person",
                "name"
              |);
              M.read (| Value.String "age" |);
              M.alloc (|
                M.SubPointer.get_struct_record_field (|
                  M.read (| self |),
                  "scoping_rules_ownership_and_rules_partial_moves::main::Person",
                  "age"
                |)
              |)
            ]
          |)))
      | _, _, _ => M.impossible "wrong number of arguments"
      end.
    
    Axiom Implements :
      M.IsTraitInstance
        "core::fmt::Debug"
        Self
        (* Trait polymorphic types *) []
        (* Instance *) [ ("fmt", InstanceField.Method fmt) ].
  End Impl_core_fmt_Debug_for_scoping_rules_ownership_and_rules_partial_moves_main_Person.
End main.
