Skip to content

Commit

Permalink
Add support for no-alloc using static lifetime ref Box and Vec types
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmcculloch committed May 13, 2022
1 parent 17f837c commit cb2224a
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 35 deletions.
23 changes: 18 additions & 5 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,20 @@ jobs:
features: std
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
profile: release
features: std
profile: dev
features: alloc
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
profile: dev
features:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
target: wasm32-unknown-unknown
profile: release
features:
features: std
- os: ubuntu-latest
target: wasm32-unknown-unknown
profile: release
features: alloc
- os: ubuntu-latest
target: wasm32-unknown-unknown
profile: release
Expand All @@ -55,9 +59,18 @@ jobs:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
profile: test
features: std
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
profile: test
features: alloc
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
profile: test
features:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- run: rustup update stable && rustup default stable
- run: rustup target add ${{ matrix.target }}
- run: cargo test --verbose --profile ${{ matrix.profile }} --target ${{ matrix.target }}
- run: cargo test --verbose --profile ${{ matrix.profile }} --target ${{ matrix.target }} --no-default-features --features='${{ matrix.features }}'
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ base64 = "0.13.0"

[features]
default = ["std"]
std = ["base64/std"]
std = ["alloc", "base64/std"]
alloc = []
19 changes: 13 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,28 @@ XDR_FILES= \
xdr/Stellar-types.x \
xdr/Stellar-contract.x

test: build
cargo test
all: build test

test:
cargo test --no-default-features --features 'std'
cargo test --no-default-features --features 'alloc'
cargo test --no-default-features --features ''

build: src/lib.rs
cargo build --no-default-features --features 'std'
cargo build --no-default-features --features 'alloc'
cargo build --no-default-features --features ''
cargo build --target wasm32-unknown-unknown --no-default-features --features ''
cargo build --no-default-features --features 'std' --release --target wasm32-unknown-unknown
cargo build --no-default-features --features 'alloc' --release --target wasm32-unknown-unknown
cargo build --no-default-features --features '' --release --target wasm32-unknown-unknown

watch:
cargo watch --clear --watch-when-idle --shell '$(MAKE) build'
cargo watch --clear --watch-when-idle --shell '$(MAKE)'

src/lib.rs: $(XDR_FILES)
docker run -it --rm -v $$PWD:/wd -w /wd ruby /bin/bash -c '\
gem install specific_install -v 0.3.7 && \
gem specific_install https://github.com/leighmcculloch/stellar--xdrgen.git -b rust-no-deps && \
gem specific_install https://github.com/leighmcculloch/stellar--xdrgen.git -b rust-no-deps-no-alloc && \
xdrgen \
--language rust \
--namespace lib \
Expand All @@ -36,5 +43,5 @@ $(XDR_FILES):

