Browse Source

lang: Add `InstructionData::write_to` implementation (#2733)

Co-authored-by: acheron <98934430+acheroncrypto@users.noreply.github.com>
Co-authored-by: acheron <acheroncrypto@gmail.com>
cavemanloverboy 1 year ago
parent
commit
c2b5472d85
3 changed files with 47 additions and 0 deletions
  1. 1 0
      CHANGELOG.md
  2. 10 0
      lang/src/lib.rs
  3. 36 0
      lang/tests/serialization.rs

+ 1 - 0
CHANGELOG.md

@@ -15,6 +15,7 @@ The minor version will be incremented upon a breaking change and the patch versi
 - cli: Allow force `init` and `new` ([#2698](https://github.com/coral-xyz/anchor/pull/2698)).
 - cli: Add verifiable option when `deploy` ([#2705](https://github.com/coral-xyz/anchor/pull/2705)).
 - cli: Add support for passing arguments to the underlying `solana program deploy` command with `anchor deploy` ([#2709](https://github.com/coral-xyz/anchor/pull/2709)).
+- lang: Add `InstructionData::write_to` implementation ([#2733](https://github.com/coral-xyz/anchor/pull/2733)).
 
 ### Fixes
 

+ 10 - 0
lang/src/lib.rs

@@ -271,6 +271,16 @@ pub trait InstructionData: Discriminator + AnchorSerialize {
         self.serialize(&mut data).unwrap();
         data
     }
+
+    /// Clears `data` and writes instruction data to it.
+    ///
+    /// We use a `Vec<u8>`` here because of the additional flexibility of re-allocation (only if
+    /// necessary), and because the data field in `Instruction` expects a `Vec<u8>`.
+    fn write_to(&self, mut data: &mut Vec<u8>) {
+        data.clear();
+        data.extend_from_slice(&Self::DISCRIMINATOR);
+        self.serialize(&mut data).unwrap()
+    }
 }
 
 /// An event that can be emitted via a Solana log. See [`emit!`](crate::prelude::emit) for an example.

+ 36 - 0
lang/tests/serialization.rs

@@ -0,0 +1,36 @@
+use anchor_lang::{AnchorDeserialize, AnchorSerialize, Discriminator, InstructionData};
+
+#[test]
+fn test_instruction_data() {
+    // Define some test type and implement ser/de, discriminator, and ix data
+    #[derive(Default, AnchorSerialize, AnchorDeserialize, PartialEq, Eq)]
+    struct MyType {
+        foo: [u8; 8],
+        bar: String,
+    }
+    impl Discriminator for MyType {
+        const DISCRIMINATOR: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
+    }
+    impl InstructionData for MyType {}
+
+    // Initialize some instance of the type
+    let instance = MyType {
+        foo: [0, 2, 4, 6, 8, 10, 12, 14],
+        bar: "sharding sucks".into(),
+    };
+
+    // Serialize using both methods
+    let data = instance.data();
+    let mut write = vec![];
+    instance.write_to(&mut write);
+
+    // Check that one is correct and that they are equal (implies other is correct)
+    let correct_disc = data[0..8] == MyType::DISCRIMINATOR;
+    let correct_data = MyType::deserialize(&mut &data[8..]).is_ok_and(|result| result == instance);
+    let correct_serialization = correct_disc & correct_data;
+    assert!(correct_serialization, "serialization was not correct");
+    assert_eq!(
+        &data, &write,
+        "the different methods produced different serialized representations"
+    );
+}