BSON

 view release on metacpan or  search on metacpan

corpus/README.md  view on Meta::CPAN

    { "$code": "<code here>" }

    # Javascript with scope
    { "$code": "<code here>": "$scope": { "x":1, "y":1 } }

    # Int32
    { "$numberInt": "<number>" }

However, this corpus extends JSON further to include the following:

    # Double (needed for NaN, etc.)
    { "$numberDouble": "<value|NaN|Inf|-Inf>" }

    # DBpointer (deprecated): <id> is 24 hex chars
    { "$dbpointer": "<id>", "$ns":"<namespace>" }

    # Symbol (deprecated)
    { "$symbol": "<text>" }

## Visualizing BSON

The directory includes a Perl script `bsonview`, which will decompose and

corpus/decimal128-1.json  view on Meta::CPAN

{
    "description": "Decimal128",
    "bson_type": "0x13",
    "test_key": "d",
    "valid": [
        {
            "description": "Special - Canonical NaN",
            "canonical_bson": "180000001364000000000000000000000000000000007C00",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}"
        },
        {
            "description": "Special - Negative NaN",
            "canonical_bson": "18000000136400000000000000000000000000000000FC00",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
            "lossy": true
        },
        {
            "description": "Special - Negative NaN",
            "canonical_bson": "18000000136400000000000000000000000000000000FC00",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"-NaN\"}}",
            "lossy": true
        },
        {
            "description": "Special - Canonical SNaN",
            "canonical_bson": "180000001364000000000000000000000000000000007E00",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
            "lossy": true
        },
        {
            "description": "Special - Negative SNaN",
            "canonical_bson": "18000000136400000000000000000000000000000000FE00",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
            "lossy": true
        },
        {
            "description": "Special - NaN with a payload",
            "canonical_bson": "180000001364001200000000000000000000000000007E00",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}",
            "lossy": true
        },
        {
            "description": "Special - Canonical Positive Infinity",
            "canonical_bson": "180000001364000000000000000000000000000000007800",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
        },
        {
            "description": "Special - Canonical Negative Infinity",
            "canonical_bson": "18000000136400000000000000000000000000000000F800",

corpus/decimal128-1.json  view on Meta::CPAN

        {
            "description": "Non-Canonical Parsing - Long Decimal String",
            "canonical_bson": "180000001364000100000000000000000000000000722800",
            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \".0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1E-999\"}}"
        },
        {
            "description": "Non-Canonical Parsing - nan",
            "canonical_bson": "180000001364000000000000000000000000000000007C00",
            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"nan\"}}",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}"
        },
        {
            "description": "Non-Canonical Parsing - nAn",
            "canonical_bson": "180000001364000000000000000000000000000000007C00",
            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"nAn\"}}",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}"
        },
        {
            "description": "Non-Canonical Parsing - +infinity",
            "canonical_bson": "180000001364000000000000000000000000000000007800",
            "degenerate_extjson": "{\"d\" : {\"$numberDecimal\" : \"+infinity\"}}",
            "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
        },
        {
            "description": "Non-Canonical Parsing - infinity",
            "canonical_bson": "180000001364000000000000000000000000000000007800",

corpus/decimal128-2.json  view on Meta::CPAN

          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"Infinity\"}}"
       },
       {
          "description": "[decq528] Specials",
          "canonical_bson": "18000000136400000000000000000000000000000000F800",
          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"-Infinity\"}}"
       },
       {
          "description": "[decq541] Specials",
          "canonical_bson": "180000001364000000000000000000000000000000007C00",
          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"NaN\"}}"
       },
       {
          "description": "[decq074] Nmin and below",
          "canonical_bson": "18000000136400000000000A5BC138938D44C64D31000000",
          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E-6143\"}}"
       },
       {
          "description": "[decq602] fold-down full sequence",
          "canonical_bson": "18000000136400000000000A5BC138938D44C64D31FE5F00",
          "canonical_extjson": "{\"d\" : {\"$numberDecimal\" : \"1.000000000000000000000000000000000E+6144\"}}"

corpus/decimal128-4.json  view on Meta::CPAN

       {
          "description": "[basx568] Near-specials (Conversion_syntax)",
          "string": "-Infinit"
       },
       {
          "description": "[basx590] some baddies with dots and Es and dots and specials (Conversion_syntax)",
          "string": ".Infinity"
       },
       {
          "description": "[basx562] Near-specials (Conversion_syntax)",
          "string": "NaNq"
       },
       {
          "description": "[basx563] Near-specials (Conversion_syntax)",
          "string": "NaNs"
       },
       {
          "description": "[dqbas939] overflow results at different rounding modes (Overflow & Inexact & Rounded)",
          "string": "-7e10000"
       },
       {
          "description": "[dqbsr534] negatives (Rounded & Inexact)",
          "string": "-1.11111111111111111111111111111234650"
       },
       {

corpus/decimal128-7.json  view on Meta::CPAN

       {
          "description": "[basx569] Near-specials (Conversion_syntax)",
          "string": "0Inf"
       },
       {
          "description": "[basx571] Near-specials (Conversion_syntax)",
          "string": "-0Inf"
       },
       {
          "description": "[basx575] Near-specials (Conversion_syntax)",
          "string": "0sNaN"
       },
       {
          "description": "[basx503] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": "++1"
       },
       {
          "description": "[basx504] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": "--1"
       },
       {

corpus/decimal128-7.json  view on Meta::CPAN

       {
          "description": "[basx585] some baddies with dots and Es and dots and specials (Conversion_syntax)",
          "string": "-.E"
       },
       {
          "description": "[basx589] some baddies with dots and Es and dots and specials (Conversion_syntax)",
          "string": "+.Inf"
       },
       {
          "description": "[basx586] some baddies with dots and Es and dots and specials (Conversion_syntax)",
          "string": ".NaN"
       },
       {
          "description": "[basx587] some baddies with dots and Es and dots and specials (Conversion_syntax)",
          "string": "-.NaN"
       },
       {
          "description": "[basx545] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": "ONE"
       },
       {
          "description": "[basx561] Near-specials (Conversion_syntax)",
          "string": "qNaN"
       },
       {
          "description": "[basx573] Near-specials (Conversion_syntax)",
          "string": "-sNa"
       },
       {
          "description": "[basx588] some baddies with dots and Es and dots and specials (Conversion_syntax)",
          "string": "+.sNaN"
       },
       {
          "description": "[basx544] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": "ten"
       },
       {
          "description": "[basx527] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": "u0b65"
       },
       {
          "description": "[basx526] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": "u0e5a"
       },
       {
          "description": "[basx515] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": "x"
       },
       {
          "description": "[basx574] Near-specials (Conversion_syntax)",
          "string": "xNaN"
       },
       {
          "description": "[basx530] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": ".123.5"
       },
       {
          "description": "[basx500] The 'baddies' tests from DiagBigDecimal, plus some new ones (Conversion_syntax)",
          "string": "1..2"
       },
       {

corpus/double.json  view on Meta::CPAN

            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"0.0\"}}",
            "relaxed_extjson": "{\"d\" : 0.0}"
        },
        {
            "description": "-0.0",
            "canonical_bson": "10000000016400000000000000008000",
            "canonical_extjson": "{\"d\" : {\"$numberDouble\": \"-0.0\"}}",
            "relaxed_extjson": "{\"d\" : -0.0}"
        },
        {
            "description": "NaN",
            "canonical_bson": "10000000016400000000000000F87F00",
            "canonical_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}",
            "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}",
            "lossy": true
        },
        {
            "description": "NaN with payload",
            "canonical_bson": "10000000016400120000000000F87F00",
            "canonical_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}",
            "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"NaN\"}}",
            "lossy": true
        },
        {
            "description": "Inf",
            "canonical_bson": "10000000016400000000000000F07F00",
            "canonical_extjson": "{\"d\": {\"$numberDouble\": \"Infinity\"}}",
            "relaxed_extjson": "{\"d\": {\"$numberDouble\": \"Infinity\"}}"
        },
        {
            "description": "-Inf",

lib/BSON.pm  view on Meta::CPAN

                }
                else {
                    return { '$numberLong' => "$data" };
                }
            }
            else {
                return { '$numberDouble' => 'Infinity' }
                    if $data =~ $is_inf;
                return { '$numberDouble' => '-Infinity' }
                    if $data =~ $is_ninf;
                return { '$numberDouble' => 'NaN' }
                    if $data =~ $is_nan;
                my $value = "$data";
                $value = $value / 1.0;
                return { '$numberDouble' => "$value" };
            }
        }

        return $data;
    }

lib/BSON/Decimal128.pm  view on Meta::CPAN

    my $bid = shift;
    my $binary = unpack( "B*", scalar reverse($bid) );
    my ( $coef, $e );

    # sign bit
    my $pos = !substr( $binary, 0, 1 );

    # detect special values from first 5 bits after sign bit
    my $special = substr( $binary, 1, 5 );
    if ( $special eq "11111" ) {
        return "NaN";
    }
    if ( $special eq "11110" ) {
        return $pos ? "Infinity" : "-Infinity";
    }

    if ( substr( $binary, 1, 2 ) eq '11' ) {
        # Bits: 1*sign 2*ignored 14*exponent 111*significand.
        # Implicit 0b100 prefix in significand.
        $coef = "" . Math::BigInt->new( "0b100" . substr( $binary, 17 ) );
        $e = unpack( "n", pack( "B*", "00" . substr( $binary, 3, 14 ) ) ) - BIAS;

lib/BSON/Decimal128.pm  view on Meta::CPAN

        # maybe coefficient is exact length?
        return $pos ? "0.$coef" : "-0.$coef"
          if length($coef) == abs($e);

        # otherwise length(coef) > abs($e), so insert dot after first digit
        substr( $coef, $e, 0, "." );
        return $pos ? $coef : "-$coef";
    }
}

my ( $bidNaN, $bidPosInf, $bidNegInf ) =
  map { scalar reverse pack( "B*", $_ . ( "0" x 118 ) ) } qw/ 011111 011110 111110 /;

sub _croak { croak("Couldn't parse '$_[0]' as valid Decimal128") }

sub _erange { croak("Value '$_[0]' is out of range for Decimal128") }

sub _erounding { croak("Value '$_[0]' can't be rounded to Decimal128") }

sub _string_to_bid {
    my $s = shift;

    # Check special values
    return $bidNaN    if $s =~ /\A -? NaN \z/ix;
    return $bidPosInf if $s =~ /\A \+?Inf(?:inity)? \z/ix;
    return $bidNegInf if $s =~ /\A -Inf(?:inity)? \z/ix;

    # Parse string
    my ( $sign, $mant, $exp ) = $s =~ /\A $decimal_re \z/x;
    $sign = "" unless defined $sign;
    $exp = 0 unless defined $exp && length($exp);
    $exp =~ s{^e}{}i;

    # Throw error if unparseable

lib/BSON/Double.pm  view on Meta::CPAN

package BSON::Double;
# ABSTRACT: BSON type wrapper for Double

use version;
our $VERSION = 'v1.12.2';

use Carp;

#pod =attr value
#pod
#pod A numeric scalar (or the special strings "Inf", "-Inf" or "NaN").  This
#pod will be coerced to Perl's numeric type.  The default is 0.0.
#pod
#pod =cut

use Moo;

has 'value' => (
    is => 'ro'
);

use namespace::clean -except => 'meta';

use constant {
    nInf  => unpack("d<",pack("H*","000000000000f0ff")),
    pInf  => unpack("d<",pack("H*","000000000000f07f")),
    NaN   => unpack("d<",pack("H*","000000000000f8ff")),
};

sub BUILD {
    my $self = shift;
    # coerce to NV internally
    $self->{value} = defined( $self->{value} ) ? $self->{value} / 1.0 : 0.0;
}

#pod =method TO_JSON
#pod
#pod Returns a double.
#pod
#pod If the C<BSON_EXTJSON> environment variable is true and the
#pod C<BSON_EXTJSON_RELAXED> environment variable is false, returns a hashref
#pod compatible with
#pod MongoDB's L<extended JSON|https://github.com/mongodb/specifications/blob/master/source/extended-json.rst>
#pod format, which represents it as a document as follows:
#pod
#pod     {"$numberDouble" : "42.0"}
#pod
#pod If C<BSON_EXTJSON> is false and the value is 'Inf', '-Inf' or 'NaN'
#pod (which are illegal in regular JSON), then an exception is thrown.
#pod
#pod =cut

my $use_win32_specials = ($^O eq 'MSWin32' && $] lt "5.022");

