Skip to content

Commit

Permalink
[aptos-stdlib] Any type (aptos-labs#3291)
Browse files Browse the repository at this point in the history
This adds the `Any` type which allows polymorphic representation of values.
  • Loading branch information
wrwg authored Aug 22, 2022
1 parent 183d105 commit 205d2ef
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 4 deletions.
8 changes: 5 additions & 3 deletions aptos-move/framework/aptos-framework/sources/util.move
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ module aptos_framework::util {
friend aptos_framework::gas_schedule;

/// Native function to deserialize a type T.
/// TODO: may want to move it in extra module if needed also in other places inside of the Fx.
/// However, should not make this function public outside of the Fx.
public(friend) native fun from_bytes<T: copy + drop>(bytes: vector<u8>): T;
///
/// Note that this function does not put any constraint on `T`. If code uses this function to
/// deserialized a linear value, its their responsibility that the data they deserialize is
/// owned.
public(friend) native fun from_bytes<T>(bytes: vector<u8>): T;
}
61 changes: 61 additions & 0 deletions aptos-move/framework/aptos-stdlib/sources/any.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
module aptos_std::any {
use aptos_std::type_info;
use std::bcs;
use std::error;
use std::string::String;

/// The type provided for `unpack` is not the same as was given for `pack`.
const ETYPE_MISMATCH: u64 = 0;

/// A type which can represent a value of any type. This allows for representation of 'unknown' future
/// values. For example, to define a resource such that it can be later be extended without breaking
/// changes one can do
///
/// ```move
/// struct Resource {
/// field: Type,
/// ...
/// extension: Option<Any>
/// }
/// ```
struct Any has drop, store {
type_name: String,
data: vector<u8>
}

/// Pack a value into the `Any` representation. Because Any can be stored and dropped, this is
/// also required from `T`.
public fun pack<T: drop + store>(x: T): Any {
Any {
type_name: type_info::type_name<T>(),
data: bcs::to_bytes(&x)
}
}

/// Unpack a value from the `Any` representation. This aborts if the value has not the expected type `T`.
public fun unpack<T>(x: Any): T {
assert!(type_info::type_name<T>() == x.type_name, error::invalid_argument(ETYPE_MISMATCH));
from_bytes<T>(x.data)
}

/// Returns the type name of this Any
public fun type_name(x: &Any): &String {
&x.type_name
}

/// Native function to deserialize a type T.
///
/// Note that this function does not put any constraint on `T`. If code uses this function to
/// deserialized a linear value, its their responsibility that the data they deserialize is
/// owned.
public(friend) native fun from_bytes<T>(bytes: vector<u8>): T;

#[test_only]
struct S has store, drop { x: u64 }

#[test]
fun test_any() {
assert!(unpack<u64>(pack(22)) == 22, 1);
assert!(unpack<S>(pack(S{x:22})) == S{x: 22}, 2);
}
}
16 changes: 16 additions & 0 deletions aptos-move/framework/src/natives/any.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::natives::{util, GasParameters};
use move_deps::move_vm_runtime::native_functions::NativeFunction;

// The Any module hijacks just one function, from_bytes, from the util module. This
// is a friend function which cannot be used across packages, so we have it both
// in aptos_std and aptos_framework.
pub fn make_all(gas_params: GasParameters) -> impl Iterator<Item = (String, NativeFunction)> {
let natives = [(
"from_bytes",
util::make_native_from_bytes(gas_params.util.from_bytes),
)];
crate::natives::helpers::make_module_natives(natives)
}
4 changes: 3 additions & 1 deletion aptos-move/framework/src/natives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

pub mod account;
pub mod aggregator_natives;
pub mod any;
pub mod code;
pub mod cryptography;
pub mod event;
Expand Down Expand Up @@ -194,7 +195,8 @@ pub fn all_natives(
cryptography::ristretto255::make_all(gas_params.ristretto255)
);
add_natives_from_module!("type_info", type_info::make_all(gas_params.type_info));
add_natives_from_module!("util", util::make_all(gas_params.util));
add_natives_from_module!("util", util::make_all(gas_params.util.clone()));
add_natives_from_module!("any", util::make_all(gas_params.util));
add_natives_from_module!(
"transaction_context",
transaction_context::make_all(gas_params.transaction_context)
Expand Down

0 comments on commit 205d2ef

Please sign in to comment.