clean:
rm -f xdr/*.x
rm -f src/xdr.rs
rm -f src/lib.rs
cargo clean
96 changes: 92 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,43 @@
#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(feature = "std"))]
use core::{fmt, fmt::Debug, slice::Iter};

#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;

#[cfg(not(feature = "alloc"))]
mod alloc {
pub mod boxed {
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Box<T>(pub &'static T)
where
T: 'static;
}
pub mod vec {
use core::slice::Iter;
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Vec<T>(pub &'static [T])
where
T: 'static;
impl<T> Vec<T> {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn iter(&self) -> Iter<T> {
self.0.iter()
}
}
impl<T> AsRef<[T]> for Vec<T> {
fn as_ref(&self) -> &[T] {
self.0
}
}
}
}
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec::Vec};

use core::{fmt, fmt::Debug, slice::Iter};

#[cfg(feature = "std")]
use std::{
error, io,
Expand Down Expand Up @@ -68,6 +97,7 @@ impl From<Error> for () {
}
}

#[allow(dead_code)]
type Result<T> = core::result::Result<T, Error>;

pub trait ReadXDR
Expand Down Expand Up @@ -325,9 +355,16 @@ impl<T: WriteXDR, const N: usize> WriteXDR for [T; N] {
}
}

#[cfg(feature = "alloc")]
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct VecM<T, const MAX: u32 = { u32::MAX }>(Vec<T>);

#[cfg(not(feature = "alloc"))]
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct VecM<T, const MAX: u32 = { u32::MAX }>(Vec<T>)
where
T: 'static;

impl<T, const MAX: u32> VecM<T, MAX> {
pub fn len(&self) -> usize {
self.0.len()
Expand Down Expand Up @@ -375,6 +412,7 @@ impl<T, const MAX: u32> AsRef<Vec<T>> for VecM<T, MAX> {
}
}

#[cfg(feature = "alloc")]
impl<T: Clone, const MAX: u32> TryFrom<&[T]> for VecM<T, MAX> {
type Error = Error;

Expand All @@ -388,12 +426,30 @@ impl<T: Clone, const MAX: u32> TryFrom<&[T]> for VecM<T, MAX> {
}
}

#[cfg(not(feature = "alloc"))]
impl<T: Clone, const MAX: u32> TryFrom<&'static [T]> for VecM<T, MAX>
where
T: 'static,
{
type Error = Error;

fn try_from(v: &'static [T]) -> Result<Self> {
let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
if len <= MAX {
Ok(VecM(Vec(v)))
} else {
Err(Error::LengthExceedsMax)
}
}
}

impl<T, const MAX: u32> AsRef<[T]> for VecM<T, MAX> {
fn as_ref(&self) -> &[T] {
&self.0
self.0.as_ref()
}
}

#[cfg(feature = "alloc")]
impl<T: Clone, const N: usize, const MAX: u32> TryFrom<[T; N]> for VecM<T, MAX> {
type Error = Error;

Expand All @@ -407,6 +463,7 @@ impl<T: Clone, const N: usize, const MAX: u32> TryFrom<[T; N]> for VecM<T, MAX>
}
}

#[cfg(feature = "alloc")]
impl<T: Clone, const N: usize, const MAX: u32> TryFrom<VecM<T, MAX>> for [T; N] {
type Error = VecM<T, MAX>;

Expand All @@ -416,6 +473,37 @@ impl<T: Clone, const N: usize, const MAX: u32> TryFrom<VecM<T, MAX>> for [T; N]
}
}

#[cfg(feature = "alloc")]
impl<T: Clone, const N: usize, const MAX: u32> TryFrom<&[T; N]> for VecM<T, MAX> {
type Error = Error;

fn try_from(v: &[T; N]) -> Result<Self> {
let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
if len <= MAX {
Ok(VecM(v.to_vec()))
} else {
Err(Error::LengthExceedsMax)
}
}
}

#[cfg(not(feature = "alloc"))]
impl<T: Clone, const N: usize, const MAX: u32> TryFrom<&'static [T; N]> for VecM<T, MAX>
where
T: 'static,
{
type Error = Error;

fn try_from(v: &'static [T; N]) -> Result<Self> {
let len: u32 = v.len().try_into().map_err(|_| Error::LengthExceedsMax)?;
if len <= MAX {
Ok(VecM(Vec(v)))
} else {
Err(Error::LengthExceedsMax)
}
}
}

impl<const MAX: u32> ReadXDR for VecM<u8, MAX> {
#[cfg(feature = "std")]
fn read_xdr(r: &mut impl Read) -> Result<Self> {
Expand Down
20 changes: 1 addition & 19 deletions tests/tx.rs → tests/tx_prot18.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,6 @@
use stellar_xdr::*;

#[test]
fn test_build_small_tx() -> Result<(), Error> {
let te = TransactionEnvelope::EnvelopeTypeTx(TransactionV1Envelope {
tx: Transaction {
source_account: MuxedAccount::KeyTypeEd25519(Uint256([0; 32])),
fee: 0,
seq_num: SequenceNumber(1),
cond: Preconditions::PrecondNone,
memo: Memo::MemoText("Stellar".as_bytes().try_into()?),
operations: [].to_vec().try_into()?,
ext: TransactionExt::V0,
},
signatures: [].try_into()?,
});
let xdr = te.to_xdr_base64()?;
assert_eq!(xdr, "AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAB1N0ZWxsYXIAAAAAAAAAAAAAAAAA");
Ok(())
}

#[cfg(feature = "std")]
#[test]
fn test_parse_pubnet_v18_tx() -> Result<(), Error> {
let xdr = "AAAAAgAAAAA/ESDPPSBIB8pWPGt/zZ3dSJhShRxziDdkmLQXrdytCQAPQkAACMblAAAABQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAABB90WssODNIgi6BHveqzxTRmIpvAFRyVNM+Hm2GVuCcAAAAAAAAAAAtDSg//ZfvJXgv2/0yiA7QUDWdXpKYhdjYEWkN4yVm+AAAABdIdugAAAAAAAAAAAKt3K0JAAAAQC3/n83fG/BCSRaIQjuqL2i1koiCHChxt1aagXn2ABCRP9IL83u5zldxuUaDBklKOHEdy4cOvl2BhPNbjs7w0QSGVuCcAAAAQKxHSgHZgZY7AMlPumIt0iZvtkbsRAtt6BYahJdnxrqm3+JuCVv/1ijWi1kM85uLfo7NAITi1TbdLg0gVFO16wM=";
Expand Down
57 changes: 57 additions & 0 deletions tests/tx_small.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use stellar_xdr::*;

#[cfg(feature = "std")]
#[test]
fn test_build_small_tx_with_std() -> Result<(), Error> {
let te = TransactionEnvelope::EnvelopeTypeTx(TransactionV1Envelope {
tx: Transaction {
source_account: MuxedAccount::KeyTypeEd25519(Uint256([0; 32])),
fee: 0,
seq_num: SequenceNumber(1),
cond: Preconditions::PrecondNone,
memo: Memo::MemoText("Stellar".as_bytes().try_into()?),
operations: [].to_vec().try_into()?,
ext: TransactionExt::V0,
},
signatures: [].try_into()?,
});
let xdr = te.to_xdr_base64()?;
assert_eq!(xdr, "AAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAB1N0ZWxsYXIAAAAAAAAAAAAAAAAA");
Ok(())
}

#[cfg(feature = "alloc")]
#[test]
fn test_build_small_tx_with_alloc() -> Result<(), Error> {
let _ = TransactionEnvelope::EnvelopeTypeTx(TransactionV1Envelope {
tx: Transaction {
source_account: MuxedAccount::KeyTypeEd25519(Uint256([0; 32])),
fee: 0,
seq_num: SequenceNumber(1),
cond: Preconditions::PrecondNone,
memo: Memo::MemoText("Stellar".as_bytes().try_into()?),
operations: [].to_vec().try_into()?,
ext: TransactionExt::V0,
},
signatures: [].try_into()?,
});
Ok(())
}

#[cfg(not(feature = "alloc"))]
#[test]
fn test_build_small_tx_with_alloc() -> Result<(), Error> {
let _ = TransactionEnvelope::EnvelopeTypeTx(TransactionV1Envelope {
tx: Transaction {
source_account: MuxedAccount::KeyTypeEd25519(Uint256([0; 32])),
fee: 0,
seq_num: SequenceNumber(1),
cond: Preconditions::PrecondNone,
memo: Memo::MemoText("Stellar".as_bytes().try_into()?),
operations: (&[]).try_into()?,
ext: TransactionExt::V0,
},
signatures: (&[]).try_into()?,
});
Ok(())
}

0 comments on commit cb2224a

Please sign in to comment.