Skip to content

Commit

Permalink
support negative index values
Browse files Browse the repository at this point in the history
  • Loading branch information
KodrAus committed Sep 1, 2023
1 parent 4319842 commit a860809
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 34 deletions.
2 changes: 1 addition & 1 deletion derive/src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ to use for the annotated item.
pub(crate) struct Index;

impl SvalAttribute for Index {
type Result = usize;
type Result = isize;

fn from_lit(&self, lit: &Lit) -> Self::Result {
if let Lit::Int(ref n) = lit {
Expand Down
14 changes: 7 additions & 7 deletions derive/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,9 @@ fn quote_optional_label(label: Option<&str>) -> proc_macro2::TokenStream {

fn quote_index(index: Index) -> proc_macro2::TokenStream {
match index {
Index::Explicit(index) => quote!(&sval::Index::new(#index)),
Index::Explicit(index) => quote!(&sval::Index::from(#index)),
Index::Implicit(index) => {
quote!(&sval::Index::new(#index).with_tag(&sval::tags::VALUE_OFFSET))
quote!(&sval::Index::from(#index).with_tag(&sval::tags::VALUE_OFFSET))
}
}
}
Expand All @@ -554,7 +554,7 @@ fn quote_optional_index(index: Option<Index>) -> proc_macro2::TokenStream {
}

struct IndexAllocator {
next_index: usize,
next_index: isize,
explicit: bool,
}

Expand All @@ -566,11 +566,11 @@ impl IndexAllocator {
}
}

fn index_of(explicit: Option<usize>) -> Option<Index> {
fn index_of(explicit: Option<isize>) -> Option<Index> {
explicit.map(Index::Explicit)
}

fn next_index(&mut self, explicit: Option<usize>) -> Index {
fn next_index(&mut self, explicit: Option<isize>) -> Index {
if let Some(index) = explicit {
self.explicit = true;
self.next_index = index + 1;
Expand All @@ -591,6 +591,6 @@ impl IndexAllocator {

#[derive(Debug, Clone, Copy)]
enum Index {
Implicit(usize),
Explicit(usize),
Implicit(isize),
Explicit(isize),
}
22 changes: 11 additions & 11 deletions derive/test/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,16 +414,16 @@ mod derive_enum {
#[derive(Value)]
#[sval(tag = "CONTAINER", label = "enum", index = 0)]
enum Enum {
#[sval(tag = "VARIANT", label = "tag", index = 1)]
#[sval(tag = "VARIANT", label = "tag", index = -1)]
Tag,
#[sval(tag = "VARIANT", label = "tagged", index = 2)]
#[sval(tag = "VARIANT", label = "tagged", index = -2)]
Tagged(i32),
#[sval(tag = "VARIANT", label = "record", index = 3)]
#[sval(tag = "VARIANT", label = "record", index = -3)]
Record {
#[sval(tag = "FIELD", label = "field")]
a: i32,
},
#[sval(tag = "VARIANT", label = "tuple", index = 4)]
#[sval(tag = "VARIANT", label = "tuple", index = -4)]
Tuple(
#[sval(tag = "FIELD", index = 1)] i32,
#[sval(tag = "FIELD", index = 2)] i32,
Expand All @@ -442,7 +442,7 @@ mod derive_enum {
Tag(
Some(VARIANT),
Some(sval::Label::new("tag")),
Some(sval::Index::new(1)),
Some(sval::Index::new_isize(-1)),
),
EnumEnd(
Some(CONTAINER),
Expand All @@ -464,13 +464,13 @@ mod derive_enum {
TaggedBegin(
Some(VARIANT),
Some(sval::Label::new("tagged")),
Some(sval::Index::new(2)),
Some(sval::Index::new_isize(-2)),
),
I32(42),
TaggedEnd(
Some(VARIANT),
Some(sval::Label::new("tagged")),
Some(sval::Index::new(2)),
Some(sval::Index::new_isize(-2)),
),
EnumEnd(
Some(CONTAINER),
Expand All @@ -492,7 +492,7 @@ mod derive_enum {
RecordTupleBegin(
Some(VARIANT),
Some(sval::Label::new("record")),
Some(sval::Index::new(3)),
Some(sval::Index::new_isize(-3)),
Some(1),
),
RecordTupleValueBegin(Some(FIELD), sval::Label::new("field"), sval::Index::new(0)),
Expand All @@ -501,7 +501,7 @@ mod derive_enum {
RecordTupleEnd(
Some(VARIANT),
Some(sval::Label::new("record")),
Some(sval::Index::new(3)),
Some(sval::Index::new_isize(-3)),
),
EnumEnd(
Some(CONTAINER),
Expand All @@ -523,7 +523,7 @@ mod derive_enum {
TupleBegin(
Some(VARIANT),
Some(sval::Label::new("tuple")),
Some(sval::Index::new(4)),
Some(sval::Index::new_isize(-4)),
Some(2),
),
TupleValueBegin(Some(FIELD), sval::Index::new(1)),
Expand All @@ -535,7 +535,7 @@ mod derive_enum {
TupleEnd(
Some(VARIANT),
Some(sval::Label::new("tuple")),
Some(sval::Index::new(4)),
Some(sval::Index::new_isize(-4)),
),
EnumEnd(
Some(CONTAINER),
Expand Down
154 changes: 139 additions & 15 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,21 +246,85 @@ impl fmt::Debug for Tag {
The index of a value in its parent context.
*/
#[derive(Clone)]
pub struct Index(usize, Option<Tag>);
pub struct Index(i128, Option<Tag>);

impl From<i32> for Index {
fn from(index: i32) -> Self {
Index::new_i32(index)
}
}

impl From<i64> for Index {
fn from(index: i64) -> Self {
Index::new_i64(index)
}
}

impl From<isize> for Index {
fn from(index: isize) -> Self {
Index::new_isize(index)
}
}

impl From<u32> for Index {
fn from(index: u32) -> Self {
Index::new_u32(index)
}
}

impl From<u64> for Index {
fn from(index: u64) -> Self {
Index::new_u64(index)
}
}

impl From<usize> for Index {
fn from(index: usize) -> Self {
Index::new(index)
}
}

impl Index {
/**
Create a new index from a numeric value.
*/
pub const fn new(index: usize) -> Self {
Index(index, None)
Index(index as i128, None)
}

/**
Create a new None index from a 32bit numeric value.
*/
pub const fn new_u32(index: u32) -> Self {
Index(index as usize, None)
Index(index as i128, None)
}

/**
Create a new None index from a 64bit numeric value.
*/
pub const fn new_u64(index: u64) -> Self {
Index(index as i128, None)
}

/**
Create a new None index from a signed 32bit numeric value.
*/
pub const fn new_i32(index: i32) -> Self {
Index(index as i128, None)
}

/**
Create a new None index from a signed 64bit numeric value.
*/
pub const fn new_i64(index: i64) -> Self {
Index(index as i128, None)
}

/**
Create a new None index from a signed numeric value.
*/
pub const fn new_isize(index: isize) -> Self {
Index(index as i128, None)
}

/**
Expand All @@ -277,31 +341,68 @@ impl Index {
Try get the index as a numeric value.
*/
pub const fn to_usize(&self) -> Option<usize> {
Some(self.0)
if self.0 >= usize::MIN as i128 && self.0 <= usize::MAX as i128 {
Some(self.0 as usize)
} else {
None
}
}

/**
Try get the index as a 32-bit numeric value.
*/
pub const fn to_u32(&self) -> Option<u32> {
if self.0 <= u32::MAX as usize {
if self.0 >= u32::MIN as i128 && self.0 <= u32::MAX as i128 {
Some(self.0 as u32)
} else {
None
}
}

/**
Try get the index as a 64-bit numeric value.
Try get the index as a 64-bit numeric value.
*/
pub const fn to_u64(&self) -> Option<u64> {
if self.0 <= u64::MAX as usize {
if self.0 >= u64::MIN as i128 && self.0 <= u64::MAX as i128 {
Some(self.0 as u64)
} else {
None
}
}

/**
Try get the index as a signed numeric value.
*/
pub const fn to_isize(&self) -> Option<isize> {
if self.0 >= isize::MIN as i128 && self.0 <= isize::MAX as i128 {
Some(self.0 as isize)
} else {
None
}
}

/**
Try get the index as a signed 32-bit numeric value.
*/
pub const fn to_i32(&self) -> Option<i32> {
if self.0 >= i32::MIN as i128 && self.0 <= i32::MAX as i128 {
Some(self.0 as i32)
} else {
None
}
}

/**
Try get the index as a signed 64-bit numeric value.
*/
pub const fn to_i64(&self) -> Option<i64> {
if self.0 >= i64::MIN as i128 && self.0 <= i64::MAX as i128 {
Some(self.0 as i64)
} else {
None
}
}

/**
Get the tag hint associated with the index, if present.
Expand Down Expand Up @@ -470,15 +571,38 @@ mod tests {
}

#[test]
fn index() {
let small = Index::new(1);
let large = Index::new(usize::MAX);

if usize::MAX > (u32::MAX as usize) {
assert!(large.to_u32().is_none());
fn index_convert() {
for (index, to_i32, to_i64, to_u32, to_u64) in [
(
Index::from(0),
Some(0i32),
Some(0i64),
Some(0u32),
Some(0u64),
),
(
Index::from(i32::MIN),
Some(i32::MIN),
Some(i32::MIN as i64),
None,
None,
),
(Index::from(i64::MIN), None, Some(i64::MIN), None, None),
(
Index::from(u32::MAX),
None,
Some(u32::MAX as i64),
Some(u32::MAX),
Some(u32::MAX as u64),
),
(Index::from(u64::MAX), None, None, None, Some(u64::MAX)),
] {
assert_eq!(to_i32, index.to_i32(), "{:?}", index);
assert_eq!(to_i64, index.to_i64(), "{:?}", index);

assert_eq!(to_u32, index.to_u32(), "{:?}", index);
assert_eq!(to_u64, index.to_u64(), "{:?}", index);
}

assert_eq!(1, small.to_u32().unwrap());
}

#[test]
Expand Down

0 comments on commit a860809

Please sign in to comment.