verty 0.1.0

procedural macro to generate different versions of a type
Documentation
assert_expansion_eq!(unversioned: {
	struct Foo {
		a: u8,
		b: u16
	}
} => {
	struct FooV0 {
		a: u8,
		b: u16
	}
});

// unions should works exactly like structs, but test this simple case just to be sure
assert_expansion_eq!(unversioned_union: {
	union Foo {
		a: u8,
		b: u16
	}
} => {
	union FooV0 {
		a: u8,
		b: u16
	}
});

assert_expansion_eq!(single_literal: {
	struct Foo {
		a: u8,
		#[ver = 1]
		b: u16,
		#[ver = 2]
		c: u32
	}
} => {
	struct FooV0 {
		a: u8
	}

	struct FooV1 {
		a: u8,
		b: u16
	}

	struct FooV2 {
		a: u8,
		c: u32
	}
});

assert_expansion_eq!(one_based: (start = 1){
	struct Foo {
		a: u8,
		#[ver = 2..]
		b: u16
	}
} => {
	struct FooV1 {
		a: u8
	}

	struct FooV2 {
		a: u8,
		b: u16
	}
});

assert_expansion_eq!(manual_end: (end = 1){
	struct Foo {}
} => {
	struct FooV0 {}

	struct FooV1 {}
});

assert_expansion_eq!(rename_version: (rename(1 => Bar)){
	struct Foo {
		a: u8,
		#[ver = 1..=2]
		b: u16
	}
} => {
	struct FooV0 {
		a: u8
	}

	struct Bar {
		a: u8,
		b: u16
	}

	struct FooV2 {
		a: u8,
		b: u16
	}
});

assert_expansion_eq!(added_fields: {
	struct Foo {
		a: u8,
		#[ver = 1..]
		b: u16,
		#[ver = 2..=3]
		c: u32,
		#[ver = ..2]
		d: u64
	}
} => {
	struct FooV0 {
		a: u8,
		d: u64
	}

	struct FooV1 {
		a: u8,
		b: u16,
		d: u64
	}

	struct FooV2 {
		a: u8,
		b: u16,
		c: u32
	}

	struct FooV3 {
		a: u8,
		b: u16,
		c: u32
	}
});

assert_expansion_eq!(@no_doctest version_attrs: {
	#[derive(Bar, Baz)]
	#[ver_attr(1..=2, derive(Serialize))]
	#[attr]
	#[ver_attr(..2, quux)]
	struct Foo {
		#[ver = 0..=1]
		#[ver_attr(0, field)]
		a: u8,
		#[ver = 1..]
		b: String,
		#[ver = 3..]
		f: fn()
	}
} => {
	#[derive(Bar, Baz)]
	#[attr]
	#[quux]
	struct FooV0 {
		#[field]
		a: u8
	}

	#[derive(Bar, Baz)]
	#[derive(Serialize)]
	#[attr]
	#[quux]
	struct FooV1 {
		a: u8,
		b: String
	}

	#[derive(Bar, Baz)]
	#[derive(Serialize)]
	#[attr]
	struct FooV2 {
		b: String
	}

	#[derive(Bar, Baz)]
	#[attr]
	struct FooV3 {
		b: String,
		f: fn()
	}
});

assert_expansion_eq!(added_generics: {
	struct Foo<T, #[ver = 1..] U: Copy, #[ver = ..2] V> {
		a: T,
		#[ver = 2..]
		b: U,
		#[ver = 1]
		marker: std::marker::PhantomData<(U, V)>,
		#[ver = 0]
		c: V,
	}
} => {
	struct FooV0<T, V> {
		a: T,
		c: V
	}

	struct FooV1<T, U: Copy, V> {
		a: T,
		marker: std::marker::PhantomData<(U, V)>
	}

	struct FooV2<T, U: Copy> {
		a: T,
		b: U
	}
});

assert_expansion_eq!(version_wheres_1: {
	#[ver_where(1, T: Clone)]
	struct Foo<T, U> {
		#[ver = ..=1]
		a: T,
		#[ver = 2..]
		b: [T; 0],
		#[ver = 0]
		c: [U; 0],
		#[ver = 1..=2]
		c: U,
		#[ver = 3..]
		d: [U; 2]
	}
} => {
	struct FooV0<T, U> {
		a: T,
		c: [U; 0]
	}

	struct FooV1<T, U>
	where T: Clone
	{
		a: T,
		c: U
	}

	struct FooV2<T, U> {
		b: [T; 0],
		c: U
	}

	struct FooV3<T, U> {
		b: [T; 0],
		d: [U; 2]
	}
});

assert_expansion_eq!(version_wheres_2: {
	#[ver_where(1, u8: Copy)]
	struct Bar
	where u8: Sized {}
} => {
	struct BarV0
	where u8: Sized {}

	struct BarV1
	where u8: Sized, u8: Copy {}
});

assert_expansion_eq!(@no_doctest ver_field_type: (end = 1){
	struct Foo {
		bar: VerType!(Bar)
	}
} => {
	struct FooV0 {
		bar: BarV0
	}

	struct FooV1 {
		bar: BarV1
	}
});

assert_expansion_eq!(@no_doctest ver_field_type_2: (end = 1){
	struct Foo {
		bar: Option<VerType!(Bar)>
	}
} => {
	struct FooV0 {
		bar: Option<BarV0>
	}

	struct FooV1 {
		bar: Option<BarV1>
	}
});

assert_expansion_eq!(@no_doctest ver_field_type_3: (end = 4){
	struct Foo {
		bar: ver_match! {
			0 => { Bar };
			1..=2 => { Baz };
			3.. => { Qux };
		}
	}
} => {
	struct FooV0 {
		bar: Bar
	}

	struct FooV1 {
		bar: Baz
	}

	struct FooV2 {
		bar: Baz
	}

	struct FooV3 {
		bar: Qux
	}

	struct FooV4 {
		bar: Qux
	}
});

assert_expansion_eq!(@no_doctest ver_gen_1: (end = 1){
	struct Foo<#[ver = 1] T> {
		bar: Bar<ver_gen!(1, T)>
	}
} => {
	struct FooV0<> {
		bar: Bar<>
	}

	struct FooV1<T> {
		bar: Bar<T>
	}
});

assert_expansion_eq!(@no_doctest ver_gen_2: (end = 1){
	struct Foo<I: IntoIterator<ver_gen!(0, Item = u8), ver_gen!(1, IntoIter: Clone)> + FooTrait<ver_gen!(1, BOOL = false)>> {
		bar: Bar<ver_gen!(0, 'static), I, ver_gen!(1, { 10 })>
	}
} => {
	struct FooV0<I: IntoIterator<Item = u8> + FooTrait<>> {
		bar: Bar<'static, I>
	}

	struct FooV1<I: IntoIterator<IntoIter: Clone> + FooTrait<BOOL = false>> {
		bar: Bar<I, { 10 }>
	}
});

assert_expansion_eq!(@no_doctest ver_gen_in_ver_type: (end = 1){
	struct Foo<#[ver = 1] T> {
		bar: VerType!(Bar<ver_gen!(1, T)>)
	}
} => {
	struct FooV0<> {
		bar: BarV0<>
	}

	struct FooV1<T> {
		bar: BarV1<T>
	}
});

assert_expansion_error!(below_min: (start = 1){
	struct Foo {
		#[ver = 0..]
		a: u8
	}
} => "version 0 is below minimum version (1)");

assert_expansion_error!(above_max: (end = 1){
	struct Foo {
		#[ver = 0..2]
		a: u8
	}
} => "version 2 is above maximum version (1)");