my $win32_specials = qr/-?1.\#IN[DF]/i;
my $unix_specials = qr/-?(?:inf|nan)/i;
my $illegal = $use_win32_specials ? qr/^$win32_specials/ : qr/^$unix_specials/;

lib/BSON/Double.pm  view on Meta::CPAN


sub TO_JSON {
    my $copy = "$_[0]->{value}"; # avoid changing value to PVNV

    if ($ENV{BSON_EXTJSON} && $ENV{BSON_EXTJSON_RELAXED}) {

        return { '$numberDouble' => 'Infinity' }
            if $copy =~ $is_inf;
        return { '$numberDouble' => '-Infinity' }
            if $copy =~ $is_ninf;
        return { '$numberDouble' => 'NaN' }
            if $copy =~ $is_nan;
    }

    if ($ENV{BSON_EXTJSON} && !$ENV{BSON_EXTJSON_RELAXED}) {

        return { '$numberDouble' => 'Infinity' }
            if $copy =~ $is_inf;
        return { '$numberDouble' => '-Infinity' }
            if $copy =~ $is_ninf;
        return { '$numberDouble' => 'NaN' }
            if $copy =~ $is_nan;
        my $value = $_[0]->{value}/1.0;
        return { '$numberDouble' => "$value" };
    }

    croak( "The value '$copy' is illegal in JSON" )
        if $copy =~ $illegal;

    return $_[0]->{value}/1.0;
}

lib/BSON/Double.pm  view on Meta::CPAN


=head1 DESCRIPTION

This module provides a BSON type wrapper for a numeric value that
would be represented in BSON as a double.

=head1 ATTRIBUTES

=head2 value

A numeric scalar (or the special strings "Inf", "-Inf" or "NaN").  This
will be coerced to Perl's numeric type.  The default is 0.0.

=head1 METHODS

=head2 TO_JSON

Returns a double.

If the C<BSON_EXTJSON> environment variable is true and the
C<BSON_EXTJSON_RELAXED> environment variable is false, returns a hashref
compatible with
MongoDB's L<extended JSON|https://github.com/mongodb/specifications/blob/master/source/extended-json.rst>
format, which represents it as a document as follows:

    {"$numberDouble" : "42.0"}

If C<BSON_EXTJSON> is false and the value is 'Inf', '-Inf' or 'NaN'
(which are illegal in regular JSON), then an exception is thrown.

=for Pod::Coverage BUILD nInf pInf NaN

=head1 INFINITY AND NAN

Some Perls may not support converting "Inf" or "NaN" strings to their
double equivalent.  They are available as functions from the L<POSIX>
module, but as a lighter alternative to POSIX, the following functions are
available:

=over 4

=item *

BSON::Double::pInf() – positive infinity

=item *

BSON::Double::nInf() – negative infinity

=item *

BSON::Double::NaN() – not-a-number

=back

=head1 OVERLOADING

The numification operator, C<0+> is overloaded to return the C<value>,
the full "minimal set" of overloaded operations is provided (per L<overload>
documentation) and fallback overloading is enabled.

=head1 AUTHORS

lib/BSON/PP.pm  view on Meta::CPAN

# Max integer sizes
my $max_int32 = 2147483647;
my $min_int32 = -2147483648;
my $max_int64 =
  HAS_INT64 ? 9223372036854775807 : Math::BigInt->new("9223372036854775807");
