Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert BigInt/Decimal to expected types for packed numbers #1391

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

jadams-tresys
Copy link
Contributor

Still have an edge case for packed xs:date/Time values require an actual BigInt, but this fixes DAFFODIL-2961

Copy link
Contributor

@mbeckerle mbeckerle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1
I don't have much to add beyond finding one typo.

@jadams-tresys
Copy link
Contributor Author

I think I've addressed all the comments from review now. I have now rebased onto main, which now includes the fixes from #1337. Definitely was a mistake to rebase onto that earlier before it was merged.

Copy link
Member

@stevedlawrence stevedlawrence left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 looks good � , just needs lint fixes and one small change to remove a val that I think is now unused

Packed numbers had been represented internally as BigInt/Decimal.  This
could cause issues when the values were referenced as part of an
expression and would lead to class conversion errors.  This commit
parses the packed numbers into their expected numeric type.

DAFFODIL-2961
Copy link
Contributor

@mbeckerle mbeckerle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just added some questions, and suggest adding a scaladoc to motivate the toNumber method name change.

override def toBigInteger(num: Array[Byte]): JBigInteger = DecimalUtils.bcdToBigInteger(num)
override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
DecimalUtils.bcdToBigDecimal(num, scale)
override def toNumber(num: Array[Byte]): JBigInteger = DecimalUtils.bcdToBigInteger(num)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the return type is different. toNumber returns a JBigInteger.

I'm surprised this even works. JBigInteger must be a sub-type of JBigDecimal.

override def toBigInteger(num: Array[Byte]): JBigInteger = DecimalUtils.bcdToBigInteger(num)
override def toBigDecimal(num: Array[Byte], scale: Int): JBigDecimal =
DecimalUtils.bcdToBigDecimal(num, scale)
override def toNumber(num: Array[Byte]): JBigDecimal =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change this to toNumber? The return type is not JNumber.

Is there scaladoc on the toNumber method? There needs to be to explain this naming convention. I don't really understand why this got renamed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trait these classes mix in requires an implementation of def toNumber(num: Array[Byte]): A, where A <: Number. We could remove the A type parameter and just make it so it always returns a JNumber, but then implementations have to be a bit more careful to return the right thing.

As it is right now, the type parameter ensures the implementations of toNumber return the right kind of JNumber (some should always return a BigInteger, some should always return a BigDecimal). I'm not sure the type parameter is used anywhere else though, so maybe that's overkill and just adds unnecessary complication?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the type parameter is almost certainly the right thing, I just don't see a change that adds this toNumber super method declaration, yet it's not in the current Daffodil main branch, so when did this type parameter get added?

But what is the purpose of the toNumber method? I think it is "convert to a number type we can store in the Infoset object. This should be the most specific meaningful subtype of JNumber" that is used in the Infoset object representation. Or something like that.

Copy link
Contributor Author

@jadams-tresys jadams-tresys Jan 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The top level declaration of toNumber is in PackedBinaryTraits.scala where it is simply declared as

    trait PackedBinaryConversion[A <: Number] {
        def toNumber(num: Array[Byte]): A
        ....

The actual implementations are in the classes that extend the PackedBinaryConversion trait, like BCDIntegerKnownLengthParser.

The function will only generate either BigInteger's or BigDecimal's depending on the calling classes type, so perhaps a better name for the function would be "toBigNumber". The BigNumber then gets converted to the appropriate PrimType by calling PrimNumberic.fromNumber(bigNumber). This call is made by the toPrimType function of the same trait.

@jadams-tresys
Copy link
Contributor Author

I've made another small change that I had forgotten about. We don't want to check the bit length of binary numbers during schema compilation if the binaryNumberRep is not "binary" as it can take more than 4 bytes to represent an xs:int for example. Please double check that this simple extra conditional is a reasonable solution to this.

<tdml:error>Error in packed data</tdml:error>
<tdml:error>out of range for type</tdml:error>
</tdml:errors>
</tdml:parserTestCase>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a positive test case for this? To show that you can have a large amount of bytes for packed values as long as the result is within range of the type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants