mlabs-haskell / lambda-buffers

LambdaBuffers toolkit for sharing types and their semantics between different languages
https://mlabs-haskell.github.io/lambda-buffers/
Apache License 2.0
29 stars 0 forks source link

Rust codegen #156

Closed szg251 closed 7 months ago

szg251 commented 7 months ago

Rust codegen generating types and trait implementations.

Based on the following LambdaBuffers definition:

module Example

import Prelude
import Plutus.V1 (PlutusData)
import qualified Plutus.V1 (Bytes, AssetClass, POSIXTime)

-- Using a phantom type has to expand the data type in Rust with PhantomData markers
prod Ref a = Plutus.V1.AssetClass

derive Eq (Ref a)
derive Json (Ref a)
derive PlutusData (Ref a)

-- Type recursions will be Boxed
record User = {
  name : Plutus.V1.Bytes,
  status : Status,
  friends : List (Ref User)
}

derive Eq User
derive Json User
derive PlutusData User

sum Status = Active Plutus.V1.POSIXTime | Inactive Plutus.V1.POSIXTime

derive Eq Status
derive Json Status
derive PlutusData Status

we get the following implementation (formatted for better readability):

#![no_implicit_prelude]
#![allow(warnings)]
extern crate lbf_plutus_v1;
extern crate lbf_prelude;
extern crate lbr_prelude;
extern crate num_bigint;
extern crate plutus_ledger_api;
extern crate serde_json;
extern crate std;

#[derive(std::fmt::Debug, std::clone::Clone)]
pub struct Ref<A>(
    lbf_plutus_v1::plutus::v1::AssetClass,
    std::marker::PhantomData<A>,
);

#[derive(std::fmt::Debug, std::clone::Clone)]
pub enum Status {
    Active(lbf_plutus_v1::plutus::v1::POSIXTime),
    Inactive(lbf_plutus_v1::plutus::v1::POSIXTime),
}

#[derive(std::fmt::Debug, std::clone::Clone)]
pub struct User {
    name: lbf_plutus_v1::plutus::v1::Bytes,
    status: Status,
    friends: std::boxed::Box<lbf_prelude::prelude::List<Ref<User>>>,
}

impl<A: std::cmp::PartialEq + std::clone::Clone> std::cmp::PartialEq for Ref<A> {
    fn eq<'a>(self: &'a Self, other: &'a Self) -> bool {
        std::boxed::Box::new(move |x0: &'a Self| {
            std::boxed::Box::new(move |x1: &'a Self| {
                let x2 = &x0.0;
                let x3 = &x1.0;
                lbr_prelude::lamval::eq(x2)(x3)
            })
        })(self)(other)
    }
}

impl<A: std::cmp::Eq + std::clone::Clone> std::cmp::Eq for Ref<A> {}

impl<A: lbr_prelude::json::Json + std::clone::Clone> lbr_prelude::json::Json for Ref<A> {
    fn to_json<'a>(self: &'a Self) -> serde_json::Value {
        std::boxed::Box::new(move |x0: &'a Self| {
            let x1 = &x0.0;
            <lbf_plutus_v1::plutus::v1::AssetClass>::to_json(x1)
        })(self)
    }
    fn from_json<'a>(
        value: &'a serde_json::Value,
    ) -> std::result::Result<Self, lbr_prelude::error::Error> {
        std::boxed::Box::new(move |x0: &_| {
            lbr_prelude::json::lamval::bind_parse(
                <lbf_plutus_v1::plutus::v1::AssetClass>::from_json(x0),
            )(std::boxed::Box::new(move |x1: &_| {
                std::result::Result::Ok(Ref(
                    <_ as std::clone::Clone>::clone(&x1),
                    std::marker::PhantomData,
                ))
            }))
        })(value)
    }
}

impl<A: plutus_ledger_api::plutus_data::IsPlutusData + std::clone::Clone>
    plutus_ledger_api::plutus_data::IsPlutusData for Ref<A>
{
    fn to_plutus_data<'a>(self: &'a Self) -> plutus_ledger_api::plutus_data::PlutusData {
        std::boxed::Box::new(move |x0: &'a Self| {
            let x1 = &x0.0;
            <lbf_plutus_v1::plutus::v1::AssetClass>::to_plutus_data(x1)
        })(self)
    }
    fn from_plutus_data<'a>(
        plutus_data: &'a plutus_ledger_api::plutus_data::PlutusData,
    ) -> std::result::Result<Self, plutus_ledger_api::plutus_data::PlutusDataError> {
        std::boxed::Box::new(move |x0: &'a plutus_ledger_api::plutus_data::PlutusData| {
            plutus_ledger_api::lamval::bind_parse(
                <lbf_plutus_v1::plutus::v1::AssetClass>::from_plutus_data(x0),
            )(std::boxed::Box::new(move |x1: &_| {
                std::result::Result::Ok(Ref(
                    <_ as std::clone::Clone>::clone(&x1),
                    std::marker::PhantomData,
                ))
            }))
        })(plutus_data)
    }
}

impl std::cmp::PartialEq for User {
    fn eq<'a>(self: &'a Self, other: &'a Self) -> bool {
        std::boxed::Box::new(move |x0: &'a Self| {
            std::boxed::Box::new(move |x1: &'a Self| {
                lbr_prelude::lamval::and(lbr_prelude::lamval::and(lbr_prelude::lamval::eq(
                    &x0.name,
                )(&x1.name))(lbr_prelude::lamval::eq(
                    &x0.status,
                )(&x1.status)))(lbr_prelude::lamval::eq(&x0.friends)(&x1.friends))
            })
        })(self)(other)
    }
}

impl std::cmp::Eq for User {}

impl lbr_prelude::json::Json for User {
    fn to_json<'a>(self: &'a Self) -> serde_json::Value {
        std::boxed::Box::new(move |x0: &'a Self| {
            lbr_prelude::json::lamval::json_object(std::vec![
                (
                    <_ as std::convert::From<&str>>::from("friends"),
                    <lbf_prelude::prelude::List<Ref<User>>>::to_json(&x0.friends)
                ),
                (
                    <_ as std::convert::From<&str>>::from("name"),
                    <lbf_plutus_v1::plutus::v1::Bytes>::to_json(&x0.name)
                ),
                (
                    <_ as std::convert::From<&str>>::from("status"),
                    <Status>::to_json(&x0.status)
                )
            ])
        })(self)
    }
    fn from_json<'a>(
        value: &'a serde_json::Value,
    ) -> std::result::Result<Self, lbr_prelude::error::Error> {
        lbr_prelude::json::lamval::case_json_object(std::boxed::Box::new(move |x0: &_| {
            lbr_prelude::json::lamval::json_field(<_ as std::convert::From<&str>>::from("name"))(x0)(
                std::boxed::Box::new(move |x1: &_| {
                    lbr_prelude::json::lamval::bind_parse(
                        <lbf_plutus_v1::plutus::v1::Bytes>::from_json(x1),
                    )(std::boxed::Box::new(move |x2: &_| {
                        lbr_prelude::json::lamval::json_field(
                            <_ as std::convert::From<&str>>::from("status"),
                        )(x0)(std::boxed::Box::new(move |x3: &_| {
                            lbr_prelude::json::lamval::bind_parse(<Status>::from_json(x3))(
                                std::boxed::Box::new(move |x4: &_| {
                                    lbr_prelude::json::lamval::json_field(
                                        <_ as std::convert::From<&str>>::from("friends"),
                                    )(x0)(std::boxed::Box::new(
                                        move |x5: &_| {
                                            lbr_prelude::json::lamval::bind_parse(
                                                <lbf_prelude::prelude::List<Ref<User>>>::from_json(
                                                    x5,
                                                ),
                                            )(
                                                std::boxed::Box::new(move |x6: &_| {
                                                    std::result::Result::Ok(User {
                                                        friends: std::boxed::Box::new(
                                                            <_ as std::clone::Clone>::clone(&x6),
                                                        ),
                                                        name: <_ as std::clone::Clone>::clone(&x2),
                                                        status: <_ as std::clone::Clone>::clone(
                                                            &x4,
                                                        ),
                                                    })
                                                }),
                                            )
                                        },
                                    ))
                                }),
                            )
                        }))
                    }))
                }),
            )
        }))(value)
    }
}

impl plutus_ledger_api::plutus_data::IsPlutusData for User {
    fn to_plutus_data<'a>(self: &'a Self) -> plutus_ledger_api::plutus_data::PlutusData {
        std::boxed::Box::new(move |x0: &'a Self| {
            plutus_ledger_api::plutus_data::PlutusData::list(std::vec![
                <lbf_plutus_v1::plutus::v1::Bytes>::to_plutus_data(&x0.name),
                <Status>::to_plutus_data(&x0.status),
                <lbf_prelude::prelude::List<Ref<User>>>::to_plutus_data(&x0.friends)
            ])
        })(self)
    }
    fn from_plutus_data<'a>(
        plutus_data: &'a plutus_ledger_api::plutus_data::PlutusData,
    ) -> std::result::Result<Self, plutus_ledger_api::plutus_data::PlutusDataError> {
        std::boxed::Box::new(move |x0: &'a plutus_ledger_api::plutus_data::PlutusData| {
            plutus_ledger_api::lamval::case_plutus_data(std::boxed::Box::new(move |x1: &_| {
                std::boxed::Box::new(move |x2: &_| plutus_ledger_api::lamval::fail_parse())
            }))(std::boxed::Box::new(
                move |x3: &_| match std::vec::Vec::as_slice(x3) {
                    [x4, x5, x6] => plutus_ledger_api::lamval::bind_parse(
                        <lbf_plutus_v1::plutus::v1::Bytes>::from_plutus_data(x4),
                    )(std::boxed::Box::new(move |x7: &_| {
                        plutus_ledger_api::lamval::bind_parse(<Status>::from_plutus_data(x5))(
                            std::boxed::Box::new(move |x8: &_| {
                                plutus_ledger_api::lamval::bind_parse(<lbf_prelude::prelude::List<
                                    Ref<User>,
                                >>::from_plutus_data(
                                    x6
                                ))(std::boxed::Box::new(
                                    move |x9: &_| {
                                        std::result::Result::Ok(User {
                                            friends: std::boxed::Box::new(
                                                <_ as std::clone::Clone>::clone(&x9),
                                            ),
                                            name: <_ as std::clone::Clone>::clone(&x7),
                                            status: <_ as std::clone::Clone>::clone(&x8),
                                        })
                                    },
                                ))
                            }),
                        )
                    })),
                    x10 => plutus_ledger_api::lamval::fail_parse(),
                },
            ))(std::boxed::Box::new(move |x11: &_| {
                plutus_ledger_api::lamval::fail_parse()
            }))(std::boxed::Box::new(move |x12: &_| {
                plutus_ledger_api::lamval::fail_parse()
            }))(x0)
        })(plutus_data)
    }
}

impl std::cmp::PartialEq for Status {
    fn eq<'a>(self: &'a Self, other: &'a Self) -> bool {
        std::boxed::Box::new(move |x0: &'a Self| {
            std::boxed::Box::new(move |x1: &'a Self| match x0 {
                Status::Active(x2) => match x1 {
                    Status::Active(x3) => lbr_prelude::lamval::eq(x2)(x3),
                    Status::Inactive(x4) => false,
                },
                Status::Inactive(x5) => match x1 {
                    Status::Active(x6) => false,
                    Status::Inactive(x7) => lbr_prelude::lamval::eq(x5)(x7),
                },
            })
        })(self)(other)
    }
}

impl std::cmp::Eq for Status {}

impl lbr_prelude::json::Json for Status {
    fn to_json<'a>(self: &'a Self) -> serde_json::Value {
        std::boxed::Box::new(move |x0: &'a Self| match x0 {
            Status::Active(x1) => lbr_prelude::json::lamval::json_constructor(
                <_ as std::convert::From<&str>>::from("Active"),
            )(std::vec![
                <lbf_plutus_v1::plutus::v1::POSIXTime>::to_json(x1)
            ]),
            Status::Inactive(x2) => lbr_prelude::json::lamval::json_constructor(
                <_ as std::convert::From<&str>>::from("Inactive"),
            )(std::vec![
                <lbf_plutus_v1::plutus::v1::POSIXTime>::to_json(x2)
            ]),
        })(self)
    }
    fn from_json<'a>(
        value: &'a serde_json::Value,
    ) -> std::result::Result<Self, lbr_prelude::error::Error> {
        lbr_prelude::json::lamval::case_json_constructor(<_ as std::convert::From<&str>>::from(
            "TODO(bladyjoker): Print qualified type name",
        ))(std::vec![
            (
                <_ as std::convert::From<&str>>::from("Active"),
                std::boxed::Box::new(move |x0: &_| {
                    match std::vec::Vec::as_slice(x0) {
                        [x1] => lbr_prelude::json::lamval::bind_parse(
                            <lbf_plutus_v1::plutus::v1::POSIXTime>::from_json(x1),
                        )(std::boxed::Box::new(move |x2: &_| {
                            std::result::Result::Ok(Status::Active(
                                <_ as std::clone::Clone>::clone(&x2),
                            ))
                        })),
                        x3 => lbr_prelude::json::lamval::fail_parse(<_ as std::convert::From<
                            &str,
                        >>::from(
                            "Expected a JSON Array of 1 elements",
                        )),
                    }
                })
            ),
            (
                <_ as std::convert::From<&str>>::from("Inactive"),
                std::boxed::Box::new(move |x4: &_| {
                    match std::vec::Vec::as_slice(x4) {
                        [x5] => lbr_prelude::json::lamval::bind_parse(
                            <lbf_plutus_v1::plutus::v1::POSIXTime>::from_json(x5),
                        )(std::boxed::Box::new(move |x6: &_| {
                            std::result::Result::Ok(Status::Inactive(
                                <_ as std::clone::Clone>::clone(&x6),
                            ))
                        })),
                        x7 => lbr_prelude::json::lamval::fail_parse(<_ as std::convert::From<
                            &str,
                        >>::from(
                            "Expected a JSON Array of 1 elements",
                        )),
                    }
                })
            )
        ])(value)
    }
}

impl plutus_ledger_api::plutus_data::IsPlutusData for Status {
    fn to_plutus_data<'a>(self: &'a Self) -> plutus_ledger_api::plutus_data::PlutusData {
        std::boxed::Box::new(move |x0: &'a Self| match x0 {
            Status::Active(x1) => plutus_ledger_api::lamval::constr(0)(std::vec![
                <lbf_plutus_v1::plutus::v1::POSIXTime>::to_plutus_data(x1)
            ]),
            Status::Inactive(x2) => plutus_ledger_api::lamval::constr(1)(std::vec![
                <lbf_plutus_v1::plutus::v1::POSIXTime>::to_plutus_data(x2)
            ]),
        })(self)
    }
    fn from_plutus_data<'a>(
        plutus_data: &'a plutus_ledger_api::plutus_data::PlutusData,
    ) -> std::result::Result<Self, plutus_ledger_api::plutus_data::PlutusDataError> {
        std::boxed::Box::new(move |x0: &'a plutus_ledger_api::plutus_data::PlutusData| {
            plutus_ledger_api::lamval::case_plutus_data(std::boxed::Box::new(move |x1: &_| {
                std::boxed::Box::new(move |x2: &_| {
                    lbr_prelude::lamval::case_int(
                        x1,
                        std::vec![
                            (
                                <_ as std::convert::From<u32>>::from(0),
                                match std::vec::Vec::as_slice(x2) {
                                    [x3] => plutus_ledger_api::lamval::bind_parse(
                                        <lbf_plutus_v1::plutus::v1::POSIXTime>::from_plutus_data(
                                            x3
                                        )
                                    )(
                                        std::boxed::Box::new(move |x4: &_| {
                                            std::result::Result::Ok(Status::Active(
                                                <_ as std::clone::Clone>::clone(&x4),
                                            ))
                                        })
                                    ),
                                    x5 => plutus_ledger_api::lamval::fail_parse(),
                                }
                            ),
                            (
                                <_ as std::convert::From<u32>>::from(1),
                                match std::vec::Vec::as_slice(x2) {
                                    [x6] => plutus_ledger_api::lamval::bind_parse(
                                        <lbf_plutus_v1::plutus::v1::POSIXTime>::from_plutus_data(
                                            x6
                                        )
                                    )(
                                        std::boxed::Box::new(move |x7: &_| {
                                            std::result::Result::Ok(Status::Inactive(
                                                <_ as std::clone::Clone>::clone(&x7),
                                            ))
                                        })
                                    ),
                                    x8 => plutus_ledger_api::lamval::fail_parse(),
                                }
                            )
                        ],
                        std::boxed::Box::new(move |x9: &_| plutus_ledger_api::lamval::fail_parse()),
                    )
                })
            }))(std::boxed::Box::new(move |x10: &_| {
                plutus_ledger_api::lamval::fail_parse()
            }))(std::boxed::Box::new(move |x11: &_| {
                lbr_prelude::lamval::case_int(
                    x11,
                    std::vec![],
                    std::boxed::Box::new(move |x12: &_| plutus_ledger_api::lamval::fail_parse()),
                )
            }))(std::boxed::Box::new(move |x13: &_| {
                plutus_ledger_api::lamval::fail_parse()
            }))(x0)
        })(plutus_data)
    }
}