Skip to content

Conversation

szg251
Copy link
Collaborator

@szg251 szg251 commented Dec 6, 2023

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)
    }
}

@szg251 szg251 marked this pull request as ready for review December 11, 2023 08:53
@szg251 szg251 requested a review from bladyjoker December 11, 2023 08:54
@szg251 szg251 requested a review from jaredponn December 13, 2023 07:34
Copy link
Contributor

@bladyjoker bladyjoker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is amaaazing! First round done.

I'm looking forward to the testsuites as I wonder if using Rust primitives 'char' for example, might break stuff because of some kind of special treatment.

@szg251 szg251 requested a review from bladyjoker December 15, 2023 15:03
@szg251 szg251 mentioned this pull request Dec 15, 2023
Copy link
Contributor

@bladyjoker bladyjoker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glorious! Left a few comments, but regardless we can proceed.

@bladyjoker bladyjoker added codegen devops All things devops (Nix, language servers, editors, code quality etc) rust labels Dec 19, 2023
@szg251 szg251 enabled auto-merge December 20, 2023 08:52
@szg251 szg251 added this pull request to the merge queue Dec 20, 2023
Merged via the queue into main with commit 59d3fb6 Dec 20, 2023
@szg251 szg251 deleted the szg251/rust-codegen branch December 20, 2023 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
codegen devops All things devops (Nix, language servers, editors, code quality etc) rust
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants