diff --git a/ci/token.sh b/ci/token.sh index 6eb07567b5a..1fda62aa3a3 100755 --- a/ci/token.sh +++ b/ci/token.sh @@ -9,6 +9,7 @@ set -e ./do.sh build token ./do.sh doc token ./do.sh test token + cc token/inc/token.h -o token/target/token.gch ) ( diff --git a/token/Cargo.lock b/token/Cargo.lock index 97aeff26b7d..1ced8bd5775 100644 --- a/token/Cargo.lock +++ b/token/Cargo.lock @@ -1,5 +1,25 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.0.0" @@ -16,6 +36,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + [[package]] name = "block-buffer" version = "0.7.3" @@ -65,12 +91,45 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "cbindgen" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104ca409bbff8293739438c71820a2606111b5f8f81835536dc673dfd807369e" +dependencies = [ + "clap", + "heck", + "log", + "proc-macro2 1.0.18", + "quote 1.0.7", + "serde", + "serde_json", + "syn 1.0.31", + "tempfile", + "toml", +] + [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "clap" +version = "2.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "crypto-mac" version = "0.7.0" @@ -128,6 +187,24 @@ dependencies = [ "wasi", ] +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.2" @@ -153,6 +230,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" + [[package]] name = "libc" version = "0.2.71" @@ -298,6 +381,27 @@ dependencies = [ "rand_core", ] +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "remove_dir_all" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc5b3ce5d5ea144bb04ebd093a9e14e9765bcfec866aecda9b6dec43b3d1e24" +dependencies = [ + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + [[package]] name = "serde" version = "1.0.112" @@ -327,6 +431,17 @@ dependencies = [ "syn 1.0.31", ] +[[package]] +name = "serde_json" +version = "1.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.8.2" @@ -369,9 +484,9 @@ version = "1.2.3" [[package]] name = "solana-sdk-macro" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76f29c489add350172c11ec1232b060276feffdf5344ef66cbd4dd844ada7a" +checksum = "da5f311e7735323eb0ad348c68170c2503a2c56cfa1a261646d8182b373fa670" dependencies = [ "bs58", "proc-macro2 1.0.18", @@ -383,14 +498,22 @@ dependencies = [ name = "spl-token" version = "0.1.0" dependencies = [ + "cbindgen", "num-derive 0.2.5", "num-traits", "rand", + "remove_dir_all", "solana-sdk", "solana-sdk-bpf-test", "thiserror", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "subtle" version = "1.0.0" @@ -419,6 +542,29 @@ dependencies = [ "unicode-xid 0.2.0", ] +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.20" @@ -439,12 +585,33 @@ dependencies = [ "syn 1.0.31", ] +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +dependencies = [ + "serde", +] + [[package]] name = "typenum" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + [[package]] name = "unicode-xid" version = "0.1.0" @@ -457,8 +624,36 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/token/Cargo.toml b/token/Cargo.toml index 549f464f39b..c24110db4f3 100644 --- a/token/Cargo.toml +++ b/token/Cargo.toml @@ -13,6 +13,7 @@ edition = "2018" [dependencies] num-derive = "0.2" num-traits = "0.2" +remove_dir_all = "=0.5.0" solana-sdk = { version = "=1.2.0", default-features = false, features=["program"] } solana-sdk-bpf-test = { path = "../bin/bpf-sdk/rust/test", default-features = false } thiserror = "1.0" @@ -20,6 +21,9 @@ thiserror = "1.0" [dev-dependencies] rand = { version = "0.7.0"} +[build-dependencies] +cbindgen = "0.14" + [lib] name = "spl_token" crate-type = ["cdylib", "lib"] diff --git a/token/build.rs b/token/build.rs new file mode 100644 index 00000000000..c0aa47eb071 --- /dev/null +++ b/token/build.rs @@ -0,0 +1,10 @@ +extern crate cbindgen; + +use std::env; + +fn main() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + cbindgen::generate(&crate_dir) + .unwrap() + .write_to_file("inc/token.h"); +} diff --git a/token/cbindgen.toml b/token/cbindgen.toml new file mode 100644 index 00000000000..04b9812dea4 --- /dev/null +++ b/token/cbindgen.toml @@ -0,0 +1,15 @@ +language = "C" +header = "/* Autogenerated SPL Token program C Bindings */" +pragma_once = true +cpp_compat = true +line_length = 80 +tab_width = 4 +style = "both" + +[export] +prefix = "Token" +include = ["Instruction", "State"] + +[parse] +parse_deps = true +include = ["solana-sdk"] diff --git a/token/inc/token.h b/token/inc/token.h new file mode 100644 index 00000000000..de9d464b29a --- /dev/null +++ b/token/inc/token.h @@ -0,0 +1,171 @@ +/* Autogenerated SPL Token program C Bindings */ + +#pragma once + +#include +#include +#include +#include + +typedef struct TokenInstruction TokenInstruction; + +/** + * Specifies the financial specifics of a token. + */ +typedef struct TokenTokenInfo { + /** + * Total supply of tokens. + */ + uint64_t supply; + /** + * Number of base 10 digits to the right of the decimal place in the total supply. + */ + uint64_t decimals; +} TokenTokenInfo; + +typedef uint8_t TokenPubkey[32]; + +/** + * A C representation of Rust's `std::option::Option` + */ +typedef enum TokenCOption_Pubkey_Tag { + /** + * No value + */ + None_Pubkey, + /** + * Some value `T` + */ + Some_Pubkey, +} TokenCOption_Pubkey_Tag; + +typedef struct TokenSome_Body_Pubkey { + TokenPubkey _0; +} TokenSome_Body_Pubkey; + +typedef struct TokenCOption_Pubkey { + TokenCOption_Pubkey_Tag tag; + union { + TokenSome_Body_Pubkey some; + }; +} TokenCOption_Pubkey; + +/** + * Represents a token type identified and identified by its public key. Accounts + * are associated with a specific token type and only accounts with + * matching types my inter-opt. + */ +typedef struct TokenToken { + /** + * The total supply of tokens. + */ + TokenTokenInfo info; + /** + * Optional token owner, used to mint new tokens. The owner may only + * be provided during token creation. If no owner is present then the token + * has a fixed supply and no further tokens may be minted. + */ + TokenCOption_Pubkey owner; +} TokenToken; + +/** + * Delegation details. + */ +typedef struct TokenAccountDelegate { + /** + * The source account for the tokens. + */ + TokenPubkey source; + /** + * The original maximum amount that this delegate account was authorized to spend. + */ + uint64_t original_amount; +} TokenAccountDelegate; + +/** + * A C representation of Rust's `std::option::Option` + */ +typedef enum TokenCOption_AccountDelegate_Tag { + /** + * No value + */ + None_AccountDelegate, + /** + * Some value `T` + */ + Some_AccountDelegate, +} TokenCOption_AccountDelegate_Tag; + +typedef struct TokenSome_Body_AccountDelegate { + TokenAccountDelegate _0; +} TokenSome_Body_AccountDelegate; + +typedef struct TokenCOption_AccountDelegate { + TokenCOption_AccountDelegate_Tag tag; + union { + TokenSome_Body_AccountDelegate some; + }; +} TokenCOption_AccountDelegate; + +/** + * Account that holds or may delegate tokens. + */ +typedef struct TokenAccount { + /** + * The type of token this account holds. + */ + TokenPubkey token; + /** + * Owner of this account. + */ + TokenPubkey owner; + /** + * Amount of tokens this account holds. + */ + uint64_t amount; + /** + * If `delegate` is None, `amount` belongs to this account. + * If `delegate` is Option<_>, `amount` represents the remaining allowance + * of tokens this delegate is authorized to transfer from the `source` account. + */ + TokenCOption_AccountDelegate delegate; +} TokenAccount; + +/** + * Token program states. + */ +typedef enum TokenState_Tag { + /** + * Unallocated state, may be initialized into another state. + */ + Unallocated, + /** + * A token type. + */ + Token, + /** + * An account that holds an amount of tokens or was delegated the authority to transfer + * tokens on behalf of another account. + */ + Account, + /** + * Invalid state, cannot be modified by the token program. + */ + Invalid, +} TokenState_Tag; + +typedef struct TokenToken_Body { + TokenToken _0; +} TokenToken_Body; + +typedef struct TokenAccount_Body { + TokenAccount _0; +} TokenAccount_Body; + +typedef struct TokenState { + TokenState_Tag tag; + union { + TokenToken_Body token; + TokenAccount_Body account; + }; +} TokenState; diff --git a/token/src/lib.rs b/token/src/lib.rs index 827e9ff3f04..38a9efeb2c4 100644 --- a/token/src/lib.rs +++ b/token/src/lib.rs @@ -4,5 +4,6 @@ pub mod error; pub mod instruction; +pub mod option; pub mod processor; pub mod state; diff --git a/token/src/option.rs b/token/src/option.rs new file mode 100644 index 00000000000..df70c051ffe --- /dev/null +++ b/token/src/option.rs @@ -0,0 +1,965 @@ +//! A C representation of Rust's `std::option::Option` used accross the FFI +//! boundary for Solana program interfaces +//! +//! This implementation mostly matches `std::option` except iterators since the iteration +//! trait requires returning `std::option::Option` + +use std::pin::Pin; +use std::{ + convert, hint, mem, + ops::{Deref, DerefMut}, +}; + +/// A C representation of Rust's `std::option::Option` +#[repr(C)] +#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +pub enum COption { + /// No value + None, + /// Some value `T` + Some(T), +} + +///////////////////////////////////////////////////////////////////////////// +// Type implementation +///////////////////////////////////////////////////////////////////////////// + +impl COption { + ///////////////////////////////////////////////////////////////////////// + // Querying the contained values + ///////////////////////////////////////////////////////////////////////// + + /// Returns `true` if the option is a [`COption::Some`] value. + /// + /// # Examples + /// + /// ```ignore + /// let x: COption = COption::Some(2); + /// assert_eq!(x.is_some(), true); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.is_some(), false); + /// ``` + /// + /// [`COption::Some`]: #variant.COption::Some + #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] + #[inline] + pub fn is_some(&self) -> bool { + match *self { + COption::Some(_) => true, + COption::None => false, + } + } + + /// Returns `true` if the option is a [`COption::None`] value. + /// + /// # Examples + /// + /// ```ignore + /// let x: COption = COption::Some(2); + /// assert_eq!(x.is_none(), false); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.is_none(), true); + /// ``` + /// + /// [`COption::None`]: #variant.COption::None + #[must_use = "if you intended to assert that this doesn't have a value, consider \ + `.and_then(|| panic!(\"`COption` had a value when expected `COption::None`\"))` instead"] + #[inline] + pub fn is_none(&self) -> bool { + !self.is_some() + } + + /// Returns `true` if the option is a [`COption::Some`] value containing the given value. + /// + /// # Examples + /// + /// ```ignore + /// #![feature(option_result_contains)] + /// + /// let x: COption = COption::Some(2); + /// assert_eq!(x.contains(&2), true); + /// + /// let x: COption = COption::Some(3); + /// assert_eq!(x.contains(&2), false); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.contains(&2), false); + /// ``` + #[must_use] + #[inline] + pub fn contains(&self, x: &U) -> bool + where + U: PartialEq, + { + match self { + COption::Some(y) => x == y, + COption::None => false, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Adapter for working with references + ///////////////////////////////////////////////////////////////////////// + + /// Converts from `&COption` to `COption<&T>`. + /// + /// # Examples + /// + /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, preserving the original. + /// The [`map`] method takes the `self` argument by value, consuming the original, + /// so this technique uses `as_ref` to first take an `COption` to a reference + /// to the value inside the original. + /// + /// [`map`]: enum.COption.html#method.map + /// [`String`]: ../../std/string/struct.String.html + /// [`usize`]: ../../std/primitive.usize.html + /// + /// ```ignore + /// let text: COption = COption::Some("Hello, world!".to_string()); + /// // First, cast `COption` to `COption<&String>` with `as_ref`, + /// // then consume *that* with `map`, leaving `text` on the stack. + /// let text_length: COption = text.as_ref().map(|s| s.len()); + /// println!("still can print text: {:?}", text); + /// ``` + #[inline] + pub fn as_ref(&self) -> COption<&T> { + match *self { + COption::Some(ref x) => COption::Some(x), + COption::None => COption::None, + } + } + + /// Converts from `&mut COption` to `COption<&mut T>`. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::Some(2); + /// match x.as_mut() { + /// COption::Some(v) => *v = 42, + /// COption::None => {}, + /// } + /// assert_eq!(x, COption::Some(42)); + /// ``` + #[inline] + pub fn as_mut(&mut self) -> COption<&mut T> { + match *self { + COption::Some(ref mut x) => COption::Some(x), + COption::None => COption::None, + } + } + + /// Converts from [`Pin`]`<&COption>` to `COption<`[`Pin`]`<&T>>`. + /// + /// [`Pin`]: ../pin/struct.Pin.html + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn as_pin_ref(self: Pin<&Self>) -> COption> { + unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } + } + + /// Converts from [`Pin`]`<&mut COption>` to `COption<`[`Pin`]`<&mut T>>`. + /// + /// [`Pin`]: ../pin/struct.Pin.html + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn as_pin_mut(self: Pin<&mut Self>) -> COption> { + unsafe { + Pin::get_unchecked_mut(self) + .as_mut() + .map(|x| Pin::new_unchecked(x)) + } + } + + ///////////////////////////////////////////////////////////////////////// + // Getting to contained values + ///////////////////////////////////////////////////////////////////////// + + /// Unwraps an option, yielding the content of a [`COption::Some`]. + /// + /// # Panics + /// + /// Panics if the value is a [`COption::None`] with a custom panic message provided by + /// `msg`. + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("value"); + /// assert_eq!(x.expect("the world is ending"), "value"); + /// ``` + /// + /// ```ignore{.should_panic} + /// let x: COption<&str> = COption::None; + /// x.expect("the world is ending"); // panics with `the world is ending` + /// ``` + #[inline] + pub fn expect(self, msg: &str) -> T { + match self { + COption::Some(val) => val, + COption::None => expect_failed(msg), + } + } + + /// Moves the value `v` out of the `COption` if it is [`COption::Some(v)`]. + /// + /// In general, because this function may panic, its use is discouraged. + /// Instead, prefer to use pattern matching and handle the [`COption::None`] + /// case explicitly. + /// + /// # Panics + /// + /// Panics if the self value equals [`COption::None`]. + /// + /// [`COption::Some(v)`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("air"); + /// assert_eq!(x.unwrap(), "air"); + /// ``` + /// + /// ```ignore{.should_panic} + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.unwrap(), "air"); // fails + /// ``` + #[inline] + pub fn unwrap(self) -> T { + match self { + COption::Some(val) => val, + COption::None => panic!("called `COption::unwrap()` on a `COption::None` value"), + } + } + + /// Returns the contained value or a default. + /// + /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use [`unwrap_or_else`], + /// which is lazily evaluated. + /// + /// [`unwrap_or_else`]: #method.unwrap_or_else + /// + /// # Examples + /// + /// ```ignore + /// assert_eq!(COption::Some("car").unwrap_or("bike"), "car"); + /// assert_eq!(COption::None.unwrap_or("bike"), "bike"); + /// ``` + #[inline] + pub fn unwrap_or(self, def: T) -> T { + match self { + COption::Some(x) => x, + COption::None => def, + } + } + + /// Returns the contained value or computes it from a closure. + /// + /// # Examples + /// + /// ```ignore + /// let k = 10; + /// assert_eq!(COption::Some(4).unwrap_or_else(|| 2 * k), 4); + /// assert_eq!(COption::None.unwrap_or_else(|| 2 * k), 20); + /// ``` + #[inline] + pub fn unwrap_or_else T>(self, f: F) -> T { + match self { + COption::Some(x) => x, + COption::None => f(), + } + } + + ///////////////////////////////////////////////////////////////////////// + // Transforming contained values + ///////////////////////////////////////////////////////////////////////// + + /// Maps an `COption` to `COption` by applying a function to a contained value. + /// + /// # Examples + /// + /// Converts an `COption<`[`String`]`>` into an `COption<`[`usize`]`>`, consuming the original: + /// + /// [`String`]: ../../std/string/struct.String.html + /// [`usize`]: ../../std/primitive.usize.html + /// + /// ```ignore + /// let maybe_some_string = COption::Some(String::from("Hello, World!")); + /// // `COption::map` takes self *by value*, consuming `maybe_some_string` + /// let maybe_some_len = maybe_some_string.map(|s| s.len()); + /// + /// assert_eq!(maybe_some_len, COption::Some(13)); + /// ``` + #[inline] + pub fn map U>(self, f: F) -> COption { + match self { + COption::Some(x) => COption::Some(f(x)), + COption::None => COption::None, + } + } + + /// Applies a function to the contained value (if any), + /// or returns the provided default (if not). + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.map_or(42, |v| v.len()), 3); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.map_or(42, |v| v.len()), 42); + /// ``` + #[inline] + pub fn map_or U>(self, default: U, f: F) -> U { + match self { + COption::Some(t) => f(t), + COption::None => default, + } + } + + /// Applies a function to the contained value (if any), + /// or computes a default (if not). + /// + /// # Examples + /// + /// ```ignore + /// let k = 21; + /// + /// let x = COption::Some("foo"); + /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42); + /// ``` + #[inline] + pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { + match self { + COption::Some(t) => f(t), + COption::None => default(), + } + } + + /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to + /// [`Ok(v)`] and [`COption::None`] to [`Err(err)`]. + /// + /// Arguments passed to `ok_or` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`ok_or_else`], which is + /// lazily evaluated. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Err(err)`]: ../../std/result/enum.Result.html#variant.Err + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(v)`]: #variant.COption::Some + /// [`ok_or_else`]: #method.ok_or_else + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.ok_or(0), Ok("foo")); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.ok_or(0), Err(0)); + /// ``` + #[inline] + pub fn ok_or(self, err: E) -> Result { + match self { + COption::Some(v) => Ok(v), + COption::None => Err(err), + } + } + + /// Transforms the `COption` into a [`Result`], mapping [`COption::Some(v)`] to + /// [`Ok(v)`] and [`COption::None`] to [`Err(err())`]. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Err(err())`]: ../../std/result/enum.Result.html#variant.Err + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(v)`]: #variant.COption::Some + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some("foo"); + /// assert_eq!(x.ok_or_else(|| 0), Ok("foo")); + /// + /// let x: COption<&str> = COption::None; + /// assert_eq!(x.ok_or_else(|| 0), Err(0)); + /// ``` + #[inline] + pub fn ok_or_else E>(self, err: F) -> Result { + match self { + COption::Some(v) => Ok(v), + COption::None => Err(err()), + } + } + + ///////////////////////////////////////////////////////////////////////// + // Boolean operations on the values, eager and lazy + ///////////////////////////////////////////////////////////////////////// + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise returns `optb`. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y: COption<&str> = COption::None; + /// assert_eq!(x.and(y), COption::None); + /// + /// let x: COption = COption::None; + /// let y = COption::Some("foo"); + /// assert_eq!(x.and(y), COption::None); + /// + /// let x = COption::Some(2); + /// let y = COption::Some("foo"); + /// assert_eq!(x.and(y), COption::Some("foo")); + /// + /// let x: COption = COption::None; + /// let y: COption<&str> = COption::None; + /// assert_eq!(x.and(y), COption::None); + /// ``` + #[inline] + pub fn and(self, optb: COption) -> COption { + match self { + COption::Some(_) => optb, + COption::None => COption::None, + } + } + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `f` with the + /// wrapped value and returns the result. + /// + /// COption::Some languages call this operation flatmap. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// fn sq(x: u32) -> COption { COption::Some(x * x) } + /// fn nope(_: u32) -> COption { COption::None } + /// + /// assert_eq!(COption::Some(2).and_then(sq).and_then(sq), COption::Some(16)); + /// assert_eq!(COption::Some(2).and_then(sq).and_then(nope), COption::None); + /// assert_eq!(COption::Some(2).and_then(nope).and_then(sq), COption::None); + /// assert_eq!(COption::None.and_then(sq).and_then(sq), COption::None); + /// ``` + #[inline] + pub fn and_then COption>(self, f: F) -> COption { + match self { + COption::Some(x) => f(x), + COption::None => COption::None, + } + } + + /// Returns [`COption::None`] if the option is [`COption::None`], otherwise calls `predicate` + /// with the wrapped value and returns: + /// + /// - [`COption::Some(t)`] if `predicate` returns `true` (where `t` is the wrapped + /// value), and + /// - [`COption::None`] if `predicate` returns `false`. + /// + /// This function works similar to [`Iterator::filter()`]. You can imagine + /// the `COption` being an iterator over one or zero elements. `filter()` + /// lets you decide which elements to keep. + /// + /// # Examples + /// + /// ```ignore + /// fn is_even(n: &i32) -> bool { + /// n % 2 == 0 + /// } + /// + /// assert_eq!(COption::None.filter(is_even), COption::None); + /// assert_eq!(COption::Some(3).filter(is_even), COption::None); + /// assert_eq!(COption::Some(4).filter(is_even), COption::Some(4)); + /// ``` + /// + /// [`COption::None`]: #variant.COption::None + /// [`COption::Some(t)`]: #variant.COption::Some + /// [`Iterator::filter()`]: ../../std/iter/trait.Iterator.html#method.filter + #[inline] + pub fn filter bool>(self, predicate: P) -> Self { + if let COption::Some(x) = self { + if predicate(&x) { + return COption::Some(x); + } + } + COption::None + } + + /// Returns the option if it contains a value, otherwise returns `optb`. + /// + /// Arguments passed to `or` are eagerly evaluated; if you are passing the + /// result of a function call, it is recommended to use [`or_else`], which is + /// lazily evaluated. + /// + /// [`or_else`]: #method.or_else + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y = COption::None; + /// assert_eq!(x.or(y), COption::Some(2)); + /// + /// let x = COption::None; + /// let y = COption::Some(100); + /// assert_eq!(x.or(y), COption::Some(100)); + /// + /// let x = COption::Some(2); + /// let y = COption::Some(100); + /// assert_eq!(x.or(y), COption::Some(2)); + /// + /// let x: COption = COption::None; + /// let y = COption::None; + /// assert_eq!(x.or(y), COption::None); + /// ```ignore + #[inline] + pub fn or(self, optb: COption) -> COption { + match self { + COption::Some(_) => self, + COption::None => optb, + } + } + + /// Returns the option if it contains a value, otherwise calls `f` and + /// returns the result. + /// + /// # Examples + /// + /// ```ignore + /// fn nobody() -> COption<&'static str> { COption::None } + /// fn vikings() -> COption<&'static str> { COption::Some("vikings") } + /// + /// assert_eq!(COption::Some("barbarians").or_else(vikings), COption::Some("barbarians")); + /// assert_eq!(COption::None.or_else(vikings), COption::Some("vikings")); + /// assert_eq!(COption::None.or_else(nobody), COption::None); + /// ``` + #[inline] + pub fn or_else COption>(self, f: F) -> COption { + match self { + COption::Some(_) => self, + COption::None => f(), + } + } + + /// Returns [`COption::Some`] if exactly one of `self`, `optb` is [`COption::Some`], otherwise returns [`COption::None`]. + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let x = COption::Some(2); + /// let y: COption = COption::None; + /// assert_eq!(x.xor(y), COption::Some(2)); + /// + /// let x: COption = COption::None; + /// let y = COption::Some(2); + /// assert_eq!(x.xor(y), COption::Some(2)); + /// + /// let x = COption::Some(2); + /// let y = COption::Some(2); + /// assert_eq!(x.xor(y), COption::None); + /// + /// let x: COption = COption::None; + /// let y: COption = COption::None; + /// assert_eq!(x.xor(y), COption::None); + /// ``` + #[inline] + pub fn xor(self, optb: COption) -> COption { + match (self, optb) { + (COption::Some(a), COption::None) => COption::Some(a), + (COption::None, COption::Some(b)) => COption::Some(b), + _ => COption::None, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Entry-like operations to insert if COption::None and return a reference + ///////////////////////////////////////////////////////////////////////// + + /// Inserts `v` into the option if it is [`COption::None`], then + /// returns a mutable reference to the contained value. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::None; + /// + /// { + /// let y: &mut u32 = x.get_or_insert(5); + /// assert_eq!(y, &5); + /// + /// *y = 7; + /// } + /// + /// assert_eq!(x, COption::Some(7)); + /// ``` + #[inline] + pub fn get_or_insert(&mut self, v: T) -> &mut T { + self.get_or_insert_with(|| v) + } + + /// Inserts a value computed from `f` into the option if it is [`COption::None`], then + /// returns a mutable reference to the contained value. + /// + /// [`COption::None`]: #variant.COption::None + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::None; + /// + /// { + /// let y: &mut u32 = x.get_or_insert_with(|| 5); + /// assert_eq!(y, &5); + /// + /// *y = 7; + /// } + /// + /// assert_eq!(x, COption::Some(7)); + /// ``` + #[inline] + pub fn get_or_insert_with T>(&mut self, f: F) -> &mut T { + if let COption::None = *self { + *self = COption::Some(f()) + } + + match *self { + COption::Some(ref mut v) => v, + COption::None => unsafe { hint::unreachable_unchecked() }, + } + } + + ///////////////////////////////////////////////////////////////////////// + // Misc + ///////////////////////////////////////////////////////////////////////// + + /// Replaces the actual value in the option by the value given in parameter, + /// returning the old value if present, + /// leaving a [`COption::Some`] in its place without deinitializing either one. + /// + /// [`COption::Some`]: #variant.COption::Some + /// + /// # Examples + /// + /// ```ignore + /// let mut x = COption::Some(2); + /// let old = x.replace(5); + /// assert_eq!(x, COption::Some(5)); + /// assert_eq!(old, COption::Some(2)); + /// + /// let mut x = COption::None; + /// let old = x.replace(3); + /// assert_eq!(x, COption::Some(3)); + /// assert_eq!(old, COption::None); + /// ``` + #[inline] + pub fn replace(&mut self, value: T) -> COption { + mem::replace(self, COption::Some(value)) + } +} + +impl COption<&T> { + /// Maps an `COption<&T>` to an `COption` by copying the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let x = 12; + /// let opt_x = COption::Some(&x); + /// assert_eq!(opt_x, COption::Some(&12)); + /// let copied = opt_x.copied(); + /// assert_eq!(copied, COption::Some(12)); + /// ``` + pub fn copied(self) -> COption { + self.map(|&t| t) + } +} + +impl COption<&mut T> { + /// Maps an `COption<&mut T>` to an `COption` by copying the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = 12; + /// let opt_x = COption::Some(&mut x); + /// assert_eq!(opt_x, COption::Some(&mut 12)); + /// let copied = opt_x.copied(); + /// assert_eq!(copied, COption::Some(12)); + /// ``` + pub fn copied(self) -> COption { + self.map(|&mut t| t) + } +} + +impl COption<&T> { + /// Maps an `COption<&T>` to an `COption` by cloning the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let x = 12; + /// let opt_x = COption::Some(&x); + /// assert_eq!(opt_x, COption::Some(&12)); + /// let cloned = opt_x.cloned(); + /// assert_eq!(cloned, COption::Some(12)); + /// ``` + pub fn cloned(self) -> COption { + self.map(|t| t.clone()) + } +} + +impl COption<&mut T> { + /// Maps an `COption<&mut T>` to an `COption` by cloning the contents of the + /// option. + /// + /// # Examples + /// + /// ```ignore + /// let mut x = 12; + /// let opt_x = COption::Some(&mut x); + /// assert_eq!(opt_x, COption::Some(&mut 12)); + /// let cloned = opt_x.cloned(); + /// assert_eq!(cloned, COption::Some(12)); + /// ``` + pub fn cloned(self) -> COption { + self.map(|t| t.clone()) + } +} + +impl COption { + /// Returns the contained value or a default + /// + /// Consumes the `self` argument then, if [`COption::Some`], returns the contained + /// value, otherwise if [`COption::None`], returns the [default value] for that + /// type. + /// + /// # Examples + /// + /// Converts a string to an integer, turning poorly-formed strings + /// into 0 (the default value for integers). [`parse`] converts + /// a string to any other type that implements [`FromStr`], returning + /// [`COption::None`] on error. + /// + /// ```ignore + /// let good_year_from_input = "1909"; + /// let bad_year_from_input = "190blarg"; + /// let good_year = good_year_from_input.parse().ok().unwrap_or_default(); + /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default(); + /// + /// assert_eq!(1909, good_year); + /// assert_eq!(0, bad_year); + /// ``` + /// + /// [`COption::Some`]: #variant.COption::Some + /// [`COption::None`]: #variant.COption::None + /// [default value]: ../default/trait.Default.html#tymethod.default + /// [`parse`]: ../../std/primitive.str.html#method.parse + /// [`FromStr`]: ../../std/str/trait.FromStr.html + #[inline] + pub fn unwrap_or_default(self) -> T { + match self { + COption::Some(x) => x, + COption::None => Default::default(), + } + } +} + +impl COption { + /// Converts from `COption` (or `&COption`) to `COption<&T::Target>`. + /// + /// Leaves the original COption in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via [`Deref`]. + /// + /// [`Deref`]: ../../std/ops/trait.Deref.html + /// + /// # Examples + /// + /// ```ignore + /// #![feature(inner_deref)] + /// + /// let x: COption = COption::Some("hey".to_owned()); + /// assert_eq!(x.as_deref(), COption::Some("hey")); + /// + /// let x: COption = COption::None; + /// assert_eq!(x.as_deref(), COption::None); + /// ``` + pub fn as_deref(&self) -> COption<&T::Target> { + self.as_ref().map(|t| t.deref()) + } +} + +impl COption { + /// Converts from `COption` (or `&mut COption`) to `COption<&mut T::Target>`. + /// + /// Leaves the original `COption` in-place, creating a new one containing a mutable reference to + /// the inner type's `Deref::Target` type. + /// + /// # Examples + /// + /// ```ignore + /// #![feature(inner_deref)] + /// + /// let mut x: COption = COption::Some("hey".to_owned()); + /// assert_eq!(x.as_deref_mut().map(|x| { + /// x.make_ascii_uppercase(); + /// x + /// }), COption::Some("HEY".to_owned().as_mut_str())); + /// ``` + pub fn as_deref_mut(&mut self) -> COption<&mut T::Target> { + self.as_mut().map(|t| t.deref_mut()) + } +} + +impl COption> { + /// Transposes an `COption` of a [`Result`] into a [`Result`] of an `COption`. + /// + /// [`COption::None`] will be mapped to [`Ok`]`(`[`COption::None`]`)`. + /// [`COption::Some`]`(`[`Ok`]`(_))` and [`COption::Some`]`(`[`Err`]`(_))` will be mapped to + /// [`Ok`]`(`[`COption::Some`]`(_))` and [`Err`]`(_)`. + /// + /// [`COption::None`]: #variant.COption::None + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`COption::Some`]: #variant.COption::Some + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ```ignore + /// #[derive(Debug, Eq, PartialEq)] + /// struct COption::SomeErr; + /// + /// let x: Result, COption::SomeErr> = Ok(COption::Some(5)); + /// let y: COption> = COption::Some(Ok(5)); + /// assert_eq!(x, y.transpose()); + /// ``` + #[inline] + pub fn transpose(self) -> Result, E> { + match self { + COption::Some(Ok(x)) => Ok(COption::Some(x)), + COption::Some(Err(e)) => Err(e), + COption::None => Ok(COption::None), + } + } +} + +// This is a separate function to reduce the code size of .expect() itself. +#[inline(never)] +#[cold] +fn expect_failed(msg: &str) -> ! { + panic!("{}", msg) +} + +// // This is a separate function to reduce the code size of .expect_none() itself. +// #[inline(never)] +// #[cold] +// fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! { +// panic!("{}: {:?}", msg, value) +// } + +///////////////////////////////////////////////////////////////////////////// +// Trait implementations +///////////////////////////////////////////////////////////////////////////// + +impl Clone for COption { + #[inline] + fn clone(&self) -> Self { + match self { + COption::Some(x) => COption::Some(x.clone()), + COption::None => COption::None, + } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + match (self, source) { + (COption::Some(to), COption::Some(from)) => to.clone_from(from), + (to, from) => *to = from.clone(), + } + } +} + +impl Default for COption { + /// Returns [`COption::None`][COption::COption::None]. + /// + /// # Examples + /// + /// ```ignore + /// let opt: COption = COption::default(); + /// assert!(opt.is_none()); + /// ``` + #[inline] + fn default() -> COption { + COption::None + } +} + +impl From for COption { + fn from(val: T) -> COption { + COption::Some(val) + } +} + +impl<'a, T> From<&'a COption> for COption<&'a T> { + fn from(o: &'a COption) -> COption<&'a T> { + o.as_ref() + } +} + +impl<'a, T> From<&'a mut COption> for COption<&'a mut T> { + fn from(o: &'a mut COption) -> COption<&'a mut T> { + o.as_mut() + } +} + +impl COption> { + /// Converts from `COption>` to `COption` + /// + /// # Examples + /// Basic usage: + /// ```ignore + /// #![feature(option_flattening)] + /// let x: COption> = COption::Some(COption::Some(6)); + /// assert_eq!(COption::Some(6), x.flatten()); + /// + /// let x: COption> = COption::Some(COption::None); + /// assert_eq!(COption::None, x.flatten()); + /// + /// let x: COption> = COption::None; + /// assert_eq!(COption::None, x.flatten()); + /// ``` + /// Flattening once only removes one level of nesting: + /// ```ignore + /// #![feature(option_flattening)] + /// let x: COption>> = COption::Some(COption::Some(COption::Some(6))); + /// assert_eq!(COption::Some(COption::Some(6)), x.flatten()); + /// assert_eq!(COption::Some(6), x.flatten().flatten()); + /// ``` + #[inline] + pub fn flatten(self) -> COption { + self.and_then(convert::identity) + } +} diff --git a/token/src/state.rs b/token/src/state.rs index 9ecf5fe5df8..7c8d2315e47 100644 --- a/token/src/state.rs +++ b/token/src/state.rs @@ -3,6 +3,7 @@ use crate::{ error::TokenError, instruction::{TokenInfo, TokenInstruction}, + option::COption, }; use solana_sdk::{ account_info::AccountInfo, entrypoint::ProgramResult, info, program_error::ProgramError, @@ -21,7 +22,7 @@ pub struct Token { /// Optional token owner, used to mint new tokens. The owner may only /// be provided during token creation. If no owner is present then the token /// has a fixed supply and no further tokens may be minted. - pub owner: Option, + pub owner: COption, } /// Delegation details. @@ -47,7 +48,7 @@ pub struct Account { /// If `delegate` is None, `amount` belongs to this account. /// If `delegate` is Option<_>, `amount` represents the remaining allowance /// of tokens this delegate is authorized to transfer from the `source` account. - pub delegate: Option, + pub delegate: COption, } /// Token program states. @@ -102,12 +103,12 @@ impl State { } if let Ok(owner_account_into) = next_account_info(account_info_iter) { - Some(*owner_account_into.key) + COption::Some(*owner_account_into.key) } else { - None + COption::None } } else if let Ok(owner_account_into) = next_account_info(account_info_iter) { - Some(*owner_account_into.key) + COption::Some(*owner_account_into.key) } else { return Err(TokenError::OwnerRequiredIfNoInitialSupply.into()); }; @@ -136,10 +137,10 @@ impl State { token: *token_account_info.key, owner: *owner_account_info.key, amount: 0, - delegate: None, + delegate: COption::None, }; if let Ok(delegate_account) = next_account_info(account_info_iter) { - token_account.delegate = Some(AccountDelegate { + token_account.delegate = COption::Some(AccountDelegate { source: *delegate_account.key, original_amount: 0, }); @@ -177,7 +178,7 @@ impl State { return Err(TokenError::InsufficientFunds.into()); } - if let Some(ref delegate) = source_account.delegate { + if let COption::Some(ref delegate) = source_account.delegate { let source_account_info = next_account_info(account_info_iter)?; let mut actual_source_data = source_account_info.data.borrow_mut(); if let State::Account(mut actual_source_account) = @@ -236,16 +237,16 @@ impl State { } match &delegate_account.delegate { - None => { + COption::None => { return Err(TokenError::NotDelegate.into()); } - Some(delegate) => { + COption::Some(delegate) => { if source_account_info.key != &delegate.source { return Err(TokenError::NotDelegate.into()); } delegate_account.amount = amount; - delegate_account.delegate = Some(AccountDelegate { + delegate_account.delegate = COption::Some(AccountDelegate { source: delegate.source, original_amount: amount, }); @@ -279,14 +280,14 @@ impl State { State::Account(account).serialize(&mut account_data)?; } State::Token(mut token) => { - if Some(*owner_account_info.key) != token.owner { + if COption::Some(*owner_account_info.key) != token.owner { return Err(TokenError::NoOwner.into()); } if !owner_account_info.is_signer { return Err(ProgramError::MissingRequiredSignature); } - token.owner = Some(*new_owner_account_info.key); + token.owner = COption::Some(*new_owner_account_info.key); State::Token(token).serialize(&mut account_data)?; } _ => { @@ -310,12 +311,12 @@ impl State { let mut token_account_data = token_account_info.data.borrow_mut(); if let State::Token(mut token) = State::deserialize(&token_account_data)? { match token.owner { - Some(owner) => { + COption::Some(owner) => { if *owner_account_info.key != owner { return Err(TokenError::NoOwner.into()); } } - None => { + COption::None => { return Err(TokenError::FixedSupply.into()); } } @@ -384,7 +385,7 @@ impl State { return Err(TokenError::InsufficientFunds.into()); } - if let Some(ref delegate) = source_account.delegate { + if let COption::Some(ref delegate) = source_account.delegate { let source_account_info = next_account_info(account_info_iter)?; let mut actual_source_data = source_account_info.data.borrow_mut(); if let State::Account(mut actual_source_account) = @@ -1315,7 +1316,7 @@ mod tests { token, Token { info, - owner: Some(owner_key) + owner: COption::Some(owner_key) } ); } else {