my $min_int64 =
  HAS_INT64 ? -9223372036854775808 : Math::BigInt->new("-9223372036854775808");

#<<<
my $int_re     = qr/^(?:(?:[+-]?)(?:[0123456789]+))$/;
my $doub_re    = qr/^(?:(?i)(?:NaN|-?Inf(?:inity)?)|(?:[+-]?)(?:(?=[0123456789]|[.])(?:[0123456789]*)(?:(?:[.])(?:[0123456789]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[0123456789]+))|))$/;
#>>>

my $bools_re = qr/::(?:Boolean|_Bool|Bool)\z/;

use constant {

    BSON_TYPE_NAME => "CZ*",
    BSON_DOUBLE => "d<",
    BSON_STRING => "V/Z*",
    BSON_BOOLEAN => "C",

t/mapping/decimal128.t  view on Meta::CPAN


# test overloading
is( bson_decimal128("3.14159"), "3.14159", "overloading correct" );

# BSON::Decimal128 -> BSON::Decimal128
$hash = decode( encode( { A => bson_decimal128("3.14159") } ) );
is( ref( $hash->{A} ), 'BSON::Decimal128', "BSON::Decimal128->BSON::Decimal128" );
is( $hash->{A}->value, "3.14159", "value correct" );

# test special decimal128s
for my $s ( qw/Infinity -Infinity NaN/ ) {
    $hash = decode( encode( { A => bson_decimal128($s) } ) );
    is( $hash->{A}->value, $s, "$s value correct" );
}

# to JSON
is( to_myjson( { a => bson_decimal128("0.0") } ),
    q[{"a":"0.0"}], 'bson_decimal128(0.0)' );
is( to_myjson( { a => bson_decimal128("42") } ),
    q[{"a":"42"}], 'bson_decimal128(42)' );
is( to_myjson( { a => bson_decimal128("0.1") } ),

t/mapping/double.t  view on Meta::CPAN


# BSON::Double -> BSON::Double
$hash = decode( encode( { A => bson_double(3.14159) } ), wrap_numbers => 1 );
is( ref( $hash->{A} ), 'BSON::Double', "BSON::Double->BSON::Double" );
packed_is( FLOAT, $hash->{A}->value, 3.14159, "value correct" );

# test special doubles
my %special = (
    "Inf"  => BSON::Double::pInf(),
    "-Inf" => BSON::Double::nInf(),
    "NaN"  => BSON::Double::NaN(),
);

for my $s ( qw/Inf -Inf NaN/ ) {
    $hash = decode( encode( { A => $special{$s} } ) );
    is( sv_type( $hash->{A} ), 'PVNV', "$s as double->double" );
    packed_is( FLOAT, $hash->{A}, $special{$s}, "value correct" );
}

for my $s ( qw/Inf -Inf NaN/ ) {
    $hash = decode( encode( { A => $special{$s} } ), wrap_numbers => 1 );
    is( ref( $hash->{A} ), 'BSON::Double', "$s as double->BSON::Double" )
        or diag explain $hash;
    packed_is( FLOAT, $hash->{A}, $special{$s}, "value correct" );
}

# test special BSON::Double
for my $s ( qw/Inf -Inf NaN/ ) {
    $hash = decode( encode( { A => bson_double($special{$s}) } ) );
    is( sv_type( $hash->{A} ), 'PVNV', "$s as BSON::Double->BSON::Double" );
    packed_is( FLOAT, $hash->{A}, $special{$s}, "value correct" );
}

for my $s ( qw/Inf -Inf NaN/ ) {
    $hash = decode( encode( { A => bson_double($special{$s}) } ), wrap_numbers => 1 );
    is( ref( $hash->{A} ), 'BSON::Double', "$s as BSON::Double->BSON::Double" )
        or diag explain $hash;
    packed_is( FLOAT, $hash->{A}, $special{$s}, "value correct" );
}

# to JSON

# Depending on the JSON parser (and version), .0 might get encoded in various
# lossy ways, so we check with a regex for any of the various things we might see



( run in 0.517 second using v1.01-cache-2.11-cpan-fd5d4e115d8 )