From 712b8eec3d90f7e61908cb32c4433ee38a5f1848 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Wed, 1 Sep 2010 11:22:43 +0900
Subject: [PATCH 01/43] added pp version

---
 perl/lib/Data/MessagePack/PP.pm | 556 ++++++++++++++++++++++++++++++++
 1 file changed, 556 insertions(+)
 create mode 100644 perl/lib/Data/MessagePack/PP.pm

diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
new file mode 100644
index 00000000..f4f1060f
--- /dev/null
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -0,0 +1,556 @@
+package Data::MessagePack::PP;
+
+use 5.008000;
+use strict;
+use B ();
+use Scalar::Util qw( blessed );
+use Carp ();
+
+our $VERSION = '0.03';
+
+
+# copied from Data::MessagePack
+our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };
+our $false = do { bless \(my $dummy = 0), "Data::MessagePack::Boolean" };
+
+sub true  () { $true  }
+sub false () { $false }
+
+our $PreferInteger;
+
+# See also
+# http://redmine.msgpack.org/projects/msgpack/wiki/FormatSpec
+# http://cpansearch.perl.org/src/YAPPO/Data-Model-0.00006/lib/Data/Model/Driver/Memcached.pm
+# http://frox25.no-ip.org/~mtve/wiki/MessagePack.html : reference to using CORE::pack, CORE::unpack
+
+
+BEGIN {
+    # for pack and unpack compatibility
+    if ( $] < 5.010 ) {
+        require Data::Float;
+        *pack_double = sub {
+            my $float_hex = Data::Float::float_hex( $_[0] );
+            my ( $sign, $sgnf, $exp ) = $float_hex =~ /^([-+])0x1\.([a-z0-9]+)p([-+][\d]+)$/;
+            my @bits;
+
+            $sign = $sign eq '-' ? 1 : 0;
+            $exp  = sprintf( '%011b', 1023 + $exp );
+
+            my $bit  = $sign . $exp . join( '', map { unpack('B4', pack('H', $_) ) } split //, $sgnf );
+
+            while ( $bit =~ /(.{8})/g ) {
+                push @bits, $1;
+            }
+
+             return pack( 'C*', 0xcb, map { unpack( 'C', pack("B*", $_ ) ) } @bits );
+        };
+        *unpack_double = sub {
+            my $bits = join('', map { sprintf('%08b', $_) } unpack( 'C*', substr( $_[0], $_[1], 8 ) ) );
+            my $sign = substr($bits, 0, 1) ? '-' : '+';
+            my $sgnf = substr($bits, 12, 52);
+            my $exp  = substr($bits, 1, 11);
+            $bits = '';
+            while ( $sgnf =~ /(.{4})/g ) {
+                $bits .= unpack('H',pack('B4', $1));
+            }
+            $exp = ((unpack("C*",(pack("B8", (substr('00000'.$exp,0,8) )))) <<8 )
+                    + unpack("C*",(pack("B8", (substr('00000'.$exp,8,8) ))))) - 1023;
+            return Data::Float::hex_float( $sign . '0x1.' . $bits . 'p' . $exp ) + 0.0;
+        };
+        *unpack_float  = sub { Carp::croak("unpack_float is disable in less than Perl 5.10"); };
+        *unpack_int16  = sub {
+            my $v = unpack 'n', substr( $_[0], $_[1], 2 );
+            return $v ? $v - 0x10000 : 0;
+        };
+        *unpack_int32  = sub {
+            my $v = unpack 'N', substr( $_[0], $_[1], 4 );
+            return $v ? -(~$v + 1) : $v;
+        };
+        *unpack_int64  = sub { Carp::croak("unpack_int64 is disable in less than Perl 5.10"); };
+    }
+    else {
+        *pack_double   = sub { return pack 'Cd>', 0xcb, $_[0]; };
+        *unpack_double = sub { return unpack( 'd>', substr( $_[0], $_[1], 8 ) ); };
+        *unpack_float  = sub { return unpack( 'f>', substr( $_[0], $_[1], 4 ) ); };
+        *unpack_int16  = sub { return unpack 'n!',  substr( $_[0], $_[1], 2 ); };
+        *unpack_int32  = sub { return unpack 'N!',  substr( $_[0], $_[1], 4 ); };
+        *unpack_int64  = sub { return unpack 'Q>',  substr( $_[0], $_[1], 8 ); };
+    }
+    # for 5.8 etc.
+    unless ( defined &utf8::is_utf8 ) {
+       require Encode;
+       *utf8::is_utf8 = *Encode::is_utf8;
+    }
+}
+
+
+#
+# PACK
+#
+
+{
+    my $max_depth;
+
+sub pack {
+    Carp::croak('Usage: Data::MessagePack->pack($dat [,$max_depth])') if @_ < 2;
+    $max_depth = defined $_[2] ? $_[2] : 512; # init
+    return _pack( $_[1] );
+}
+
+
+sub _pack {
+    my ( $value ) = @_;
+
+    return pack( 'C', 0xc0 ) if ( not defined $value );
+
+    my $b_obj = B::svref_2object( ref $value ? $value : \$value );
+
+    if ( $b_obj->isa('B::AV') ) {
+        my $num = @$value;
+        my $header = 
+              $num < 16          ? pack( 'C',  0x90 + $num )
+            : $num < 2 ** 16 - 1 ? pack( 'Cn', 0xdc,  $num )
+            : $num < 2 ** 32 - 1 ? pack( 'CN', 0xdd,  $num )
+            : die "" # don't arrivie here
+        ;
+        if ( --$max_depth <= 0 ) {
+            Carp::croak("perl structure exceeds maximum nesting level (max_depth set too low?)");
+        }
+        return join( '', $header, map { _pack( $_ ) } @$value );
+    }
+
+    elsif ( $b_obj->isa('B::HV') ) {
+        my $num = keys %$value;
+        my $header = 
+              $num < 16          ? pack( 'C',  0x80 + $num )
+            : $num < 2 ** 16 - 1 ? pack( 'Cn', 0xde,  $num )
+            : $num < 2 ** 32 - 1 ? pack( 'CN', 0xdf,  $num )
+            : die "" # don't arrivie here
+        ;
+        if ( --$max_depth <= 0 ) {
+            Carp::croak("perl structure exceeds maximum nesting level (max_depth set too low?)");
+        }
+        return join( '', $header, map { _pack( $_ ) } %$value );
+    }
+
+    elsif ( blessed( $value ) eq 'Data::MessagePack::Boolean' ) {
+        return  pack( 'C', $$value ? 0xc3 : 0xc2 );
+    }
+
+    my $flags = $b_obj->FLAGS;
+
+    if ( $flags & ( B::SVf_IOK | B::SVp_IOK ) ) {
+
+        if ($value >= 0) {
+            return    $value <= 127 ?    pack 'C',        $value
+                    : $value < 2 ** 8 ?  pack 'CC', 0xcc, $value
+                    : $value < 2 ** 16 ? pack 'Cn', 0xcd, $value
+                    : $value < 2 ** 32 ? pack 'CN', 0xce, $value
+                    : pack 'CQ>', 0xcf, $value;
+        }
+        else {
+            return    -$value <= 32 ?      pack 'C',        $value
+                    : -$value <= 2 **  7 ? pack 'Cc', 0xd0, $value
+                    : -$value <= 2 ** 15 ? pack 'Cn', 0xd1, $value
+                    : -$value <= 2 ** 31 ? pack 'CN', 0xd2, $value
+                    : pack 'Cq>', 0xd3, $value;
+        }
+
+    }
+
+    elsif ( $flags & B::SVf_POK ) { # raw / check needs before dboule
+
+        if ( $PreferInteger ) {
+            if ( $value =~ /^-?[0-9]+$/ ) { # ok?
+                my $value2 = 0 + $value;
+                if (  0 + $value != B::svref_2object( \$value2 )->int_value ) {
+                    local $PreferInteger;      # avoid for PV => NV
+                    return _pack( "$value" );
+                }
+                return _pack( $value + 0 );
+            }
+        }
+
+        utf8::encode( $value ) if utf8::is_utf8( $value );
+
+        my $num = length $value;
+        my $header = 
+              $num < 32          ? pack( 'C',  0xa0 + $num )
+            : $num < 2 ** 16 - 1 ? pack( 'Cn', 0xda, $num )
+            : $num < 2 ** 32 - 1 ? pack( 'CN', 0xdb, $num )
+            : die "" # don't arrivie here
+        ;
+
+        return $header . $value;
+
+    }
+
+    elsif ( $flags & ( B::SVf_NOK | B::SVp_NOK ) ) { # double only
+        return pack_double( $value );
+    }
+
+    else {
+        die "???";
+    }
+
+}
+
+} # PACK
+
+
+#
+# UNPACK
+#
+
+{
+    my $p; # position variables for speed.
+
+sub unpack {
+    $p = 0; # init
+    _unpack( $_[1] );
+}
+
+
+sub _unpack {
+    my ( $value ) = @_;
+    my $byte = unpack( 'C', substr( $value, $p++, 1 ) ); # get header
+
+    die "invalid data" unless defined $byte;
+
+    if ( ( $byte >= 0x90 and $byte <= 0x9f ) or $byte == 0xdc or $byte == 0xdd ) {
+        my $num;
+        if ( $byte == 0xdc ) { # array 16
+            $num = unpack 'n', substr( $value, $p, 2 );
+            $p += 2;
+        }
+        elsif ( $byte == 0xdd ) { # array 32
+            $num = unpack 'N', substr( $value, $p, 4 );
+            $p += 4;
+        }
+        else { # fix array
+            $num = $byte & ~0x90;
+        }
+        my @array;
+        push @array, _unpack( $value ) while $num-- > 0;
+        return \@array;
+    }
+
+    elsif ( ( $byte >= 0x80 and $byte <= 0x8f ) or $byte == 0xde or $byte == 0xdf ) {
+        my $num;
+        if ( $byte == 0xde ) { # map 16
+            $num = unpack 'n', substr( $value, $p, 2 );
+            $p += 2;
+        }
+        elsif ( $byte == 0xdf ) { # map 32
+            $num = unpack 'N', substr( $value, $p, 4 );
+            $p += 4;
+        }
+        else { # fix map
+            $num = $byte & ~0x80;
+        }
+        my %map;
+        for ( 0 .. $num - 1 ) {
+            my $key = _unpack( $value );
+            my $val = _unpack( $value );
+            $map{ $key } = $val;
+        }
+        return \%map;
+    }
+
+    elsif ( $byte >= 0x00 and $byte <= 0x7f ) { # positive fixnum
+        return $byte;
+    }
+    elsif ( $byte == 0xcc ) { # uint8
+        unpack( 'C', substr( $value, $p++, 1 ) );
+    }
+    elsif ( $byte == 0xcd ) { # uint16
+        $p += 2;
+        return unpack 'n', substr( $value, $p - 2, 2 );
+    }
+    elsif ( $byte == 0xce ) { # unit32
+        $p += 4;
+        return unpack 'N', substr( $value, $p - 4, 4 );
+    }
+    elsif ( $byte == 0xcf ) { # unit64
+        $p += 8;
+        return unpack 'Q>', substr( $value, $p - 8, 8 );
+    }
+    elsif ( $byte == 0xd3 ) { # int64
+        $p += 8;
+        return unpack_int64( $value, $p - 8 );
+        return unpack 'q>',  substr( $value, $p - 8, 8 );
+    }
+    elsif ( $byte == 0xd2 ) { # int32
+        $p += 4;
+        return unpack_int32( $value, $p - 4 );
+    }
+    elsif ( $byte == 0xd1 ) { # int16
+        $p += 2;
+        return unpack_int16( $value, $p - 2 );
+    }
+    elsif ( $byte == 0xd0 ) { # int8
+        return unpack 'c',  substr( $value, $p++, 1 ); # c / C
+    }
+    elsif ( $byte >= 0xe0 and $byte <= 0xff ) { # negative fixnum
+        return $byte - 256;
+    }
+
+    elsif ( ( $byte >= 0xa0 and $byte <= 0xbf ) or $byte == 0xda or $byte == 0xdb ) { # raw
+        my $num;
+        if ( $byte == 0xda ) {
+            $num = unpack 'n', substr( $value, $p, 2 );
+            $p += 2 + $num;
+        }
+        elsif ( $byte == 0xdb ) {
+            $num = unpack 'N', substr( $value, $p, 4 );
+            $p += 4 + $num;
+        }
+        else { # fix raw
+            $num = $byte & ~0xa0;
+            $p += $num;
+        }
+        return substr( $value, $p - $num, $num );
+    }
+
+    elsif ( $byte == 0xc0 ) { # nil
+        return undef;
+    }
+    elsif ( $byte == 0xc2 ) { # boolean
+        return false;
+    }
+    elsif ( $byte == 0xc3 ) { # boolean
+        return true;
+    }
+
+    elsif ( $byte == 0xcb ) { # double
+        $p += 8;
+        return unpack_double( $value, $p - 8 );
+    }
+
+    elsif ( $byte == 0xca ) { # float
+        $p += 4;
+        return unpack_float( $value, $p - 4 );
+    }
+
+    else {
+        die "???";
+    }
+
+}
+
+
+} # UNPACK
+
+
+#
+# Data::MessagePack::Unpacker
+#
+
+package Data::MessagePack::PP::Unpacker;
+
+use strict;
+
+sub new {
+    bless { stack => [] }, shift;
+}
+
+
+sub execute_limit {
+    execute( @_ );
+}
+
+
+{
+    my $p;
+    #my $r; # remained data.
+
+sub execute {
+    my ( $self, $data, $offset, $limit ) = @_;
+    #my $value = ( defined $self->{ remain } ? $self->{ remain } : '' ) . substr( $data, $offset, $limit );
+    my $value = substr( $data, $offset, $limit ? $limit : length $data );
+    my $len   = length $value;
+
+    $p = 0;
+    #$r = 0;
+
+    while ( $len > $p ) {
+        _count( $self, $value ) or last;
+
+        if ( @{ $self->{stack} } > 0 ) {
+            $self->{stack}->[-1];
+            pop @{ $self->{stack} } if --$self->{stack}->[-1] == 0;
+        }
+    }
+
+    if ( $len == $p ) {
+        $self->{ data } .= substr( $value, 0, $p );
+        $self->{ remain } = undef;
+    }
+    else { # I thought this feature is needed. but XS version can't do so
+        #$self->{ remain } = substr( $value, 0, $p + $r );
+    }
+
+    return $p;
+}
+
+
+sub _count {
+    my ( $self, $value ) = @_;
+    my $byte = unpack( 'C', substr( $value, $p++, 1 ) ); # get header
+
+    if ( ( $byte >= 0x90 and $byte <= 0x9f ) or $byte == 0xdc or $byte == 0xdd ) {
+        my $num;
+        if ( $byte == 0xdc ) { # array 16
+            # I thought this feature is needed. but XS version can't do so. So commented out.
+            #my $len = length substr( $value, $p, 2 );
+            #if ( $len != 2 ) {
+            #    $r = $len;
+            #    return 0;
+            #}
+            $num = unpack 'n', substr( $value, $p, 2 );
+            $p += 2;
+        }
+        elsif ( $byte == 0xdd ) { # array 32
+            $num = unpack 'N', substr( $value, $p, 4 );
+            $p += 4;
+        }
+        else { # fix array
+            $num = $byte & ~0x90;
+        }
+
+        push @{ $self->{stack} }, $num + 1;
+
+        return 1;
+    }
+
+    elsif ( ( $byte >= 0x80 and $byte <= 0x8f ) or $byte == 0xde or $byte == 0xdf ) {
+        my $num;
+        if ( $byte == 0xde ) { # map 16
+            $num = unpack 'n', substr( $value, $p, 2 );
+            $p += 2;
+        }
+        elsif ( $byte == 0xdf ) { # map 32
+            $num = unpack 'N', substr( $value, $p, 4 );
+            $p += 4;
+        }
+        else { # fix map
+            $num = $byte & ~0x80;
+        }
+
+        push @{ $self->{stack} }, $num * 2 + 1; # a pair
+
+        return 1;
+    }
+
+    elsif ( $byte == 0xc0 or $byte == 0xc2 or $byte == 0xc3 ) { # nil, false, true
+        return 1;
+    }
+
+    elsif ( $byte >= 0x00 and $byte <= 0x7f ) { # positive fixnum
+        return 1;
+    }
+
+    elsif ( $byte >= 0xcc and $byte <= 0xcf ) { # uint
+        $p += $byte == 0xcc ? 1
+            : $byte == 0xcd ? 2
+            : $byte == 0xce ? 4
+            : $byte == 0xcf ? 8
+            : die;
+        return 1;
+    }
+
+    elsif ( $byte >= 0xd0 and $byte <= 0xd3 ) { # int
+        $p += $byte == 0xd0 ? 1
+            : $byte == 0xd1 ? 2
+            : $byte == 0xd2 ? 4
+            : $byte == 0xd3 ? 8
+            : die;
+        return 1;
+    }
+
+    elsif ( $byte >= 0xe0 and $byte <= 0xff ) { # negative fixnum
+        return 1;
+    }
+
+    elsif ( $byte >= 0xca and $byte <= 0xcb ) { # float, double
+        $p += $byte == 0xca ? 4 : 8;
+        return 1;
+    }
+
+    elsif ( ( $byte >= 0xa0 and $byte <= 0xbf ) or $byte == 0xda or $byte == 0xdb ) {
+        my $num;
+        if ( $byte == 0xda ) {
+            $num = unpack 'n', substr( $value, $p, 2 );
+            $p += 2;
+        }
+        elsif ( $byte == 0xdb ) {
+            $num = unpack 'N', substr( $value, $p, 4 );
+            $p += 4;
+        }
+        else { # fix raw
+            $num = $byte & ~0xa0;
+        }
+        $p += $num;
+        return 1;
+    }
+
+    else {
+        die "???";
+    }
+
+    return 0;
+}
+
+} # execute
+
+
+sub data {
+    my $data = Data::MessagePack->unpack( $_[0]->{ data } );
+    $_[0]->reset;
+    return $data;
+}
+
+
+sub is_finished {
+    my ( $self ) = @_;
+    ( scalar( @{ $self->{stack} } ) or defined $self->{ remain } ) ? 0 : 1;
+}
+
+
+sub reset {
+    $_[0]->{ stack }  = [];
+    $_[0]->{ data }   = undef;
+    $_[0]->{ remain } = undef;
+}
+
+1;
+__END__
+
+=pod
+
+=head1 NAME
+
+Data::MessagePack::PP - the pure perl version of Data::MessagePack
+
+=head1 LIMITATION
+
+Currently this module works completely in Perl 5.10 or later.
+In Perl 5.8.x, it requires L<Data::Float> and cannot unpack int64 and float (pack int64 too).
+
+
+=head1 SEE ALSO
+
+L<Data::MessagePack>,
+L<http://frox25.no-ip.org/~mtve/wiki/MessagePack.html>,
+L<Data::Float>
+
+=head1 AUTHOR
+
+makamaka
+
+=head1 COPYRIGHT AND LICENSE
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself. 
+
+=cut

From a0705a6c67e852154e92bb16876ac9e950a8f044 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Wed, 1 Sep 2010 11:59:01 +0900
Subject: [PATCH 02/43] added PP backend switch into Data::MessagePack

---
 perl/Changes                    |  6 ++++++
 perl/lib/Data/MessagePack.pm    | 15 +++++++++++++--
 perl/lib/Data/MessagePack/PP.pm | 33 +++++++++++++++------------------
 3 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/perl/Changes b/perl/Changes
index 189990a8..a8a4298c 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,9 @@
+
+0.1x
+
+    - added PP version.
+      (makamaka)
+
 0.15
 
     - better argument validation.
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index 276353a2..a3f8264e 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -1,7 +1,6 @@
 package Data::MessagePack;
 use strict;
 use warnings;
-use XSLoader;
 use 5.008001;
 
 our $VERSION = '0.15';
@@ -12,7 +11,19 @@ our $false = do { bless \(my $dummy = 0), "Data::MessagePack::Boolean" };
 sub true  () { $true  }
 sub false () { $false }
 
-XSLoader::load(__PACKAGE__, $VERSION);
+if ( !__PACKAGE__->can('pack') ) { # this idea comes from Text::Xslate
+    if ( $ENV{ PERL_DATA_MESSAGEPACK } !~ /\b pp \b/xms ) {
+        eval {
+            require XSLoader;
+            XSLoader::load(__PACKAGE__, $VERSION);
+        };
+        die $@ if $@ && $ENV{ PERL_DATA_MESSAGEPACK } =~ /\b xs \b/xms; # force XS
+    }
+    if ( !__PACKAGE__->can('pack') ) {
+        print "PP\n";
+        require 'Data/MessagePack/PP.pm';
+    }
+}
 
 1;
 __END__
diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index f4f1060f..ecb97b46 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -2,21 +2,9 @@ package Data::MessagePack::PP;
 
 use 5.008000;
 use strict;
-use B ();
-use Scalar::Util qw( blessed );
 use Carp ();
 
-our $VERSION = '0.03';
-
-
-# copied from Data::MessagePack
-our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };
-our $false = do { bless \(my $dummy = 0), "Data::MessagePack::Boolean" };
-
-sub true  () { $true  }
-sub false () { $false }
-
-our $PreferInteger;
+our $VERSION = '0.15';
 
 # See also
 # http://redmine.msgpack.org/projects/msgpack/wiki/FormatSpec
@@ -24,6 +12,13 @@ our $PreferInteger;
 # http://frox25.no-ip.org/~mtve/wiki/MessagePack.html : reference to using CORE::pack, CORE::unpack
 
 
+package
+    Data::MessagePack;
+
+use Scalar::Util qw( blessed );
+use strict;
+use B ();
+
 BEGIN {
     # for pack and unpack compatibility
     if ( $] < 5.010 ) {
@@ -160,11 +155,11 @@ sub _pack {
 
     elsif ( $flags & B::SVf_POK ) { # raw / check needs before dboule
 
-        if ( $PreferInteger ) {
+        if ( $Data::MessagePack::PreferInteger ) {
             if ( $value =~ /^-?[0-9]+$/ ) { # ok?
                 my $value2 = 0 + $value;
                 if (  0 + $value != B::svref_2object( \$value2 )->int_value ) {
-                    local $PreferInteger;      # avoid for PV => NV
+                    local $Data::MessagePack::PreferInteger; # avoid for PV => NV
                     return _pack( "$value" );
                 }
                 return _pack( $value + 0 );
@@ -346,7 +341,8 @@ sub _unpack {
 # Data::MessagePack::Unpacker
 #
 
-package Data::MessagePack::PP::Unpacker;
+package
+    Data::MessagePack::Unpacker;
 
 use strict;
 
@@ -530,7 +526,7 @@ __END__
 
 =head1 NAME
 
-Data::MessagePack::PP - the pure perl version of Data::MessagePack
+Data::MessagePack::PP - Pure Perl version of Data::MessagePack
 
 =head1 LIMITATION
 
@@ -540,9 +536,10 @@ In Perl 5.8.x, it requires L<Data::Float> and cannot unpack int64 and float (pac
 
 =head1 SEE ALSO
 
+L<http://msgpack.sourceforge.jp/>,
 L<Data::MessagePack>,
+L<Data::Float>,
 L<http://frox25.no-ip.org/~mtve/wiki/MessagePack.html>,
-L<Data::Float>
 
 =head1 AUTHOR
 

From af83a624743735e1f4404bcd3942e98eee36ce2a Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Wed, 1 Sep 2010 16:04:25 +0900
Subject: [PATCH 03/43] modified some codes for test warnings

---
 perl/lib/Data/MessagePack.pm    |  5 ++-
 perl/lib/Data/MessagePack/PP.pm | 74 +++++++++++++++++----------------
 2 files changed, 41 insertions(+), 38 deletions(-)

diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index a3f8264e..f8d16254 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -12,12 +12,13 @@ sub true  () { $true  }
 sub false () { $false }
 
 if ( !__PACKAGE__->can('pack') ) { # this idea comes from Text::Xslate
-    if ( $ENV{ PERL_DATA_MESSAGEPACK } !~ /\b pp \b/xms ) {
+    my $backend = $ENV{ PERL_DATA_MESSAGEPACK } || '';
+    if ( $backend !~ /\b pp \b/xms ) {
         eval {
             require XSLoader;
             XSLoader::load(__PACKAGE__, $VERSION);
         };
-        die $@ if $@ && $ENV{ PERL_DATA_MESSAGEPACK } =~ /\b xs \b/xms; # force XS
+        die $@ if $@ && $backend =~ /\b xs \b/xms; # force XS
     }
     if ( !__PACKAGE__->can('pack') ) {
         print "PP\n";
diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index ecb97b46..1e05bab0 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -84,6 +84,8 @@ BEGIN {
 #
 
 {
+    no warnings 'recursion';
+
     my $max_depth;
 
 sub pack {
@@ -96,16 +98,16 @@ sub pack {
 sub _pack {
     my ( $value ) = @_;
 
-    return pack( 'C', 0xc0 ) if ( not defined $value );
+    return CORE::pack( 'C', 0xc0 ) if ( not defined $value );
 
     my $b_obj = B::svref_2object( ref $value ? $value : \$value );
 
     if ( $b_obj->isa('B::AV') ) {
         my $num = @$value;
         my $header = 
-              $num < 16          ? pack( 'C',  0x90 + $num )
-            : $num < 2 ** 16 - 1 ? pack( 'Cn', 0xdc,  $num )
-            : $num < 2 ** 32 - 1 ? pack( 'CN', 0xdd,  $num )
+              $num < 16          ? CORE::pack( 'C',  0x90 + $num )
+            : $num < 2 ** 16 - 1 ? CORE::pack( 'Cn', 0xdc,  $num )
+            : $num < 2 ** 32 - 1 ? CORE::pack( 'CN', 0xdd,  $num )
             : die "" # don't arrivie here
         ;
         if ( --$max_depth <= 0 ) {
@@ -117,9 +119,9 @@ sub _pack {
     elsif ( $b_obj->isa('B::HV') ) {
         my $num = keys %$value;
         my $header = 
-              $num < 16          ? pack( 'C',  0x80 + $num )
-            : $num < 2 ** 16 - 1 ? pack( 'Cn', 0xde,  $num )
-            : $num < 2 ** 32 - 1 ? pack( 'CN', 0xdf,  $num )
+              $num < 16          ? CORE::pack( 'C',  0x80 + $num )
+            : $num < 2 ** 16 - 1 ? CORE::pack( 'Cn', 0xde,  $num )
+            : $num < 2 ** 32 - 1 ? CORE::pack( 'CN', 0xdf,  $num )
             : die "" # don't arrivie here
         ;
         if ( --$max_depth <= 0 ) {
@@ -128,8 +130,8 @@ sub _pack {
         return join( '', $header, map { _pack( $_ ) } %$value );
     }
 
-    elsif ( blessed( $value ) eq 'Data::MessagePack::Boolean' ) {
-        return  pack( 'C', $$value ? 0xc3 : 0xc2 );
+    elsif ( blessed( $value ) and blessed( $value ) eq 'Data::MessagePack::Boolean' ) {
+        return  CORE::pack( 'C', $$value ? 0xc3 : 0xc2 );
     }
 
     my $flags = $b_obj->FLAGS;
@@ -137,18 +139,18 @@ sub _pack {
     if ( $flags & ( B::SVf_IOK | B::SVp_IOK ) ) {
 
         if ($value >= 0) {
-            return    $value <= 127 ?    pack 'C',        $value
-                    : $value < 2 ** 8 ?  pack 'CC', 0xcc, $value
-                    : $value < 2 ** 16 ? pack 'Cn', 0xcd, $value
-                    : $value < 2 ** 32 ? pack 'CN', 0xce, $value
-                    : pack 'CQ>', 0xcf, $value;
+            return    $value <= 127 ?    CORE::pack 'C',        $value
+                    : $value < 2 ** 8 ?  CORE::pack 'CC', 0xcc, $value
+                    : $value < 2 ** 16 ? CORE::pack 'Cn', 0xcd, $value
+                    : $value < 2 ** 32 ? CORE::pack 'CN', 0xce, $value
+                    : CORE::pack 'CQ>', 0xcf, $value;
         }
         else {
-            return    -$value <= 32 ?      pack 'C',        $value
-                    : -$value <= 2 **  7 ? pack 'Cc', 0xd0, $value
-                    : -$value <= 2 ** 15 ? pack 'Cn', 0xd1, $value
-                    : -$value <= 2 ** 31 ? pack 'CN', 0xd2, $value
-                    : pack 'Cq>', 0xd3, $value;
+            return    -$value <= 32 ?      CORE::pack 'C', ($value & 255)
+                    : -$value <= 2 **  7 ? CORE::pack 'Cc', 0xd0, $value
+                    : -$value <= 2 ** 15 ? CORE::pack 'Cn', 0xd1, $value
+                    : -$value <= 2 ** 31 ? CORE::pack 'CN', 0xd2, $value
+                    : CORE::pack 'Cq>', 0xd3, $value;
         }
 
     }
@@ -170,9 +172,9 @@ sub _pack {
 
         my $num = length $value;
         my $header = 
-              $num < 32          ? pack( 'C',  0xa0 + $num )
-            : $num < 2 ** 16 - 1 ? pack( 'Cn', 0xda, $num )
-            : $num < 2 ** 32 - 1 ? pack( 'CN', 0xdb, $num )
+              $num < 32          ? CORE::pack( 'C',  0xa0 + $num )
+            : $num < 2 ** 16 - 1 ? CORE::pack( 'Cn', 0xda, $num )
+            : $num < 2 ** 32 - 1 ? CORE::pack( 'CN', 0xdb, $num )
             : die "" # don't arrivie here
         ;
 
@@ -198,6 +200,7 @@ sub _pack {
 #
 
 {
+
     my $p; # position variables for speed.
 
 sub unpack {
@@ -208,18 +211,18 @@ sub unpack {
 
 sub _unpack {
     my ( $value ) = @_;
-    my $byte = unpack( 'C', substr( $value, $p++, 1 ) ); # get header
+    my $byte = CORE::unpack( 'C', substr( $value, $p++, 1 ) ); # get header
 
     die "invalid data" unless defined $byte;
 
     if ( ( $byte >= 0x90 and $byte <= 0x9f ) or $byte == 0xdc or $byte == 0xdd ) {
         my $num;
         if ( $byte == 0xdc ) { # array 16
-            $num = unpack 'n', substr( $value, $p, 2 );
+            $num = CORE::unpack 'n', substr( $value, $p, 2 );
             $p += 2;
         }
         elsif ( $byte == 0xdd ) { # array 32
-            $num = unpack 'N', substr( $value, $p, 4 );
+            $num = CORE::unpack 'N', substr( $value, $p, 4 );
             $p += 4;
         }
         else { # fix array
@@ -233,11 +236,11 @@ sub _unpack {
     elsif ( ( $byte >= 0x80 and $byte <= 0x8f ) or $byte == 0xde or $byte == 0xdf ) {
         my $num;
         if ( $byte == 0xde ) { # map 16
-            $num = unpack 'n', substr( $value, $p, 2 );
+            $num = CORE::unpack 'n', substr( $value, $p, 2 );
             $p += 2;
         }
         elsif ( $byte == 0xdf ) { # map 32
-            $num = unpack 'N', substr( $value, $p, 4 );
+            $num = CORE::unpack 'N', substr( $value, $p, 4 );
             $p += 4;
         }
         else { # fix map
@@ -245,6 +248,7 @@ sub _unpack {
         }
         my %map;
         for ( 0 .. $num - 1 ) {
+            no warnings; # for undef key case
             my $key = _unpack( $value );
             my $val = _unpack( $value );
             $map{ $key } = $val;
@@ -256,24 +260,23 @@ sub _unpack {
         return $byte;
     }
     elsif ( $byte == 0xcc ) { # uint8
-        unpack( 'C', substr( $value, $p++, 1 ) );
+        CORE::unpack( 'C', substr( $value, $p++, 1 ) );
     }
     elsif ( $byte == 0xcd ) { # uint16
         $p += 2;
-        return unpack 'n', substr( $value, $p - 2, 2 );
+        return CORE::unpack 'n', substr( $value, $p - 2, 2 );
     }
     elsif ( $byte == 0xce ) { # unit32
         $p += 4;
-        return unpack 'N', substr( $value, $p - 4, 4 );
+        return CORE::unpack 'N', substr( $value, $p - 4, 4 );
     }
     elsif ( $byte == 0xcf ) { # unit64
         $p += 8;
-        return unpack 'Q>', substr( $value, $p - 8, 8 );
+        return CORE::unpack 'Q>', substr( $value, $p - 8, 8 );
     }
     elsif ( $byte == 0xd3 ) { # int64
         $p += 8;
         return unpack_int64( $value, $p - 8 );
-        return unpack 'q>',  substr( $value, $p - 8, 8 );
     }
     elsif ( $byte == 0xd2 ) { # int32
         $p += 4;
@@ -284,7 +287,7 @@ sub _unpack {
         return unpack_int16( $value, $p - 2 );
     }
     elsif ( $byte == 0xd0 ) { # int8
-        return unpack 'c',  substr( $value, $p++, 1 ); # c / C
+        return CORE::unpack 'c',  substr( $value, $p++, 1 ); # c / C
     }
     elsif ( $byte >= 0xe0 and $byte <= 0xff ) { # negative fixnum
         return $byte - 256;
@@ -293,11 +296,11 @@ sub _unpack {
     elsif ( ( $byte >= 0xa0 and $byte <= 0xbf ) or $byte == 0xda or $byte == 0xdb ) { # raw
         my $num;
         if ( $byte == 0xda ) {
-            $num = unpack 'n', substr( $value, $p, 2 );
+            $num = CORE::unpack 'n', substr( $value, $p, 2 );
             $p += 2 + $num;
         }
         elsif ( $byte == 0xdb ) {
-            $num = unpack 'N', substr( $value, $p, 4 );
+            $num = CORE::unpack 'N', substr( $value, $p, 4 );
             $p += 4 + $num;
         }
         else { # fix raw
@@ -373,7 +376,6 @@ sub execute {
         _count( $self, $value ) or last;
 
         if ( @{ $self->{stack} } > 0 ) {
-            $self->{stack}->[-1];
             pop @{ $self->{stack} } if --$self->{stack}->[-1] == 0;
         }
     }

From 8fc86ce7fa588657ce841a9cf30ea868c461c4e1 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Thu, 2 Sep 2010 14:33:59 +0900
Subject: [PATCH 04/43] removed commented out codes

---
 perl/lib/Data/MessagePack.pm    |  1 -
 perl/lib/Data/MessagePack/PP.pm | 12 ------------
 perl/{ => xs-src}/MessagePack.c |  0
 perl/{ => xs-src}/pack.c        |  0
 perl/{ => xs-src}/unpack.c      |  0
 5 files changed, 13 deletions(-)
 rename perl/{ => xs-src}/MessagePack.c (100%)
 rename perl/{ => xs-src}/pack.c (100%)
 rename perl/{ => xs-src}/unpack.c (100%)

diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index f8d16254..785f275d 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -21,7 +21,6 @@ if ( !__PACKAGE__->can('pack') ) { # this idea comes from Text::Xslate
         die $@ if $@ && $backend =~ /\b xs \b/xms; # force XS
     }
     if ( !__PACKAGE__->can('pack') ) {
-        print "PP\n";
         require 'Data/MessagePack/PP.pm';
     }
 }
diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index 1e05bab0..540b416d 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -361,16 +361,13 @@ sub execute_limit {
 
 {
     my $p;
-    #my $r; # remained data.
 
 sub execute {
     my ( $self, $data, $offset, $limit ) = @_;
-    #my $value = ( defined $self->{ remain } ? $self->{ remain } : '' ) . substr( $data, $offset, $limit );
     my $value = substr( $data, $offset, $limit ? $limit : length $data );
     my $len   = length $value;
 
     $p = 0;
-    #$r = 0;
 
     while ( $len > $p ) {
         _count( $self, $value ) or last;
@@ -384,9 +381,6 @@ sub execute {
         $self->{ data } .= substr( $value, 0, $p );
         $self->{ remain } = undef;
     }
-    else { # I thought this feature is needed. but XS version can't do so
-        #$self->{ remain } = substr( $value, 0, $p + $r );
-    }
 
     return $p;
 }
@@ -399,12 +393,6 @@ sub _count {
     if ( ( $byte >= 0x90 and $byte <= 0x9f ) or $byte == 0xdc or $byte == 0xdd ) {
         my $num;
         if ( $byte == 0xdc ) { # array 16
-            # I thought this feature is needed. but XS version can't do so. So commented out.
-            #my $len = length substr( $value, $p, 2 );
-            #if ( $len != 2 ) {
-            #    $r = $len;
-            #    return 0;
-            #}
             $num = unpack 'n', substr( $value, $p, 2 );
             $p += 2;
         }
diff --git a/perl/MessagePack.c b/perl/xs-src/MessagePack.c
similarity index 100%
rename from perl/MessagePack.c
rename to perl/xs-src/MessagePack.c
diff --git a/perl/pack.c b/perl/xs-src/pack.c
similarity index 100%
rename from perl/pack.c
rename to perl/xs-src/pack.c
diff --git a/perl/unpack.c b/perl/xs-src/unpack.c
similarity index 100%
rename from perl/unpack.c
rename to perl/xs-src/unpack.c

From 918dbd1926589a9b70f34037e35e98f3194302fc Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Thu, 2 Sep 2010 14:37:22 +0900
Subject: [PATCH 05/43] made Makefile.PL XS/PP configurable

---
 perl/Makefile.PL    | 69 +++++++++++++++++++++++++++++++++++++++------
 perl/t/00_compile.t |  2 +-
 2 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/perl/Makefile.PL b/perl/Makefile.PL
index e9f9618a..7440a46d 100644
--- a/perl/Makefile.PL
+++ b/perl/Makefile.PL
@@ -5,15 +5,29 @@ name 'Data-MessagePack';
 all_from 'lib/Data/MessagePack.pm';
 readme_from('lib/Data/MessagePack.pm');
 
-perl_version '5.008005';
+perl_version '5.008000';
 license 'perl';
-can_cc or die "This module requires a C compiler";
 
 tests 't/*.t';
 recursive_author_tests('xt');
-use_ppport 3.19;
 
-requires_c99(); # msgpack C library requires C99.
+my $use_xs = want_xs();
+
+if ( $] >= 5.008005 and $use_xs ) {
+    can_cc or die "This module requires a C compiler";
+    use_ppport 3.19;
+    requires_c99(); # msgpack C library requires C99.
+    cc_src_paths('xs-src');
+    if ($ENV{DEBUG}) {
+        cc_append_to_ccflags '-g';
+    }
+    # for author's test_pp
+    requires 'Data::Float' => 0 if ( $Module::Install::AUTHOR and $] < 5.010 );
+}
+else { # for Data::MessagePack::PP
+    print "configure PP version\n";
+    requires 'Data::Float' => 0 if ( $] < 5.010 );
+}
 
 clean_files qw{
     *.stackdump
@@ -23,10 +37,6 @@ clean_files qw{
     cover_db
 };
 
-if ($ENV{DEBUG}) {
-    cc_append_to_ccflags '-g';
-}
-
 # copy modules
 if ($Module::Install::AUTHOR && -d File::Spec->catfile('..', 'msgpack')) {
     mkdir 'msgpack' unless -d 'msgpack';
@@ -39,7 +49,50 @@ if ($Module::Install::AUTHOR && -d File::Spec->catfile('..', 'msgpack')) {
 requires 'Test::More' => 0.94; # done_testing
 test_requires('Test::Requires');
 
+test_with_env( test_pp => PERL_DATA_MESSAGEPACK => 'pp' );
+
+if($Module::Install::AUTHOR) {
+    postamble qq{test :: test_pp\n\n};
+}
+
 auto_set_repository();
 auto_include;
 WriteAll;
 
+# copied from Makefile.PL in Text::Xslate.
+sub test_with_env {
+    my($name, %env) = @_;
+
+    my $dir = '.testenv';
+    if(not -e $dir) {
+        mkdir $dir or die "Cannot mkdir '.testenv': $!";
+    }
+    clean_files($dir);
+
+    {
+        open my $out, '>', "$dir/$name.pl"
+            or die "Cannot open '$dir/$name.pl' for writing: $!";
+       print $out "# This file sets the env for 'make $name', \n";
+       print $out "# generated by $0 at ", scalar(localtime), ".\n";
+       print $out "# DO NOT EDIT THIS FILE DIRECTLY.\n";
+       print $out "\n";
+
+        while(my($name, $value) = each %env) {
+            printf $out '$ENV{q{%s}} = q{%s};'."\n", $name, $value;
+        }
+    }
+
+    # repeat testing for pure Perl mode
+    # see also ExtUtils::MM_Any::test_via_harness()
+
+    my $t =  q{$(FULLPERLRUN) -MExtUtils::Command::MM -e}
+            .q{ "do q[%s]; test_harness($(TEST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')"}
+            .q{ $(TEST_FILES)};
+
+    postamble qq{$name :: pure_all\n}
+            . qq{\t} . q{$(NOECHO) $(ECHO) TESTING: } . $name . qq{\n}
+            . qq{\t} . sprintf($t, "$dir/$name.pl") . qq{\n\n}
+
+            . qq{testall :: $name\n\n};
+    return;
+}
diff --git a/perl/t/00_compile.t b/perl/t/00_compile.t
index 66fe8f0e..f91b29e7 100644
--- a/perl/t/00_compile.t
+++ b/perl/t/00_compile.t
@@ -3,4 +3,4 @@ use warnings;
 use Test::More tests => 1;
 
 use_ok 'Data::MessagePack';
-
+diag ( $INC{'Data/MessagePack/PP.pm'} ? 'PP' : 'XS' );

From 8f43e033a49aaf1bacb8fb887a0f7b7a538c4031 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Thu, 2 Sep 2010 23:45:05 +0900
Subject: [PATCH 06/43] removed dependency on Data::Float

---
 perl/Makefile.PL                |  5 +--
 perl/lib/Data/MessagePack/PP.pm | 70 +++++++++++++--------------------
 2 files changed, 28 insertions(+), 47 deletions(-)

diff --git a/perl/Makefile.PL b/perl/Makefile.PL
index 7440a46d..b7864854 100644
--- a/perl/Makefile.PL
+++ b/perl/Makefile.PL
@@ -21,12 +21,9 @@ if ( $] >= 5.008005 and $use_xs ) {
     if ($ENV{DEBUG}) {
         cc_append_to_ccflags '-g';
     }
-    # for author's test_pp
-    requires 'Data::Float' => 0 if ( $Module::Install::AUTHOR and $] < 5.010 );
 }
-else { # for Data::MessagePack::PP
+else {
     print "configure PP version\n";
-    requires 'Data::Float' => 0 if ( $] < 5.010 );
 }
 
 clean_files qw{
diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index 540b416d..86583733 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -22,37 +22,19 @@ use B ();
 BEGIN {
     # for pack and unpack compatibility
     if ( $] < 5.010 ) {
-        require Data::Float;
-        *pack_double = sub {
-            my $float_hex = Data::Float::float_hex( $_[0] );
-            my ( $sign, $sgnf, $exp ) = $float_hex =~ /^([-+])0x1\.([a-z0-9]+)p([-+][\d]+)$/;
-            my @bits;
-
-            $sign = $sign eq '-' ? 1 : 0;
-            $exp  = sprintf( '%011b', 1023 + $exp );
-
-            my $bit  = $sign . $exp . join( '', map { unpack('B4', pack('H', $_) ) } split //, $sgnf );
-
-            while ( $bit =~ /(.{8})/g ) {
-                push @bits, $1;
-            }
-
-             return pack( 'C*', 0xcb, map { unpack( 'C', pack("B*", $_ ) ) } @bits );
-        };
-        *unpack_double = sub {
-            my $bits = join('', map { sprintf('%08b', $_) } unpack( 'C*', substr( $_[0], $_[1], 8 ) ) );
-            my $sign = substr($bits, 0, 1) ? '-' : '+';
-            my $sgnf = substr($bits, 12, 52);
-            my $exp  = substr($bits, 1, 11);
-            $bits = '';
-            while ( $sgnf =~ /(.{4})/g ) {
-                $bits .= unpack('H',pack('B4', $1));
-            }
-            $exp = ((unpack("C*",(pack("B8", (substr('00000'.$exp,0,8) )))) <<8 )
-                    + unpack("C*",(pack("B8", (substr('00000'.$exp,8,8) ))))) - 1023;
-            return Data::Float::hex_float( $sign . '0x1.' . $bits . 'p' . $exp ) + 0.0;
-        };
-        *unpack_float  = sub { Carp::croak("unpack_float is disable in less than Perl 5.10"); };
+        my $bo_is_le = unpack ( 'd', "\x00\x00\x00\x00\x00\x00\xf0\x3f") == 1; # 1.0LE
+        *pack_double = $bo_is_le ? sub {
+            my @v = unpack( 'V2', pack( 'd', $_[0] ) );
+            return pack 'CN2', 0xcb, @v[1,0];
+        }  : sub { pack 'Cd', 0xcb, $_[0]; };
+        *unpack_float = $bo_is_le ? sub {
+            my @v = unpack( 'v2', substr( $_[0], $_[1], 4 ) );
+            return unpack( 'f', pack( 'n2', @v[1,0] ) );
+        } : sub { return unpack( 'f', substr( $_[0], $_[1], 4 ) ); };
+        *unpack_double = $bo_is_le ? sub {
+            my @v = unpack( 'V2', substr( $_[0], $_[1], 8 ) );
+            return unpack( 'd', pack( 'N2', @v[1,0] ) );
+        } : sub { return unpack( 'd', substr( $_[0], $_[1], 8 ) ); };
         *unpack_int16  = sub {
             my $v = unpack 'n', substr( $_[0], $_[1], 2 );
             return $v ? $v - 0x10000 : 0;
@@ -62,14 +44,16 @@ BEGIN {
             return $v ? -(~$v + 1) : $v;
         };
         *unpack_int64  = sub { Carp::croak("unpack_int64 is disable in less than Perl 5.10"); };
+        *unpack_uint64 = sub { Carp::croak("unpack_uint64 is disable in less than Perl 5.10"); };
     }
     else {
         *pack_double   = sub { return pack 'Cd>', 0xcb, $_[0]; };
-        *unpack_double = sub { return unpack( 'd>', substr( $_[0], $_[1], 8 ) ); };
         *unpack_float  = sub { return unpack( 'f>', substr( $_[0], $_[1], 4 ) ); };
-        *unpack_int16  = sub { return unpack 'n!',  substr( $_[0], $_[1], 2 ); };
-        *unpack_int32  = sub { return unpack 'N!',  substr( $_[0], $_[1], 4 ); };
-        *unpack_int64  = sub { return unpack 'Q>',  substr( $_[0], $_[1], 8 ); };
+        *unpack_double = sub { return unpack( 'd>', substr( $_[0], $_[1], 8 ) ); };
+        *unpack_int16  = sub { return unpack( 'n!', substr( $_[0], $_[1], 2 ) ); };
+        *unpack_int32  = sub { return unpack( 'N!', substr( $_[0], $_[1], 4 ) ); };
+        *unpack_int64  = sub { return unpack( 'q>', substr( $_[0], $_[1], 8 ) ); };
+        *unpack_uint64 = sub { return unpack( 'Q>', substr( $_[0], $_[1], 8 ) ); };
     }
     # for 5.8 etc.
     unless ( defined &utf8::is_utf8 ) {
@@ -272,7 +256,7 @@ sub _unpack {
     }
     elsif ( $byte == 0xcf ) { # unit64
         $p += 8;
-        return CORE::unpack 'Q>', substr( $value, $p - 8, 8 );
+        return pack_uint64( $value, $p - 8 );
     }
     elsif ( $byte == 0xd3 ) { # int64
         $p += 8;
@@ -516,25 +500,25 @@ __END__
 
 =head1 NAME
 
-Data::MessagePack::PP - Pure Perl version of Data::MessagePack
-
-=head1 LIMITATION
-
-Currently this module works completely in Perl 5.10 or later.
-In Perl 5.8.x, it requires L<Data::Float> and cannot unpack int64 and float (pack int64 too).
+Data::MessagePack::PP - Pure Perl implementation of Data::MessagePack
 
 
 =head1 SEE ALSO
 
 L<http://msgpack.sourceforge.jp/>,
 L<Data::MessagePack>,
-L<Data::Float>,
 L<http://frox25.no-ip.org/~mtve/wiki/MessagePack.html>,
 
 =head1 AUTHOR
 
 makamaka
 
+=head1 LIMITATION
+
+Currently this module works completely in Perl 5.10 or later.
+In Perl 5.8.x, it cannot C<unpack> uint64 and int64.
+
+
 =head1 COPYRIGHT AND LICENSE
 
 This library is free software; you can redistribute it and/or modify

From 4cc6c3e535e1181dcd9810fd862b80954246f9b7 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Thu, 2 Sep 2010 23:48:57 +0900
Subject: [PATCH 07/43] modified t/05_preferred_int.t for Win32

---
 perl/t/05_preferred_int.t | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/perl/t/05_preferred_int.t b/perl/t/05_preferred_int.t
index 9860711b..67d11aaf 100644
--- a/perl/t/05_preferred_int.t
+++ b/perl/t/05_preferred_int.t
@@ -16,6 +16,7 @@ sub pis ($$) {
     # is(Dumper(Data::MessagePack->unpack(Data::MessagePack->pack($_[0]))), Dumper($_[0]));
 }
 
+my $is_win = $^O eq 'MSWin32';
 my @dat = (
     '',      'a0',
     '0',     '00',
@@ -29,12 +30,16 @@ my @dat = (
     ''.0xFFFFFF => 'ce 00 ff ff ff',
     ''.0xFFFFFFFF => 'ce ff ff ff ff',
     ''.0xFFFFFFFFF => 'ab 36 38 37 31 39 34 37 36 37 33 35',
-    ''.0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF => 'b4 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 33 34',
+    ''.0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF => $is_win ?
+                                            'b5 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 30 33 34'
+                                          : 'b4 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 33 34',
     '-'.0x8000000 => 'd2 f8 00 00 00',
     '-'.0x80000000 => 'd2 80 00 00 00',
     '-'.0x800000000 => 'ac 2d 33 34 33 35 39 37 33 38 33 36 38',
     '-'.0x8000000000 => 'ad 2d 35 34 39 37 35 35 38 31 33 38 38 38',
-    '-'.0x800000000000000000000000000000 => 'b5 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 38 65 2b 33 35',
+    '-'.0x800000000000000000000000000000 => $is_win ?
+                                            'b6 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 38 65 2b 30 33 35'
+                                          : 'b5 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 38 65 2b 33 35',
     {'0' => '1'}, '81 00 01',
     {'abc' => '1'}, '81 a3 61 62 63 01',
 );

From cdc09a7d30e3390dba17db64df121a2dc34c8f04 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Thu, 2 Sep 2010 23:52:36 +0900
Subject: [PATCH 08/43] Changes

---
 perl/Changes | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/perl/Changes b/perl/Changes
index a8a4298c..a9bb2dbb 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,7 +1,10 @@
 
 0.1x
 
-    - added PP version.
+    - added PP version (used in cases PERL_DATA_MESSAGEPACK=pp or fail to load XS).
+    - made Makefile.PL PP configurable.
+    - test_pp in author's test
+    - modified t/05_preferred_int.t for Win32
       (makamaka)
 
 0.15

From 2b75d54ce14521b70b63d7aa808a005ac8dafdfa Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Thu, 2 Sep 2010 23:56:55 +0900
Subject: [PATCH 09/43] modified pod

---
 perl/lib/Data/MessagePack/PP.pm | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index 86583733..270db343 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -509,16 +509,16 @@ L<http://msgpack.sourceforge.jp/>,
 L<Data::MessagePack>,
 L<http://frox25.no-ip.org/~mtve/wiki/MessagePack.html>,
 
-=head1 AUTHOR
-
-makamaka
-
 =head1 LIMITATION
 
 Currently this module works completely in Perl 5.10 or later.
 In Perl 5.8.x, it cannot C<unpack> uint64 and int64.
 
 
+=head1 AUTHOR
+
+makamaka
+
 =head1 COPYRIGHT AND LICENSE
 
 This library is free software; you can redistribute it and/or modify

From f91728561fe9c374edb93262e7c9a7c1d819d284 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Thu, 2 Sep 2010 23:58:40 +0900
Subject: [PATCH 10/43] ouch, modified pod

---
 perl/lib/Data/MessagePack/PP.pm | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index 270db343..5d956078 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -502,6 +502,11 @@ __END__
 
 Data::MessagePack::PP - Pure Perl implementation of Data::MessagePack
 
+=head1 LIMITATION
+
+Currently this module works completely in Perl 5.10 or later.
+In Perl 5.8.x, it cannot C<unpack> uint64 and int64.
+
 
 =head1 SEE ALSO
 
@@ -509,12 +514,6 @@ L<http://msgpack.sourceforge.jp/>,
 L<Data::MessagePack>,
 L<http://frox25.no-ip.org/~mtve/wiki/MessagePack.html>,
 
-=head1 LIMITATION
-
-Currently this module works completely in Perl 5.10 or later.
-In Perl 5.8.x, it cannot C<unpack> uint64 and int64.
-
-
 =head1 AUTHOR
 
 makamaka

From b97baf4d4713580e89e0dca3bad350339618923e Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Fri, 3 Sep 2010 12:53:56 +0900
Subject: [PATCH 11/43] added some comments in Data::MessagePack::PP

---
 perl/lib/Data/MessagePack/PP.pm | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index 5d956078..e01b7972 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -22,7 +22,10 @@ use B ();
 BEGIN {
     # for pack and unpack compatibility
     if ( $] < 5.010 ) {
+        # require $Config{byteorder}; my $bo_is_le = ( $Config{byteorder} =~ /^1234/ );
+        # which better?
         my $bo_is_le = unpack ( 'd', "\x00\x00\x00\x00\x00\x00\xf0\x3f") == 1; # 1.0LE
+        # In really, since 5.9.2 '>' is introduced.
         *pack_double = $bo_is_le ? sub {
             my @v = unpack( 'V2', pack( 'd', $_[0] ) );
             return pack 'CN2', 0xcb, @v[1,0];

From adfadc542a98dcc7d838778797b512ccf8bd78f2 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Sat, 4 Sep 2010 14:35:24 +0900
Subject: [PATCH 12/43] enable PP to pack/unpack int64 in less than Perl 5.10

---
 perl/lib/Data/MessagePack/PP.pm | 39 +++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 11 deletions(-)

diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index e01b7972..bd37ad76 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -26,6 +26,14 @@ BEGIN {
         # which better?
         my $bo_is_le = unpack ( 'd', "\x00\x00\x00\x00\x00\x00\xf0\x3f") == 1; # 1.0LE
         # In really, since 5.9.2 '>' is introduced.
+        *pack_uint64 = $bo_is_le ? sub {
+            my @v = unpack( 'V2', pack( 'Q', $_[0] ) );
+            return pack 'CN2', 0xcf, @v[1,0];
+        }  : sub { pack 'CQ', 0xcf, $_[0]; };
+        *pack_int64 = $bo_is_le ? sub {
+            my @v = unpack( 'V2', pack( 'q', $_[0] ) );
+            return pack 'CN2', 0xd3, @v[1,0];
+        }  : sub { pack 'Cq', 0xd3, $_[0]; };
         *pack_double = $bo_is_le ? sub {
             my @v = unpack( 'V2', pack( 'd', $_[0] ) );
             return pack 'CN2', 0xcb, @v[1,0];
@@ -43,13 +51,22 @@ BEGIN {
             return $v ? $v - 0x10000 : 0;
         };
         *unpack_int32  = sub {
+            no warnings; # avoid for warning about Hexadecimal number
             my $v = unpack 'N', substr( $_[0], $_[1], 4 );
-            return $v ? -(~$v + 1) : $v;
+            return $v ? $v - 0x100000000 : 0;
+        };
+        *unpack_int64 = sub {
+            my @v = unpack( 'V*', substr( $_[0], $_[1], 8 ) );
+            return unpack( 'q', pack( 'N2', @v[1,0] ) );
+        };
+        *unpack_uint64 = sub {
+            my @v = unpack( 'V*', substr( $_[0], $_[1], 8 ) );
+            return unpack( 'Q', pack( 'N2', @v[1,0] ) );
         };
-        *unpack_int64  = sub { Carp::croak("unpack_int64 is disable in less than Perl 5.10"); };
-        *unpack_uint64 = sub { Carp::croak("unpack_uint64 is disable in less than Perl 5.10"); };
     }
     else {
+        *pack_uint64   = sub { return pack 'CQ>', 0xcf, $_[0]; };
+        *pack_int64    = sub { return pack 'Cq>', 0xd3, $_[0]; };
         *pack_double   = sub { return pack 'Cd>', 0xcb, $_[0]; };
         *unpack_float  = sub { return unpack( 'f>', substr( $_[0], $_[1], 4 ) ); };
         *unpack_double = sub { return unpack( 'd>', substr( $_[0], $_[1], 8 ) ); };
@@ -130,14 +147,14 @@ sub _pack {
                     : $value < 2 ** 8 ?  CORE::pack 'CC', 0xcc, $value
                     : $value < 2 ** 16 ? CORE::pack 'Cn', 0xcd, $value
                     : $value < 2 ** 32 ? CORE::pack 'CN', 0xce, $value
-                    : CORE::pack 'CQ>', 0xcf, $value;
+                    : pack_uint64( $value );
         }
         else {
             return    -$value <= 32 ?      CORE::pack 'C', ($value & 255)
                     : -$value <= 2 **  7 ? CORE::pack 'Cc', 0xd0, $value
                     : -$value <= 2 ** 15 ? CORE::pack 'Cn', 0xd1, $value
                     : -$value <= 2 ** 31 ? CORE::pack 'CN', 0xd2, $value
-                    : CORE::pack 'Cq>', 0xd3, $value;
+                    : pack_int64( $value );
         }
 
     }
@@ -147,7 +164,9 @@ sub _pack {
         if ( $Data::MessagePack::PreferInteger ) {
             if ( $value =~ /^-?[0-9]+$/ ) { # ok?
                 my $value2 = 0 + $value;
-                if (  0 + $value != B::svref_2object( \$value2 )->int_value ) {
+                if ( $value > 0xFFFFFFFF or $value < '-'.0x80000000 or # <- needless but for XS compat
+                    0 + $value != B::svref_2object( \$value2 )->int_value
+                ) {
                     local $Data::MessagePack::PreferInteger; # avoid for PV => NV
                     return _pack( "$value" );
                 }
@@ -259,7 +278,7 @@ sub _unpack {
     }
     elsif ( $byte == 0xcf ) { # unit64
         $p += 8;
-        return pack_uint64( $value, $p - 8 );
+        return unpack_uint64( $value, $p - 8 );
     }
     elsif ( $byte == 0xd3 ) { # int64
         $p += 8;
@@ -505,11 +524,9 @@ __END__
 
 Data::MessagePack::PP - Pure Perl implementation of Data::MessagePack
 
-=head1 LIMITATION
-
-Currently this module works completely in Perl 5.10 or later.
-In Perl 5.8.x, it cannot C<unpack> uint64 and int64.
+=head1 DESCRIPTION
 
+This module is used by L<Data::MessagePack> internally.
 
 =head1 SEE ALSO
 

From 25531d83936a1253a9dc5ee1b0f4f771d301317d Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Sat, 4 Sep 2010 19:54:12 +0900
Subject: [PATCH 13/43] modified t/05_preferred_int.t for Win32

---
 perl/t/05_preferred_int.t | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/perl/t/05_preferred_int.t b/perl/t/05_preferred_int.t
index 9eb223ad..084df31c 100644
--- a/perl/t/05_preferred_int.t
+++ b/perl/t/05_preferred_int.t
@@ -34,12 +34,16 @@ my @dat = (
     ''.0xFFFFFF => 'ce 00 ff ff ff',
     ''.0xFFFFFFFF => 'ce ff ff ff ff',
     ''.0xFFFFFFFFF => 'ab 36 38 37 31 39 34 37 36 37 33 35',
-    ''.0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF => qr{^(b4 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 33 34|b7 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 34 32 31 65 2b 33 34)$},
+    ''.0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF => $is_win ? 
+                                            qr{^(b5 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 30 33 34|b8 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 34 32 31 65 2b 30 33 34)$}
+                                          : qr{^(b4 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 33 34|b7 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 34 32 31 65 2b 33 34)$},
     '-'.0x8000000 => 'd2 f8 00 00 00',
     '-'.0x80000000 => 'd2 80 00 00 00',
     '-'.0x800000000 => 'ac 2d 33 34 33 35 39 37 33 38 33 36 38',
     '-'.0x8000000000 => 'ad 2d 35 34 39 37 35 35 38 31 33 38 38 38',
-    '-'.0x800000000000000000000000000000 => qr{^(b5 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 38 65 2b 33 35|b8 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 37 39 33 36 65 2b 33 35)},
+    '-'.0x800000000000000000000000000000 => $is_win ? 
+                                              qr{^(b6 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 38 65 2b 30 33 35|b9 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 37 39 33 36 65 2b 30 33 35)}
+                                            : qr{^(b5 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 38 65 2b 33 35|b8 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 37 39 33 36 65 2b 33 35)},
     {'0' => '1'}, '81 00 01',
     {'abc' => '1'}, '81 a3 61 62 63 01',
 );

From 84123f544524d6ffd118b91cd7e053d0a6d8bbe4 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Sat, 4 Sep 2010 20:02:46 +0900
Subject: [PATCH 14/43] fallback PP configuration with c99 unspport compiler

---
 perl/Makefile.PL | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/perl/Makefile.PL b/perl/Makefile.PL
index b7864854..783e658d 100644
--- a/perl/Makefile.PL
+++ b/perl/Makefile.PL
@@ -11,19 +11,31 @@ license 'perl';
 tests 't/*.t';
 recursive_author_tests('xt');
 
-my $use_xs = want_xs();
 
-if ( $] >= 5.008005 and $use_xs ) {
-    can_cc or die "This module requires a C compiler";
-    use_ppport 3.19;
-    requires_c99(); # msgpack C library requires C99.
-    cc_src_paths('xs-src');
-    if ($ENV{DEBUG}) {
-        cc_append_to_ccflags '-g';
+if ( $] >= 5.008005 and want_xs() ) {
+    can_cc or die "This module requires a C compiler. Please retry with --pp";
+
+    my $has_c99 = c99_available(); # msgpack C library requires C99.
+
+    if ( $has_c99 ) {
+        use_ppport 3.19;
+        cc_src_paths('xs-src');
+        if ($ENV{DEBUG}) {
+            cc_append_to_ccflags '-g';
+        }
+    }
+    else {
+        print <<NOT_SUPPORT_C99;
+
+This distribution requires a C99 compiler, but yours seems not to support C99.
+Instead of XS, configure PP version.
+
+NOT_SUPPORT_C99
+
     }
 }
 else {
-    print "configure PP version\n";
+    print "configure PP version\n\n";
 }
 
 clean_files qw{

From 10ec1e48b0857319d1b122c5ef4951c4dc514a02 Mon Sep 17 00:00:00 2001
From: makamaka <makamaka.donzoko@gmail.com>
Date: Sun, 5 Sep 2010 01:54:44 +0900
Subject: [PATCH 15/43] modified begin process about byte order

---
 perl/lib/Data/MessagePack/PP.pm | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index bd37ad76..9e322991 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -25,19 +25,19 @@ BEGIN {
         # require $Config{byteorder}; my $bo_is_le = ( $Config{byteorder} =~ /^1234/ );
         # which better?
         my $bo_is_le = unpack ( 'd', "\x00\x00\x00\x00\x00\x00\xf0\x3f") == 1; # 1.0LE
-        # In really, since 5.9.2 '>' is introduced.
+        # In really, since 5.9.2 '>' is introduced. but 'n!' and 'N!'?
         *pack_uint64 = $bo_is_le ? sub {
             my @v = unpack( 'V2', pack( 'Q', $_[0] ) );
             return pack 'CN2', 0xcf, @v[1,0];
-        }  : sub { pack 'CQ', 0xcf, $_[0]; };
+        } : sub { pack 'CQ', 0xcf, $_[0]; };
         *pack_int64 = $bo_is_le ? sub {
             my @v = unpack( 'V2', pack( 'q', $_[0] ) );
             return pack 'CN2', 0xd3, @v[1,0];
-        }  : sub { pack 'Cq', 0xd3, $_[0]; };
+        } : sub { pack 'Cq', 0xd3, $_[0]; };
         *pack_double = $bo_is_le ? sub {
             my @v = unpack( 'V2', pack( 'd', $_[0] ) );
             return pack 'CN2', 0xcb, @v[1,0];
-        }  : sub { pack 'Cd', 0xcb, $_[0]; };
+        } : sub { pack 'Cd', 0xcb, $_[0]; };
         *unpack_float = $bo_is_le ? sub {
             my @v = unpack( 'v2', substr( $_[0], $_[1], 4 ) );
             return unpack( 'f', pack( 'n2', @v[1,0] ) );
@@ -55,14 +55,14 @@ BEGIN {
             my $v = unpack 'N', substr( $_[0], $_[1], 4 );
             return $v ? $v - 0x100000000 : 0;
         };
-        *unpack_int64 = sub {
+        *unpack_int64 = $bo_is_le ? sub {
             my @v = unpack( 'V*', substr( $_[0], $_[1], 8 ) );
             return unpack( 'q', pack( 'N2', @v[1,0] ) );
-        };
-        *unpack_uint64 = sub {
+        } : sub { pack 'q', substr( $_[0], $_[1], 8 ); };
+        *unpack_uint64 = $bo_is_le ? sub {
             my @v = unpack( 'V*', substr( $_[0], $_[1], 8 ) );
             return unpack( 'Q', pack( 'N2', @v[1,0] ) );
-        };
+        } : sub { pack 'Q', substr( $_[0], $_[1], 8 ); };
     }
     else {
         *pack_uint64   = sub { return pack 'CQ>', 0xcf, $_[0]; };

From b9bca2a19fc6519296bcda2c6af5f82cc744e005 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Sun, 5 Sep 2010 16:17:19 +0900
Subject: [PATCH 16/43] bump to 0.16

---
 perl/Changes                 | 5 +++++
 perl/lib/Data/MessagePack.pm | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/perl/Changes b/perl/Changes
index 189990a8..448130b4 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,8 @@
+0.16
+
+    - tests on 64bit machines with -Duselongdouble
+      (reported by andk)
+
 0.15
 
     - better argument validation.
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index 276353a2..94f28c19 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -4,7 +4,7 @@ use warnings;
 use XSLoader;
 use 5.008001;
 
-our $VERSION = '0.15';
+our $VERSION = '0.16';
 our $PreferInteger = 0;
 
 our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };

From 80db9971b5a579a1388e0e110baa4a8ec3d1ea7c Mon Sep 17 00:00:00 2001
From: Hideyuki Tanaka <tanakh@tanakh-desktop.(none)>
Date: Mon, 6 Sep 2010 01:32:00 +0900
Subject: [PATCH 17/43] pure haskell implementation.

---
 haskell/LICENSE                               |   2 +-
 haskell/cbits/msgpack.c                       | 137 ----
 haskell/msgpack.cabal                         |  55 +-
 haskell/src/Data/MessagePack.hs               | 130 ++--
 haskell/src/Data/MessagePack/Base.hsc         | 584 ------------------
 haskell/src/Data/MessagePack/Feed.hs          |  62 --
 haskell/src/Data/MessagePack/Monad.hs         | 156 -----
 .../Data/MessagePack/{Class.hs => Object.hs}  |  38 +-
 haskell/src/Data/MessagePack/Packer.hs        | 147 +++++
 haskell/src/Data/MessagePack/Put.hs           | 202 ++++++
 haskell/src/Data/MessagePack/Stream.hs        |  82 ---
 haskell/test/Monad.hs                         |  15 +-
 haskell/test/Stream.hs                        |  14 -
 haskell/test/Test.hs                          |  69 ++-
 14 files changed, 543 insertions(+), 1150 deletions(-)
 delete mode 100644 haskell/cbits/msgpack.c
 delete mode 100644 haskell/src/Data/MessagePack/Base.hsc
 delete mode 100644 haskell/src/Data/MessagePack/Feed.hs
 delete mode 100644 haskell/src/Data/MessagePack/Monad.hs
 rename haskell/src/Data/MessagePack/{Class.hs => Object.hs} (77%)
 create mode 100644 haskell/src/Data/MessagePack/Packer.hs
 create mode 100644 haskell/src/Data/MessagePack/Put.hs
 delete mode 100644 haskell/src/Data/MessagePack/Stream.hs
 delete mode 100644 haskell/test/Stream.hs

diff --git a/haskell/LICENSE b/haskell/LICENSE
index 2de30f66..3cb4d8c8 100644
--- a/haskell/LICENSE
+++ b/haskell/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009, Hideyuki Tanaka
+Copyright (c) 2009-2010, Hideyuki Tanaka
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/haskell/cbits/msgpack.c b/haskell/cbits/msgpack.c
deleted file mode 100644
index be445925..00000000
--- a/haskell/cbits/msgpack.c
+++ /dev/null
@@ -1,137 +0,0 @@
-#include <msgpack.h>
-
-void msgpack_sbuffer_init_wrap(msgpack_sbuffer* sbuf)
-{
-  msgpack_sbuffer_init(sbuf);
-}
-
-void msgpack_sbuffer_destroy_wrap(msgpack_sbuffer* sbuf)
-{
-  msgpack_sbuffer_destroy(sbuf);
-}
-
-int msgpack_sbuffer_write_wrap(void* data, const char* buf, unsigned int len)
-{
-  return msgpack_sbuffer_write(data, buf, len);
-}
-
-msgpack_packer* msgpack_packer_new_wrap(void *data, msgpack_packer_write callback)
-{
-  return msgpack_packer_new(data, callback);
-}
-
-void msgpack_packer_free_wrap(msgpack_packer* pk)
-{
-  msgpack_packer_free(pk);
-}
-
-int msgpack_pack_uint8_wrap(msgpack_packer* pk, uint8_t d)
-{
-  return msgpack_pack_uint8(pk, d);
-}
-
-int msgpack_pack_uint16_wrap(msgpack_packer* pk, uint16_t d)
-{
-  return msgpack_pack_uint16(pk, d);
-}
-
-int msgpack_pack_uint32_wrap(msgpack_packer* pk, uint32_t d)
-{
-  return msgpack_pack_uint32(pk, d);
-}
-
-int msgpack_pack_uint64_wrap(msgpack_packer* pk, uint64_t d)
-{
-  return msgpack_pack_uint64(pk, d);
-}
-
-int msgpack_pack_int8_wrap(msgpack_packer* pk, int8_t d)
-{
-  return msgpack_pack_int8(pk, d);
-}
-
-int msgpack_pack_int16_wrap(msgpack_packer* pk, int16_t d)
-{
-  return msgpack_pack_int16(pk, d);
-}
-
-int msgpack_pack_int32_wrap(msgpack_packer* pk, int32_t d)
-{
-  return msgpack_pack_int32(pk, d);
-}
-
-int msgpack_pack_int64_wrap(msgpack_packer* pk, int64_t d)
-{
-  return msgpack_pack_int64(pk, d);
-}
-
-int msgpack_pack_double_wrap(msgpack_packer* pk, double d)
-{
-  return msgpack_pack_double(pk, d);
-}
-
-int msgpack_pack_nil_wrap(msgpack_packer* pk)
-{
-  return msgpack_pack_nil(pk);
-}
-
-int msgpack_pack_true_wrap(msgpack_packer* pk)
-{
-  return msgpack_pack_true(pk);
-}
-
-int msgpack_pack_false_wrap(msgpack_packer* pk)
-{
-  return msgpack_pack_false(pk);
-}
-
-int msgpack_pack_array_wrap(msgpack_packer* pk, unsigned int n)
-{
-  return msgpack_pack_array(pk, n);
-}
-
-int msgpack_pack_map_wrap(msgpack_packer* pk, unsigned int n)
-{
-  return msgpack_pack_map(pk, n);
-}
-
-int msgpack_pack_raw_wrap(msgpack_packer* pk, size_t l)
-{
-  return msgpack_pack_raw(pk, l);
-}
-
-int msgpack_pack_raw_body_wrap(msgpack_packer* pk, const void *b, size_t l)
-{
-  return msgpack_pack_raw_body(pk, b, l);
-}
-
-bool msgpack_unpacker_reserve_buffer_wrap(msgpack_unpacker *mpac, size_t size)
-{
-  return msgpack_unpacker_reserve_buffer(mpac, size);
-}
-
-char *msgpack_unpacker_buffer_wrap(msgpack_unpacker *mpac)
-{
-  return msgpack_unpacker_buffer(mpac);
-}
-
-size_t msgpack_unpacker_buffer_capacity_wrap(const msgpack_unpacker *mpac)
-{
-  return msgpack_unpacker_buffer_capacity(mpac);
-}
-
-void msgpack_unpacker_buffer_consumed_wrap(msgpack_unpacker *mpac, size_t size)
-{
-  msgpack_unpacker_buffer_consumed(mpac, size);
-}
-
-void msgpack_unpacker_data_wrap(msgpack_unpacker *mpac, msgpack_object *obj)
-{
-  *obj=msgpack_unpacker_data(mpac);
-}
-
-size_t msgpack_unpacker_message_size_wrap(const msgpack_unpacker *mpac)
-{
-  return msgpack_unpacker_message_size(mpac);
-}
-
diff --git a/haskell/msgpack.cabal b/haskell/msgpack.cabal
index 82cdb525..8346c1f8 100644
--- a/haskell/msgpack.cabal
+++ b/haskell/msgpack.cabal
@@ -1,32 +1,35 @@
-Name:                msgpack
-Version:             0.2.2
-License:             BSD3
-License-File:        LICENSE
-Author:              Hideyuki Tanaka
-Maintainer:          Hideyuki Tanaka <tanaka.hideyuki@gmail.com>
-Category:            Data
-Synopsis:            A Haskell binding to MessagePack
+Name:               msgpack
+Version:            0.3.0
+Synopsis:           A Haskell binding to MessagePack
 Description:
   A Haskell binding to MessagePack <http://msgpack.sourceforge.jp/>
-Homepage:	     http://github.com/tanakh/hsmsgpack
-Stability:	     Experimental
-Tested-with:	     GHC==6.10.4
-Cabal-Version:	     >=1.2
-Build-Type:          Simple
 
-library
-  build-depends:	base>=4 && <5, mtl, bytestring
-  ghc-options:		-O2 -Wall
-  hs-source-dirs:	src
-  extra-libraries:	msgpackc
+License:            BSD3
+License-File:       LICENSE
+Category:           Data
+Author:             Hideyuki Tanaka
+Maintainer:         Hideyuki Tanaka <tanaka.hideyuki@gmail.com>
+Homepage:           http://github.com/tanakh/hsmsgpack
+Stability:          Experimental
+Tested-with:        GHC == 6.12.3
+Cabal-Version:      >= 1.2
+Build-Type:         Simple
+
+Library
+  Build-depends:    base >=4 && <5,
+                    transformers >= 0.2.1 && < 0.2.2,
+                    MonadCatchIO-transformers >= 0.2.2 && < 0.2.3,
+                    bytestring >= 0.9 && < 0.10,
+                    vector >= 0.6.0 && < 0.6.1,
+                    iteratee >= 0.4 && < 0.5,
+                    attoparsec >= 0.8.1 && < 0.8.2,
+                    binary >= 0.5.0 && < 0.5.1,
+                    data-binary-ieee754 >= 0.4 && < 0.5
+  Ghc-options:      -Wall -O2
+  Hs-source-dirs:   src
 
   Exposed-modules:
     Data.MessagePack
-    Data.MessagePack.Base
-    Data.MessagePack.Class
-    Data.MessagePack.Feed
-    Data.MessagePack.Monad
-    Data.MessagePack.Stream
-
-  C-Sources:
-    cbits/msgpack.c
+    Data.MessagePack.Object
+    Data.MessagePack.Put
+    Data.MessagePack.Parser
diff --git a/haskell/src/Data/MessagePack.hs b/haskell/src/Data/MessagePack.hs
index 2949e603..010eaab0 100644
--- a/haskell/src/Data/MessagePack.hs
+++ b/haskell/src/Data/MessagePack.hs
@@ -1,7 +1,7 @@
 --------------------------------------------------------------------
 -- |
 -- Module    : Data.MessagePack
--- Copyright : (c) Hideyuki Tanaka, 2009
+-- Copyright : (c) Hideyuki Tanaka, 2009-2010
 -- License   : BSD3
 --
 -- Maintainer:  tanaka.hideyuki@gmail.com
@@ -13,51 +13,105 @@
 --------------------------------------------------------------------
 
 module Data.MessagePack(
-  module Data.MessagePack.Base,
-  module Data.MessagePack.Class,
-  module Data.MessagePack.Feed,
-  module Data.MessagePack.Monad,
-  module Data.MessagePack.Stream,
+  module Data.MessagePack.Object,
+  module Data.MessagePack.Put,
+  module Data.MessagePack.Parser,
   
-  -- * Pack and Unpack
-  packb,
-  unpackb,
+  -- * Simple functions of Pack and Unpack
+  pack,
+  unpack,
+  
+  -- * Pack functions
+  packToString,
+  packToHandle,
+  packToFile,
+  
+  -- * Unpack functions
+  unpackFromString,
+  unpackFromHandle,
+  unpackFromFile,
   
-  -- * Pure version of Pack and Unpack
-  packb',
-  unpackb',
   ) where
 
-import Data.ByteString (ByteString)
-import System.IO.Unsafe
+import qualified Control.Monad.CatchIO as CIO
+import Control.Monad.IO.Class
+import qualified Data.Attoparsec as A
+import Data.Binary.Put
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.Functor.Identity
+import qualified Data.Iteratee as I
+import qualified Data.Iteratee.IO as I
+import System.IO
 
-import Data.MessagePack.Base
-import Data.MessagePack.Class
-import Data.MessagePack.Feed
-import Data.MessagePack.Monad
-import Data.MessagePack.Stream
+import Data.MessagePack.Object
+import Data.MessagePack.Put
+import Data.MessagePack.Parser
+
+bufferSize :: Int
+bufferSize = 4 * 1024
+
+class IsByteString s where
+  toBS :: s -> B.ByteString
+
+instance IsByteString B.ByteString where
+  toBS = id
+
+instance IsByteString L.ByteString where
+  toBS = B.concat . L.toChunks
 
 -- | Pack Haskell data to MessagePack string.
-packb :: OBJECT a => a -> IO ByteString
-packb dat = do
-  sb <- newSimpleBuffer
-  pc <- newPacker sb
-  pack pc dat
-  simpleBufferData sb
+pack :: ObjectPut a => a -> L.ByteString
+pack = packToString . put
 
 -- | Unpack MessagePack string to Haskell data.
-unpackb :: OBJECT a => ByteString -> IO (Result a)
-unpackb bs = do
-  withZone $ \z -> do
-    r <- unpackObject z bs
-    return $ case r of
-      Left err -> Left (show err)
-      Right (_, dat) -> fromObject dat
+unpack :: (ObjectGet a, IsByteString s) => s -> a
+unpack bs =
+  runIdentity $ I.run $ I.joinIM $ I.enumPure1Chunk (toBS bs) (parserToIteratee get)
 
--- | Pure version of 'packb'.
-packb' :: OBJECT a => a -> ByteString
-packb' dat = unsafePerformIO $ packb dat
+-- TODO: tryUnpack
 
--- | Pure version of 'unpackb'.
-unpackb' :: OBJECT a => ByteString -> Result a
-unpackb' bs = unsafePerformIO $ unpackb bs
+-- | Pack to ByteString.
+packToString :: Put -> L.ByteString
+packToString = runPut
+
+-- | Pack to Handle
+packToHandle :: Handle -> Put -> IO ()
+packToHandle h = L.hPutStr h . packToString
+
+-- | Pack to File
+packToFile :: FilePath -> Put -> IO ()
+packToFile path = L.writeFile path . packToString
+
+-- | Unpack from ByteString
+unpackFromString :: (Monad m, IsByteString s) => s -> A.Parser a -> m a
+unpackFromString bs =
+  I.run . I.joinIM . I.enumPure1Chunk (toBS bs) . parserToIteratee
+
+-- | Unpack from Handle
+unpackFromHandle :: CIO.MonadCatchIO m => Handle -> A.Parser a -> m a
+unpackFromHandle h =
+  I.run . I.joinIM . I.enumHandle bufferSize h . parserToIteratee
+
+-- | Unpack from File
+unpackFromFile :: CIO.MonadCatchIO m => FilePath -> A.Parser a -> m a
+unpackFromFile path p =
+  CIO.bracket
+  (liftIO $ openBinaryFile path ReadMode)
+  (liftIO . hClose)
+  (flip unpackFromHandle p)
+
+parserToIteratee :: Monad m => A.Parser a -> I.Iteratee B.ByteString m a
+parserToIteratee p = I.icont (itr (A.parse p)) Nothing
+  where
+    itr pcont s = case s of
+      I.EOF _ ->
+        I.throwErr (I.setEOF s)
+      I.Chunk bs ->
+        case pcont bs of
+          A.Fail _ _ msg ->
+            I.throwErr (I.iterStrExc msg)
+          A.Partial cont ->
+            I.icont (itr cont) Nothing
+          A.Done remain ret ->
+            I.idone ret (I.Chunk remain)
diff --git a/haskell/src/Data/MessagePack/Base.hsc b/haskell/src/Data/MessagePack/Base.hsc
deleted file mode 100644
index b6cdc287..00000000
--- a/haskell/src/Data/MessagePack/Base.hsc
+++ /dev/null
@@ -1,584 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE ForeignFunctionInterface #-}
-
---------------------------------------------------------------------
--- |
--- Module    : Data.MessagePack.Base
--- Copyright : (c) Hideyuki Tanaka, 2009
--- License   : BSD3
---
--- Maintainer:  tanaka.hideyuki@gmail.com
--- Stability :  experimental
--- Portability: portable
---
--- Low Level Interface to MessagePack C API
---
---------------------------------------------------------------------
-
-module Data.MessagePack.Base(
-  -- * Simple Buffer
-  SimpleBuffer,
-  newSimpleBuffer,
-  simpleBufferData,
-  
-  -- * Serializer
-  Packer,
-  newPacker,
-  
-  packU8,
-  packU16,
-  packU32,
-  packU64,  
-  packS8,
-  packS16,
-  packS32,
-  packS64,
-  
-  packTrue,
-  packFalse,
-  
-  packInt,
-  packDouble,
-  packNil,
-  packBool,
-  
-  packArray,
-  packMap,
-  packRAW,
-  packRAWBody,
-  packRAW',
-  
-  -- * Stream Deserializer
-  Unpacker,
-  defaultInitialBufferSize,
-  newUnpacker,
-  unpackerReserveBuffer,
-  unpackerBuffer,
-  unpackerBufferCapacity,
-  unpackerBufferConsumed,
-  unpackerFeed,
-  unpackerExecute,
-  unpackerData,
-  unpackerReleaseZone,
-  unpackerResetZone,
-  unpackerReset,
-  unpackerMessageSize,
-  
-  -- * MessagePack Object
-  Object(..),
-  packObject,
-  
-  UnpackReturn(..),
-  unpackObject,
-  
-  -- * Memory Zone
-  Zone,
-  newZone,
-  freeZone,
-  withZone,
-  ) where
-
-import Control.Exception
-import Control.Monad
-import Data.ByteString (ByteString)
-import qualified Data.ByteString as BS hiding (pack, unpack)
-import Data.Int
-import Data.Word
-import Foreign.C
-import Foreign.Concurrent
-import Foreign.ForeignPtr hiding (newForeignPtr)
-import Foreign.Marshal.Alloc
-import Foreign.Marshal.Array
-import Foreign.Ptr
-import Foreign.Storable
-
-#include <msgpack.h>
-
-type SimpleBuffer = ForeignPtr ()
-
-type WriteCallback = Ptr () -> CString -> CUInt -> IO CInt
-
--- | Create a new Simple Buffer. It will be deleted automatically.
-newSimpleBuffer :: IO SimpleBuffer
-newSimpleBuffer = do
-  ptr <- mallocBytes (#size msgpack_sbuffer)
-  fptr <- newForeignPtr ptr $ do
-    msgpack_sbuffer_destroy ptr
-    free ptr
-  withForeignPtr fptr $ \p ->
-    msgpack_sbuffer_init p
-  return fptr
-
--- | Get data of Simple Buffer.
-simpleBufferData :: SimpleBuffer -> IO ByteString
-simpleBufferData sb =
-  withForeignPtr sb $ \ptr -> do
-    size <- (#peek msgpack_sbuffer, size) ptr
-    dat  <- (#peek msgpack_sbuffer, data) ptr
-    BS.packCStringLen (dat, fromIntegral (size :: CSize))
-
-foreign import ccall "msgpack_sbuffer_init_wrap" msgpack_sbuffer_init ::
-  Ptr () -> IO ()
-
-foreign import ccall "msgpack_sbuffer_destroy_wrap" msgpack_sbuffer_destroy ::
-  Ptr () -> IO ()
-
-foreign import ccall "msgpack_sbuffer_write_wrap" msgpack_sbuffer_write ::
-  WriteCallback
-
-type Packer = ForeignPtr ()
-
--- | Create new Packer. It will be deleted automatically.
-newPacker :: SimpleBuffer -> IO Packer
-newPacker sbuf = do
-  cb <- wrap_callback msgpack_sbuffer_write
-  ptr <- withForeignPtr sbuf $ \ptr ->
-    msgpack_packer_new ptr cb
-  fptr <- newForeignPtr ptr $ do
-    msgpack_packer_free ptr
-  return fptr
-
-foreign import ccall "msgpack_packer_new_wrap" msgpack_packer_new ::
-  Ptr () -> FunPtr WriteCallback -> IO (Ptr ())
-
-foreign import ccall "msgpack_packer_free_wrap" msgpack_packer_free ::
-  Ptr () -> IO ()
-
-foreign import ccall "wrapper" wrap_callback ::
-  WriteCallback -> IO (FunPtr WriteCallback)
-
-packU8 :: Packer -> Word8 -> IO Int
-packU8 pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_uint8 ptr n
-
-foreign import ccall "msgpack_pack_uint8_wrap" msgpack_pack_uint8 ::
-  Ptr () -> Word8 -> IO CInt
-
-packU16 :: Packer -> Word16 -> IO Int
-packU16 pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_uint16 ptr n
-
-foreign import ccall "msgpack_pack_uint16_wrap" msgpack_pack_uint16 ::
-  Ptr () -> Word16 -> IO CInt
-
-packU32 :: Packer -> Word32 -> IO Int
-packU32 pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_uint32 ptr n
-
-foreign import ccall "msgpack_pack_uint32_wrap" msgpack_pack_uint32 ::
-  Ptr () -> Word32 -> IO CInt
-
-packU64 :: Packer -> Word64 -> IO Int
-packU64 pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_uint64 ptr n
-
-foreign import ccall "msgpack_pack_uint64_wrap" msgpack_pack_uint64 ::
-  Ptr () -> Word64 -> IO CInt
-
-packS8 :: Packer -> Int8 -> IO Int
-packS8 pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_int8 ptr n
-
-foreign import ccall "msgpack_pack_int8_wrap" msgpack_pack_int8 ::
-  Ptr () -> Int8 -> IO CInt
-
-packS16 :: Packer -> Int16 -> IO Int
-packS16 pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_int16 ptr n
-
-foreign import ccall "msgpack_pack_int16_wrap" msgpack_pack_int16 ::
-  Ptr () -> Int16 -> IO CInt
-
-packS32 :: Packer -> Int32 -> IO Int
-packS32 pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_int32 ptr n
-
-foreign import ccall "msgpack_pack_int32_wrap" msgpack_pack_int32 ::
-  Ptr () -> Int32 -> IO CInt
-
-packS64 :: Packer -> Int64 -> IO Int
-packS64 pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_int64 ptr n
-
-foreign import ccall "msgpack_pack_int64_wrap" msgpack_pack_int64 ::
-  Ptr () -> Int64 -> IO CInt
-
--- | Pack an integral data.
-packInt :: Integral a => Packer -> a -> IO Int
-packInt pc n = packS64 pc $ fromIntegral n
-
--- | Pack a double data.
-packDouble :: Packer -> Double -> IO Int
-packDouble pc d =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_double ptr (realToFrac d)
-
-foreign import ccall "msgpack_pack_double_wrap" msgpack_pack_double ::
-  Ptr () -> CDouble -> IO CInt
-
--- | Pack a nil.
-packNil :: Packer -> IO Int
-packNil pc =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_nil ptr
-
-foreign import ccall "msgpack_pack_nil_wrap" msgpack_pack_nil ::
-  Ptr () -> IO CInt
-
-packTrue :: Packer -> IO Int
-packTrue pc =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_true ptr
-
-foreign import ccall "msgpack_pack_true_wrap" msgpack_pack_true ::
-  Ptr () -> IO CInt
-
-packFalse :: Packer -> IO Int
-packFalse pc =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_false ptr
-
-foreign import ccall "msgpack_pack_false_wrap" msgpack_pack_false ::
-  Ptr () -> IO CInt
-
--- | Pack a bool data.
-packBool :: Packer -> Bool -> IO Int
-packBool pc True  = packTrue pc
-packBool pc False = packFalse pc
-
--- | 'packArray' @p n@ starts packing an array. 
--- Next @n@ data will consist this array.
-packArray :: Packer -> Int -> IO Int
-packArray pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_array ptr (fromIntegral n)
-
-foreign import ccall "msgpack_pack_array_wrap" msgpack_pack_array ::
-  Ptr () -> CUInt -> IO CInt
-
--- | 'packMap' @p n@ starts packing a map. 
--- Next @n@ pairs of data (2*n data) will consist this map.
-packMap :: Packer -> Int -> IO Int
-packMap pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_map ptr (fromIntegral n)
-
-foreign import ccall "msgpack_pack_map_wrap" msgpack_pack_map ::
-  Ptr () -> CUInt -> IO CInt
-
--- | 'packRAW' @p n@ starts packing a byte sequence. 
--- Next total @n@ bytes of 'packRAWBody' call will consist this sequence.
-packRAW :: Packer -> Int -> IO Int
-packRAW pc n =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-    msgpack_pack_raw ptr (fromIntegral n)
-
-foreign import ccall "msgpack_pack_raw_wrap" msgpack_pack_raw ::
-  Ptr () -> CSize -> IO CInt
-
--- | Pack a byte sequence.
-packRAWBody :: Packer -> ByteString -> IO Int
-packRAWBody pc bs =
-  liftM fromIntegral $ withForeignPtr pc $ \ptr ->
-  BS.useAsCStringLen bs $ \(str, len) ->
-    msgpack_pack_raw_body ptr (castPtr str) (fromIntegral len)
-
-foreign import ccall "msgpack_pack_raw_body_wrap" msgpack_pack_raw_body ::
-  Ptr () -> Ptr () -> CSize -> IO CInt
-
--- | Pack a single byte stream. It calls 'packRAW' and 'packRAWBody'.
-packRAW' :: Packer -> ByteString -> IO Int
-packRAW' pc bs = do
-  _ <- packRAW pc (BS.length bs)
-  packRAWBody pc bs
-
-type Unpacker = ForeignPtr ()
-
-defaultInitialBufferSize :: Int
-defaultInitialBufferSize = 32 * 1024 -- #const MSGPACK_UNPACKER_DEFAULT_INITIAL_BUFFER_SIZE
-
--- | 'newUnpacker' @initialBufferSize@ creates a new Unpacker. It will be deleted automatically.
-newUnpacker :: Int -> IO Unpacker
-newUnpacker initialBufferSize = do
-  ptr <- msgpack_unpacker_new (fromIntegral initialBufferSize)
-  fptr <- newForeignPtr ptr $ do
-    msgpack_unpacker_free ptr
-  return fptr
-
-foreign import ccall "msgpack_unpacker_new" msgpack_unpacker_new ::
-  CSize -> IO (Ptr ())
-
-foreign import ccall "msgpack_unpacker_free" msgpack_unpacker_free ::
-  Ptr() -> IO ()
-
--- | 'unpackerReserveBuffer' @up size@ reserves at least @size@ bytes of buffer.
-unpackerReserveBuffer :: Unpacker -> Int -> IO Bool
-unpackerReserveBuffer up size =
-  withForeignPtr up $ \ptr ->
-  liftM (/=0) $ msgpack_unpacker_reserve_buffer ptr (fromIntegral size)
-
-foreign import ccall "msgpack_unpacker_reserve_buffer_wrap" msgpack_unpacker_reserve_buffer ::
-  Ptr () -> CSize -> IO CChar
-
--- | Get a pointer of unpacker buffer.
-unpackerBuffer :: Unpacker -> IO (Ptr CChar)
-unpackerBuffer up =
-  withForeignPtr up $ \ptr ->
-  msgpack_unpacker_buffer ptr
-
-foreign import ccall "msgpack_unpacker_buffer_wrap" msgpack_unpacker_buffer ::
-  Ptr () -> IO (Ptr CChar)
-
--- | Get size of allocated buffer.
-unpackerBufferCapacity :: Unpacker -> IO Int
-unpackerBufferCapacity up =
-  withForeignPtr up $ \ptr ->
-  liftM fromIntegral $ msgpack_unpacker_buffer_capacity ptr
-
-foreign import ccall "msgpack_unpacker_buffer_capacity_wrap" msgpack_unpacker_buffer_capacity ::
-  Ptr () -> IO CSize
-
--- | 'unpackerBufferConsumed' @up size@ notices that writed @size@ bytes to buffer.
-unpackerBufferConsumed :: Unpacker -> Int -> IO ()
-unpackerBufferConsumed up size =
-  withForeignPtr up $ \ptr ->
-  msgpack_unpacker_buffer_consumed ptr (fromIntegral size)
-
-foreign import ccall "msgpack_unpacker_buffer_consumed_wrap" msgpack_unpacker_buffer_consumed ::
-  Ptr () -> CSize -> IO ()
-
--- | Write byte sequence to Unpacker. It is utility funciton, calls 'unpackerReserveBuffer', 'unpackerBuffer' and 'unpackerBufferConsumed'.
-unpackerFeed :: Unpacker -> ByteString -> IO ()
-unpackerFeed up bs =
-  BS.useAsCStringLen bs $ \(str, len) -> do
-    True <- unpackerReserveBuffer up len
-    ptr <- unpackerBuffer up
-    copyArray ptr str len
-    unpackerBufferConsumed up len
-
--- | Execute deserializing. It returns 0 when buffer contains not enough bytes, returns 1 when succeeded, returns negative value when it failed.
-unpackerExecute :: Unpacker -> IO Int
-unpackerExecute up =
-  withForeignPtr up $ \ptr ->
-  liftM fromIntegral $ msgpack_unpacker_execute ptr
-
-foreign import ccall "msgpack_unpacker_execute" msgpack_unpacker_execute ::
-  Ptr () -> IO CInt
-
--- | Returns a deserialized object when 'unpackerExecute' returned 1.
-unpackerData :: Unpacker -> IO Object
-unpackerData up =
-  withForeignPtr up $ \ptr ->
-  allocaBytes (#size msgpack_object) $ \pobj -> do
-    msgpack_unpacker_data ptr pobj
-    peekObject pobj
-
-foreign import ccall "msgpack_unpacker_data_wrap" msgpack_unpacker_data ::
-  Ptr () -> Ptr () -> IO ()
-
--- | Release memory zone. The returned zone must be freed by calling 'freeZone'.
-unpackerReleaseZone :: Unpacker -> IO Zone
-unpackerReleaseZone up =
-  withForeignPtr up $ \ptr ->
-  msgpack_unpacker_release_zone ptr
-
-foreign import ccall "msgpack_unpacker_release_zone" msgpack_unpacker_release_zone ::
-  Ptr () -> IO (Ptr ())
-
--- | Free memory zone used by Unapcker.
-unpackerResetZone :: Unpacker -> IO ()
-unpackerResetZone up =
-  withForeignPtr up $ \ptr ->
-  msgpack_unpacker_reset_zone ptr
-
-foreign import ccall "msgpack_unpacker_reset_zone" msgpack_unpacker_reset_zone ::
-  Ptr () -> IO ()
-
--- | Reset Unpacker state except memory zone.
-unpackerReset :: Unpacker -> IO ()
-unpackerReset up =
-  withForeignPtr up $ \ptr ->
-  msgpack_unpacker_reset ptr
-
-foreign import ccall "msgpack_unpacker_reset" msgpack_unpacker_reset ::
-  Ptr () -> IO ()
-
--- | Returns number of bytes of sequence of deserializing object.
-unpackerMessageSize :: Unpacker -> IO Int
-unpackerMessageSize up =
-  withForeignPtr up $ \ptr ->
-  liftM fromIntegral $ msgpack_unpacker_message_size ptr
-
-foreign import ccall "msgpack_unpacker_message_size_wrap" msgpack_unpacker_message_size ::
-  Ptr () -> IO CSize
-
-type Zone = Ptr ()
-
--- | Create a new memory zone. It must be freed manually.
-newZone :: IO Zone
-newZone =
-  msgpack_zone_new (#const MSGPACK_ZONE_CHUNK_SIZE)
-
--- | Free a memory zone.
-freeZone :: Zone -> IO ()
-freeZone z =
-  msgpack_zone_free z
-
--- | Create a memory zone, then execute argument, then free memory zone.
-withZone :: (Zone -> IO a) -> IO a
-withZone z =
-  bracket newZone freeZone z
-
-foreign import ccall "msgpack_zone_new" msgpack_zone_new ::
-  CSize -> IO Zone
-
-foreign import ccall "msgpack_zone_free" msgpack_zone_free ::
-  Zone -> IO ()
-
--- | Object Representation of MessagePack data.
-data Object =
-  ObjectNil
-  | ObjectBool Bool
-  | ObjectInteger Int
-  | ObjectDouble Double
-  | ObjectRAW ByteString
-  | ObjectArray [Object]
-  | ObjectMap [(Object, Object)]
-  deriving (Show)
-
-peekObject :: Ptr a -> IO Object
-peekObject ptr = do
-  typ <- (#peek msgpack_object, type) ptr
-  case (typ :: CInt) of
-    (#const MSGPACK_OBJECT_NIL) ->
-      return ObjectNil
-    (#const MSGPACK_OBJECT_BOOLEAN) ->
-      peekObjectBool ptr
-    (#const MSGPACK_OBJECT_POSITIVE_INTEGER) ->
-      peekObjectPositiveInteger ptr
-    (#const MSGPACK_OBJECT_NEGATIVE_INTEGER) ->
-      peekObjectNegativeInteger ptr
-    (#const MSGPACK_OBJECT_DOUBLE) ->
-      peekObjectDouble ptr
-    (#const MSGPACK_OBJECT_RAW) ->
-      peekObjectRAW ptr
-    (#const MSGPACK_OBJECT_ARRAY) ->
-      peekObjectArray ptr
-    (#const MSGPACK_OBJECT_MAP) ->
-      peekObjectMap ptr
-    _ ->
-      fail $ "peekObject: unknown object type (" ++ show typ ++ ")"
-
-peekObjectBool :: Ptr a -> IO Object
-peekObjectBool ptr = do
-  b <- (#peek msgpack_object, via.boolean) ptr
-  return $ ObjectBool $ (b :: CUChar) /= 0
-
-peekObjectPositiveInteger :: Ptr a -> IO Object
-peekObjectPositiveInteger ptr = do
-  n <- (#peek msgpack_object, via.u64) ptr
-  return $ ObjectInteger $ fromIntegral (n :: Word64)
-
-peekObjectNegativeInteger :: Ptr a -> IO Object
-peekObjectNegativeInteger ptr = do
-  n <- (#peek msgpack_object, via.i64) ptr
-  return $ ObjectInteger $ fromIntegral (n :: Int64)
-
-peekObjectDouble :: Ptr a -> IO Object
-peekObjectDouble ptr = do
-  d <- (#peek msgpack_object, via.dec) ptr
-  return $ ObjectDouble $ realToFrac (d :: CDouble)
-
-peekObjectRAW :: Ptr a -> IO Object
-peekObjectRAW ptr = do
-  size <- (#peek msgpack_object, via.raw.size) ptr
-  p    <- (#peek msgpack_object, via.raw.ptr) ptr
-  bs   <- BS.packCStringLen (p, fromIntegral (size :: Word32))
-  return $ ObjectRAW bs
-
-peekObjectArray :: Ptr a -> IO Object
-peekObjectArray ptr = do
-  csize <- (#peek msgpack_object, via.array.size) ptr
-  let size = fromIntegral (csize :: Word32)
-  p     <- (#peek msgpack_object, via.array.ptr) ptr
-  objs  <- mapM (\i -> peekObject $ p `plusPtr`
-                      ((#size msgpack_object) * i))
-           [0..size-1]
-  return $ ObjectArray objs
-
-peekObjectMap :: Ptr a -> IO Object
-peekObjectMap ptr = do
-  csize <- (#peek msgpack_object, via.map.size) ptr
-  let size = fromIntegral (csize :: Word32)
-  p     <- (#peek msgpack_object, via.map.ptr) ptr
-  dat   <- mapM (\i -> peekObjectKV $ p `plusPtr`
-                      ((#size msgpack_object_kv) * i))
-           [0..size-1]
-  return $ ObjectMap dat
-
-peekObjectKV :: Ptr a -> IO (Object, Object)
-peekObjectKV ptr = do
-  k <- peekObject $ ptr `plusPtr` (#offset msgpack_object_kv, key)
-  v <- peekObject $ ptr `plusPtr` (#offset msgpack_object_kv, val)
-  return (k, v)
-
--- | Pack a Object.
-packObject :: Packer -> Object -> IO ()
-packObject pc ObjectNil = packNil pc >> return ()
-
-packObject pc (ObjectBool b) = packBool pc b >> return ()
-
-packObject pc (ObjectInteger n) = packInt pc n >> return ()
-
-packObject pc (ObjectDouble d) = packDouble pc d >> return ()
-
-packObject pc (ObjectRAW bs) = packRAW' pc bs >> return ()
-
-packObject pc (ObjectArray ls) = do
-  _ <- packArray pc (length ls)
-  mapM_ (packObject pc) ls
-
-packObject pc (ObjectMap ls) = do
-  _ <- packMap pc (length ls)
-  mapM_ (\(a, b) -> packObject pc a >> packObject pc b) ls
-
-data UnpackReturn =
-  UnpackContinue     -- ^ not enough bytes to unpack object
-  | UnpackParseError -- ^ got invalid bytes
-  | UnpackError      -- ^ other error
-  deriving (Eq, Show)
-
--- | Unpack a single MessagePack object from byte sequence.
-unpackObject :: Zone -> ByteString -> IO (Either UnpackReturn (Int, Object))
-unpackObject z dat =
-  allocaBytes (#size msgpack_object) $ \ptr ->
-  BS.useAsCStringLen dat $ \(str, len) ->
-  alloca $ \poff -> do
-    poke poff 0
-    ret <- msgpack_unpack str (fromIntegral len) poff z ptr
-    case ret of
-      (#const MSGPACK_UNPACK_SUCCESS) -> do
-        off <- peek poff
-        obj <- peekObject ptr
-        return $ Right (fromIntegral off, obj)
-      (#const MSGPACK_UNPACK_EXTRA_BYTES) -> do
-        off <- peek poff
-        obj <- peekObject ptr
-        return $ Right (fromIntegral off, obj)
-      (#const MSGPACK_UNPACK_CONTINUE) ->
-        return $ Left UnpackContinue
-      (#const MSGPACK_UNPACK_PARSE_ERROR) ->
-        return $ Left UnpackParseError
-      _ ->
-        return $ Left UnpackError
-
-foreign import ccall "msgpack_unpack" msgpack_unpack ::
-  Ptr CChar -> CSize -> Ptr CSize -> Zone -> Ptr () -> IO CInt
diff --git a/haskell/src/Data/MessagePack/Feed.hs b/haskell/src/Data/MessagePack/Feed.hs
deleted file mode 100644
index 4b486396..00000000
--- a/haskell/src/Data/MessagePack/Feed.hs
+++ /dev/null
@@ -1,62 +0,0 @@
---------------------------------------------------------------------
--- |
--- Module    : Data.MessagePack.Feed
--- Copyright : (c) Hideyuki Tanaka, 2009
--- License   : BSD3
---
--- Maintainer:  tanaka.hideyuki@gmail.com
--- Stability :  experimental
--- Portability: portable
---
--- Feeders for Stream Deserializers
---
---------------------------------------------------------------------
-
-module Data.MessagePack.Feed(
-  -- * Feeder type
-  Feeder,
-  -- * Feeders
-  feederFromHandle,
-  feederFromFile,
-  feederFromString,
-  ) where
-
-import Data.ByteString (ByteString)
-import qualified Data.ByteString as BS
-import Data.IORef
-import System.IO
-
--- | Feeder returns Just ByteString when bytes remains, otherwise Nothing.
-type Feeder = IO (Maybe ByteString)
-
--- | Feeder from Handle
-feederFromHandle :: Handle -> IO Feeder
-feederFromHandle h = return $ do
-  bs <- BS.hGetNonBlocking h bufSize
-  if BS.length bs > 0
-    then do return $ Just bs
-    else do
-    c <- BS.hGet h 1
-    if BS.length c > 0
-      then do return $ Just c
-      else do
-      hClose h
-      return Nothing
-  where
-    bufSize = 4096
-
--- | Feeder from File
-feederFromFile :: FilePath -> IO Feeder
-feederFromFile path =
-  openFile path ReadMode >>= feederFromHandle
-
--- | Feeder from ByteString
-feederFromString :: ByteString -> IO Feeder
-feederFromString bs = do
-  r <- newIORef (Just bs)
-  return $ f r
-  where
-    f r = do
-      mb <- readIORef r
-      writeIORef r Nothing
-      return mb
diff --git a/haskell/src/Data/MessagePack/Monad.hs b/haskell/src/Data/MessagePack/Monad.hs
deleted file mode 100644
index 15f21fe0..00000000
--- a/haskell/src/Data/MessagePack/Monad.hs
+++ /dev/null
@@ -1,156 +0,0 @@
---------------------------------------------------------------------
--- |
--- Module    : Data.MessagePack.Monad
--- Copyright : (c) Hideyuki Tanaka, 2009
--- License   : BSD3
---
--- Maintainer:  tanaka.hideyuki@gmail.com
--- Stability :  experimental
--- Portability: portable
---
--- Monadic Stream Serializers and Deserializers
---
---------------------------------------------------------------------
-
-module Data.MessagePack.Monad(
-  -- * Classes
-  MonadPacker(..),
-  MonadUnpacker(..),
-  
-  -- * Packer and Unpacker type
-  PackerT(..),
-  UnpackerT(..),
-  
-  -- * Packers
-  packToString,
-  packToHandle,
-  packToFile,
-  
-  -- * Unpackers
-  unpackFrom,
-  unpackFromString,
-  unpackFromHandle,
-  unpackFromFile,
-  ) where
-
-import Control.Monad
-import Control.Monad.Trans
-import Data.ByteString (ByteString)
-import qualified Data.ByteString as BS
-import System.IO
-
-import Data.MessagePack.Base hiding (Unpacker)
-import qualified Data.MessagePack.Base as Base
-import Data.MessagePack.Class
-import Data.MessagePack.Feed
-
-class Monad m => MonadPacker m where
-  -- | Serialize a object
-  put :: OBJECT a => a -> m ()
-
-class Monad m => MonadUnpacker m where
-  -- | Deserialize a object
-  get :: OBJECT a => m a
-
--- | Serializer Type
-newtype PackerT m r = PackerT { runPackerT :: Base.Packer -> m r }
-
-instance Monad m => Monad (PackerT m) where
-  a >>= b =
-    PackerT $ \pc -> do
-      r <- runPackerT a pc
-      runPackerT (b r) pc
-  
-  return r =
-    PackerT $ \_ -> return r
-
-instance MonadTrans PackerT where
-  lift m = PackerT $ \_ -> m
-
-instance MonadIO m => MonadIO (PackerT m) where
-  liftIO = lift . liftIO
-
-instance MonadIO m => MonadPacker (PackerT m) where
-  put v = PackerT $ \pc -> liftIO $ do
-    pack pc v
-
--- | Execute given serializer and returns byte sequence.
-packToString :: MonadIO m => PackerT m r -> m ByteString
-packToString m = do
-  sb <- liftIO $ newSimpleBuffer
-  pc <- liftIO $ newPacker sb
-  _ <- runPackerT m pc
-  liftIO $ simpleBufferData sb
-
--- | Execute given serializer and write byte sequence to Handle.
-packToHandle :: MonadIO m => Handle -> PackerT m r -> m ()
-packToHandle h m = do
-  sb <- packToString m
-  liftIO $ BS.hPut h sb
-  liftIO $ hFlush h
-
--- | Execute given serializer and write byte sequence to file.
-packToFile :: MonadIO m => FilePath -> PackerT m r -> m ()
-packToFile p m = do
-  sb <- packToString m
-  liftIO $ BS.writeFile p sb
-
--- | Deserializer type
-newtype UnpackerT m r = UnpackerT { runUnpackerT :: Base.Unpacker -> Feeder -> m r }
-
-instance Monad m => Monad (UnpackerT m) where
-  a >>= b =
-    UnpackerT $ \up feed -> do
-      r <- runUnpackerT a up feed
-      runUnpackerT (b r) up feed
-  
-  return r =
-    UnpackerT $ \_ _ -> return r
-
-instance MonadTrans UnpackerT where
-  lift m = UnpackerT $ \_ _ -> m
-
-instance MonadIO m => MonadIO (UnpackerT m) where
-  liftIO = lift . liftIO
-
-instance MonadIO m => MonadUnpacker (UnpackerT m) where
-  get = UnpackerT $ \up feed -> liftIO $ do
-    executeOne up feed
-    obj <- unpackerData up
-    freeZone =<< unpackerReleaseZone up
-    unpackerReset up
-    let Right r = fromObject obj
-    return r
-    
-    where
-      executeOne up feed = do
-        resp <- unpackerExecute up
-        guard $ resp>=0
-        when (resp==0) $ do
-          Just bs <- feed
-          unpackerFeed up bs
-          executeOne up feed
-
--- | Execute deserializer using given feeder.
-unpackFrom :: MonadIO m => Feeder -> UnpackerT m r -> m r
-unpackFrom f m = do
-  up <- liftIO $ newUnpacker defaultInitialBufferSize
-  runUnpackerT m up f
-
--- | Execute deserializer using given handle.
-unpackFromHandle :: MonadIO m => Handle -> UnpackerT m r -> m r
-unpackFromHandle h m =
-  flip unpackFrom m =<< liftIO (feederFromHandle h)
-
--- | Execute deserializer using given file content.
-unpackFromFile :: MonadIO m => FilePath -> UnpackerT m r -> m r
-unpackFromFile p m = do
-  h <- liftIO $ openFile p ReadMode
-  r <- flip unpackFrom m =<< liftIO (feederFromHandle h)
-  liftIO $ hClose h
-  return r
-
--- | Execute deserializer from given byte sequence.
-unpackFromString :: MonadIO m => ByteString -> UnpackerT m r -> m r
-unpackFromString bs m = do
-  flip unpackFrom m =<< liftIO (feederFromString bs)
diff --git a/haskell/src/Data/MessagePack/Class.hs b/haskell/src/Data/MessagePack/Object.hs
similarity index 77%
rename from haskell/src/Data/MessagePack/Class.hs
rename to haskell/src/Data/MessagePack/Object.hs
index 365acc5f..19a3aeba 100644
--- a/haskell/src/Data/MessagePack/Class.hs
+++ b/haskell/src/Data/MessagePack/Object.hs
@@ -1,38 +1,50 @@
 {-# LANGUAGE TypeSynonymInstances #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE OverlappingInstances #-}
-{-# LANGUAGE IncoherentInstances #-}
 
 --------------------------------------------------------------------
 -- |
--- Module    : Data.MessagePack.Class
--- Copyright : (c) Hideyuki Tanaka, 2009
+-- Module    : Data.MessagePack.Object
+-- Copyright : (c) Hideyuki Tanaka, 2009-2010
 -- License   : BSD3
 --
 -- Maintainer:  tanaka.hideyuki@gmail.com
 -- Stability :  experimental
 -- Portability: portable
 --
--- Serializing Haskell values to and from MessagePack Objects.
+-- MessagePack object definition
 --
 --------------------------------------------------------------------
 
-module Data.MessagePack.Class(
+module Data.MessagePack.Object(
+  -- * MessagePack Object
+  Object(..),
+  
   -- * Serialization to and from Object
   OBJECT(..),
   Result,
-  pack,
   ) where
 
-import Control.Monad.Error
-import Data.ByteString.Char8 (ByteString)
+import Control.Monad
+import Control.Monad.Trans.Error ()
+import qualified Data.ByteString as B
 import qualified Data.ByteString.Char8 as C8
 
-import Data.MessagePack.Base
+-- | Object Representation of MessagePack data.
+data Object =
+  ObjectNil
+  | ObjectBool Bool
+  | ObjectInteger Int
+  | ObjectDouble Double
+  | ObjectRAW B.ByteString
+  | ObjectArray [Object]
+  | ObjectMap [(Object, Object)]
+  deriving (Show)
 
 -- | The class of types serializable to and from MessagePack object
 class OBJECT a where
+  -- | Encode a value to MessagePack object
   toObject :: a -> Object
+  -- | Decode a value from MessagePack object
   fromObject :: Object -> Result a
 
 -- | A type for parser results
@@ -65,7 +77,7 @@ instance OBJECT Double where
   fromObject (ObjectDouble d) = Right d
   fromObject _ = Left fromObjectError
 
-instance OBJECT ByteString where
+instance OBJECT B.ByteString where
   toObject = ObjectRAW
   fromObject (ObjectRAW bs) = Right bs
   fromObject _ = Left fromObjectError
@@ -95,7 +107,3 @@ instance OBJECT a => OBJECT (Maybe a) where
   
   fromObject ObjectNil = return Nothing
   fromObject obj = liftM Just $ fromObject obj
-
--- | Pack a serializable Haskell value.
-pack :: OBJECT a => Packer -> a -> IO ()
-pack pc = packObject pc . toObject
diff --git a/haskell/src/Data/MessagePack/Packer.hs b/haskell/src/Data/MessagePack/Packer.hs
new file mode 100644
index 00000000..9c10f5ed
--- /dev/null
+++ b/haskell/src/Data/MessagePack/Packer.hs
@@ -0,0 +1,147 @@
+{-# Language FlexibleInstances #-}
+{-# Language OverlappingInstances #-}
+
+module Data.MessagePack.Packer(
+  ObjectPut(..),
+  ) where
+
+import Data.Binary.Put
+import Data.Binary.IEEE754
+import Data.Bits
+import qualified Data.ByteString as B
+
+import Data.MessagePack.Object
+
+class ObjectPut a where
+  put :: a -> Put
+
+instance ObjectPut Object where
+  put = putObject
+
+instance ObjectPut Int where
+  put = putInteger
+
+instance ObjectPut () where
+  put _ = putNil
+
+instance ObjectPut Bool where
+  put = putBool
+
+instance ObjectPut Double where
+  put = putDouble
+
+instance ObjectPut B.ByteString where
+  put = putRAW
+
+instance ObjectPut a => ObjectPut [a] where
+  put = putArray
+
+instance (ObjectPut k, ObjectPut v) => ObjectPut [(k, v)] where
+  put = putMap
+
+putObject :: Object -> Put
+putObject obj =
+  case obj of
+    ObjectInteger n ->
+      putInteger n
+    ObjectNil ->
+      putNil
+    ObjectBool b ->
+      putBool b
+    ObjectDouble d ->
+      putDouble d
+    ObjectRAW raw ->
+      putRAW raw
+    ObjectArray arr ->
+      putArray arr
+    ObjectMap m ->
+      putMap m
+
+putInteger :: Int -> Put      
+putInteger n =
+  case n of
+    _ | n >= 0 && n <= 127 ->
+      putWord8 $ fromIntegral n
+    _ | n >= -32 && n <= -1 ->
+      putWord8 $ fromIntegral n
+    _ | n >= 0 && n < 0x100 -> do
+      putWord8 0xCC
+      putWord8 $ fromIntegral n
+    _ | n >= 0 && n < 0x10000 -> do
+      putWord8 0xCD
+      putWord16be $ fromIntegral n
+    _ | n >= 0 && n < 0x100000000 -> do
+      putWord8 0xCE
+      putWord32be $ fromIntegral n
+    _ | n >= 0 -> do
+      putWord8 0xCF
+      putWord64be $ fromIntegral n
+    _ | n >= -0x100 -> do
+      putWord8 0xD0
+      putWord8 $ fromIntegral n
+    _ | n >= -0x10000 -> do
+      putWord8 0xD1
+      putWord16be $ fromIntegral n
+    _ | n >= -0x100000000 -> do
+      putWord8 0xD2
+      putWord32be $ fromIntegral n
+    _ -> do
+      putWord8 0xD3
+      putWord64be $ fromIntegral n
+
+putNil :: Put
+putNil = putWord8 0xC0
+
+putBool :: Bool -> Put
+putBool True = putWord8 0xC3
+putBool False = putWord8 0xC2
+
+putDouble :: Double -> Put
+putDouble d = do
+  putWord8 0xCB
+  putFloat64be d
+
+putRAW :: B.ByteString -> Put
+putRAW bs = do
+  case len of
+    _ | len <= 31 -> do
+      putWord8 $ 0xA0 .|. fromIntegral len
+    _ | len < 0x10000 -> do
+      putWord8 0xDA
+      putWord16be $ fromIntegral len
+    _ -> do
+      putWord8 0xDB
+      putWord32be $ fromIntegral len
+  putByteString bs
+  where
+    len = B.length bs
+
+putArray :: ObjectPut a => [a] -> Put
+putArray arr = do
+  case len of
+    _ | len <= 15 ->
+      putWord8 $ 0x90 .|. fromIntegral len
+    _ | len < 0x10000 -> do
+      putWord8 0xDC
+      putWord16be $ fromIntegral len
+    _ -> do
+      putWord8 0xDD
+      putWord32be $ fromIntegral len
+  mapM_ put arr
+  where
+    len = length arr
+
+putMap :: (ObjectPut k, ObjectPut v) => [(k, v)] -> Put
+putMap m = do
+  case len of
+    _ | len <= 15 ->
+      putWord8 $ 0x80 .|. fromIntegral len
+    _ | len < 0x10000 -> do
+      putWord8 0xDE
+      putWord16be $ fromIntegral len
+    _ -> do
+      putWord8 0xDF
+      putWord16be $ fromIntegral len
+  mapM_ (\(k, v) -> put k >> put v) m
+  where
+    len = length m
diff --git a/haskell/src/Data/MessagePack/Put.hs b/haskell/src/Data/MessagePack/Put.hs
new file mode 100644
index 00000000..8d0af2b2
--- /dev/null
+++ b/haskell/src/Data/MessagePack/Put.hs
@@ -0,0 +1,202 @@
+{-# Language FlexibleInstances #-}
+{-# Language IncoherentInstances #-}
+{-# Language OverlappingInstances #-}
+
+--------------------------------------------------------------------
+-- |
+-- Module    : Data.MessagePack.Put
+-- Copyright : (c) Hideyuki Tanaka, 2009-2010
+-- License   : BSD3
+--
+-- Maintainer:  tanaka.hideyuki@gmail.com
+-- Stability :  experimental
+-- Portability: portable
+--
+-- MessagePack Serializer using @Data.Binary.Put@
+--
+--------------------------------------------------------------------
+
+module Data.MessagePack.Put(
+  -- * Serializable class
+  ObjectPut(..),
+  ) where
+
+import Data.Binary.Put
+import Data.Binary.IEEE754
+import Data.Bits
+import qualified Data.ByteString as B
+import qualified Data.Vector as V
+
+import Data.MessagePack.Object
+
+-- | Serializable class
+class ObjectPut a where
+  -- | Serialize a value
+  put :: a -> Put
+
+instance ObjectPut Object where
+  put = putObject
+
+instance ObjectPut Int where
+  put = putInteger
+
+instance ObjectPut () where
+  put _ = putNil
+
+instance ObjectPut Bool where
+  put = putBool
+
+instance ObjectPut Double where
+  put = putDouble
+
+instance ObjectPut B.ByteString where
+  put = putRAW
+
+instance ObjectPut a => ObjectPut [a] where
+  put = putArray
+
+instance ObjectPut a => ObjectPut (V.Vector a) where
+  put = putArrayVector
+
+instance (ObjectPut k, ObjectPut v) => ObjectPut [(k, v)] where
+  put = putMap
+
+instance (ObjectPut k, ObjectPut v) => ObjectPut (V.Vector (k, v)) where
+  put = putMapVector
+
+putObject :: Object -> Put
+putObject obj =
+  case obj of
+    ObjectInteger n ->
+      putInteger n
+    ObjectNil ->
+      putNil
+    ObjectBool b ->
+      putBool b
+    ObjectDouble d ->
+      putDouble d
+    ObjectRAW raw ->
+      putRAW raw
+    ObjectArray arr ->
+      putArray arr
+    ObjectMap m ->
+      putMap m
+
+putInteger :: Int -> Put      
+putInteger n =
+  case n of
+    _ | n >= 0 && n <= 127 ->
+      putWord8 $ fromIntegral n
+    _ | n >= -32 && n <= -1 ->
+      putWord8 $ fromIntegral n
+    _ | n >= 0 && n < 0x100 -> do
+      putWord8 0xCC
+      putWord8 $ fromIntegral n
+    _ | n >= 0 && n < 0x10000 -> do
+      putWord8 0xCD
+      putWord16be $ fromIntegral n
+    _ | n >= 0 && n < 0x100000000 -> do
+      putWord8 0xCE
+      putWord32be $ fromIntegral n
+    _ | n >= 0 -> do
+      putWord8 0xCF
+      putWord64be $ fromIntegral n
+    _ | n >= -0x80 -> do
+      putWord8 0xD0
+      putWord8 $ fromIntegral n
+    _ | n >= -0x8000 -> do
+      putWord8 0xD1
+      putWord16be $ fromIntegral n
+    _ | n >= -0x80000000 -> do
+      putWord8 0xD2
+      putWord32be $ fromIntegral n
+    _ -> do
+      putWord8 0xD3
+      putWord64be $ fromIntegral n
+
+putNil :: Put
+putNil = putWord8 0xC0
+
+putBool :: Bool -> Put
+putBool True = putWord8 0xC3
+putBool False = putWord8 0xC2
+
+putDouble :: Double -> Put
+putDouble d = do
+  putWord8 0xCB
+  putFloat64be d
+
+putRAW :: B.ByteString -> Put
+putRAW bs = do
+  case len of
+    _ | len <= 31 -> do
+      putWord8 $ 0xA0 .|. fromIntegral len
+    _ | len < 0x10000 -> do
+      putWord8 0xDA
+      putWord16be $ fromIntegral len
+    _ -> do
+      putWord8 0xDB
+      putWord32be $ fromIntegral len
+  putByteString bs
+  where
+    len = B.length bs
+
+putArray :: ObjectPut a => [a] -> Put
+putArray arr = do
+  case len of
+    _ | len <= 15 ->
+      putWord8 $ 0x90 .|. fromIntegral len
+    _ | len < 0x10000 -> do
+      putWord8 0xDC
+      putWord16be $ fromIntegral len
+    _ -> do
+      putWord8 0xDD
+      putWord32be $ fromIntegral len
+  mapM_ put arr
+  where
+    len = length arr
+
+putArrayVector :: ObjectPut a => V.Vector a -> Put
+putArrayVector arr = do
+  case len of
+    _ | len <= 15 ->
+      putWord8 $ 0x90 .|. fromIntegral len
+    _ | len < 0x10000 -> do
+      putWord8 0xDC
+      putWord16be $ fromIntegral len
+    _ -> do
+      putWord8 0xDD
+      putWord32be $ fromIntegral len
+  V.mapM_ put arr
+  where
+    len = V.length arr
+
+putMap :: (ObjectPut k, ObjectPut v) => [(k, v)] -> Put
+putMap m = do
+  case len of
+    _ | len <= 15 ->
+      putWord8 $ 0x80 .|. fromIntegral len
+    _ | len < 0x10000 -> do
+      putWord8 0xDE
+      putWord16be $ fromIntegral len
+    _ -> do
+      putWord8 0xDF
+      putWord32be $ fromIntegral len
+  mapM_ (\(k, v) -> put k >> put v) m
+  where
+    len = length m
+
+putMapVector :: (ObjectPut k, ObjectPut v) => V.Vector (k, v) -> Put
+putMapVector m = do
+  case len of
+    _ | len <= 15 ->
+      putWord8 $ 0x80 .|. fromIntegral len
+    _ | len < 0x10000 -> do
+      putWord8 0xDE
+      putWord16be $ fromIntegral len
+    _ -> do
+      putWord8 0xDF
+      putWord32be $ fromIntegral len
+  V.mapM_ (\(k, v) -> put k >> put v) m
+  where
+    len = V.length m
diff --git a/haskell/src/Data/MessagePack/Stream.hs b/haskell/src/Data/MessagePack/Stream.hs
deleted file mode 100644
index c56fe8d4..00000000
--- a/haskell/src/Data/MessagePack/Stream.hs
+++ /dev/null
@@ -1,82 +0,0 @@
---------------------------------------------------------------------
--- |
--- Module    : Data.MessagePack.Stream
--- Copyright : (c) Hideyuki Tanaka, 2009
--- License   : BSD3
---
--- Maintainer:  tanaka.hideyuki@gmail.com
--- Stability :  experimental
--- Portability: portable
---
--- Lazy Stream Serializers and Deserializers
---
---------------------------------------------------------------------
-
-module Data.MessagePack.Stream(
-  unpackObjects,
-  unpackObjectsFromFile,
-  unpackObjectsFromHandle,
-  unpackObjectsFromString,
-  ) where
-
-import Data.ByteString (ByteString)
-import System.IO
-import System.IO.Unsafe
-
-import Data.MessagePack.Base
-import Data.MessagePack.Feed
-
--- | Unpack objects using given feeder.
-unpackObjects :: Feeder -> IO [Object]
-unpackObjects feeder = do
-  up <- newUnpacker defaultInitialBufferSize
-  f up
-  where
-  f up = unsafeInterleaveIO $ do
-    mbo <- unpackOnce up
-    case mbo of
-      Just o -> do
-        os <- f up
-        return $ o:os
-      Nothing ->
-        return []
-
-  unpackOnce up = do
-    resp <- unpackerExecute up
-    case resp of
-      0 -> do
-        r <- feedOnce up
-        if r
-          then unpackOnce up
-          else return Nothing
-      1 -> do
-        obj <- unpackerData up
-        freeZone =<< unpackerReleaseZone up
-        unpackerReset up
-        return $ Just obj
-      _ ->
-        error $ "unpackerExecute fails: " ++ show resp
-
-  feedOnce up = do
-    dat <- feeder
-    case dat of
-      Nothing ->
-        return False
-      Just bs -> do
-        unpackerFeed up bs
-        return True
-
--- | Unpack objects from file.
-unpackObjectsFromFile :: FilePath -> IO [Object]
-unpackObjectsFromFile fname =
-  unpackObjects =<< feederFromFile fname
-
--- | Unpack objects from handle.
-unpackObjectsFromHandle :: Handle -> IO [Object]
-unpackObjectsFromHandle h =
-  unpackObjects =<< feederFromHandle h
-  
--- | Unpack oobjects from given byte sequence.
-unpackObjectsFromString :: ByteString -> IO [Object]
-unpackObjectsFromString bs =
-  unpackObjects =<< feederFromString bs
diff --git a/haskell/test/Monad.hs b/haskell/test/Monad.hs
index 4bee5c54..2ec40938 100644
--- a/haskell/test/Monad.hs
+++ b/haskell/test/Monad.hs
@@ -1,16 +1,21 @@
-import Control.Monad.Trans
+{-# Language OverloadedStrings #-}
+
+import Control.Monad.IO.Class
+import qualified Data.ByteString as B
 import Data.MessagePack
 
 main = do
-  sb <- packToString $ do
+  sb <- return $ packToString $ do
     put [1,2,3::Int]
     put (3.14 :: Double)
-    put "Hoge"
+    put ("Hoge" :: B.ByteString)
   
   print sb
   
-  unpackFromString sb $ do
+  r <- unpackFromString sb $ do
     arr <- get
     dbl <- get
     str <- get
-    liftIO $ print (arr :: [Int], dbl :: Double, str :: String)
+    return (arr :: [Int], dbl :: Double, str :: B.ByteString)
+  
+  print r
diff --git a/haskell/test/Stream.hs b/haskell/test/Stream.hs
deleted file mode 100644
index ce060dea..00000000
--- a/haskell/test/Stream.hs
+++ /dev/null
@@ -1,14 +0,0 @@
-import Control.Applicative
-import qualified Data.ByteString as BS
-import Data.MessagePack
-
-main = do
-  sb <- newSimpleBuffer
-  pc <- newPacker sb
-  pack pc [1,2,3::Int]
-  pack pc True
-  pack pc "hoge"
-  bs <- simpleBufferData sb
-  
-  os <- unpackObjectsFromString bs
-  mapM_ print os
diff --git a/haskell/test/Test.hs b/haskell/test/Test.hs
index 4e713ba6..1bb551c1 100644
--- a/haskell/test/Test.hs
+++ b/haskell/test/Test.hs
@@ -1,36 +1,45 @@
+import Test.Framework
+import Test.Framework.Providers.QuickCheck2
+import Test.QuickCheck
+
 import Control.Monad
+import qualified Data.ByteString.Char8 as B
 import Data.MessagePack
 
-{-
-main = do
-  sb <- newSimpleBuffer
-  pc <- newPacker sb
-  
-  pack pc [(1,2),(2,3),(3::Int,4::Int)]
-  pack pc [4,5,6::Int]
-  pack pc "hoge"
-  
-  bs <- simpleBufferData sb
-  print bs
-  
-  up <- newUnpacker defaultInitialBufferSize
-  
-  unpackerFeed up bs
+mid :: (ObjectGet a, ObjectPut a) => a -> a
+mid = unpack . pack
 
-  let f = do
-        res <- unpackerExecute up
-        when (res==1) $ do
-          obj <- unpackerData up
-          print obj
-          f
-  
-  f
+prop_mid_int a = a == mid a
+  where types = a :: Int
+prop_mid_nil a = a == mid a
+  where types = a :: ()
+prop_mid_bool a = a == mid a
+  where types = a :: Bool
+prop_mid_double a = a == mid a
+  where types = a :: Double
+prop_mid_string a = a == B.unpack (mid (B.pack a))
+  where types = a :: String
+prop_mid_array_int a = a == mid a
+  where types = a :: [Int]
+prop_mid_array_string a = a == map B.unpack (mid (map B.pack a))
+  where types = a :: [String]
+prop_mid_map_int_double a = a == mid a
+  where types = a :: [(Int, Double)]
+prop_mid_map_string_string a = a == map (\(x, y) -> (B.unpack x, B.unpack y)) (mid (map (\(x, y) -> (B.pack x, B.pack y)) a))
+  where types = a :: [(String, String)]
 
-  return ()
--}
+tests =
+  [ testGroup "simple"
+    [ testProperty "int" prop_mid_int
+    , testProperty "nil" prop_mid_nil
+    , testProperty "bool" prop_mid_bool
+    , testProperty "double" prop_mid_double
+    , testProperty "string" prop_mid_string
+    , testProperty "[int]" prop_mid_array_int
+    , testProperty "[string]" prop_mid_array_string
+    , testProperty "[(int, double)]" prop_mid_map_int_double
+    , testProperty "[(string, string)]" prop_mid_map_string_string
+    ]
+  ]
 
-main = do
-  bs <- packb [(1,2),(2,3),(3::Int,4::Int)]
-  print bs
-  dat <- unpackb bs
-  print (dat :: Result [(Int, Int)])
+main = defaultMain tests

From 0368a70dd70a91598507bc7baad8291adc1309fa Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Mon, 6 Sep 2010 13:55:34 +0900
Subject: [PATCH 18/43] forgot to add file

---
 haskell/src/Data/MessagePack/Parser.hs | 259 +++++++++++++++++++++++++
 1 file changed, 259 insertions(+)
 create mode 100644 haskell/src/Data/MessagePack/Parser.hs

diff --git a/haskell/src/Data/MessagePack/Parser.hs b/haskell/src/Data/MessagePack/Parser.hs
new file mode 100644
index 00000000..d0cd0846
--- /dev/null
+++ b/haskell/src/Data/MessagePack/Parser.hs
@@ -0,0 +1,259 @@
+{-# Language FlexibleInstances #-}
+{-# Language IncoherentInstances #-}
+{-# Language OverlappingInstances #-}
+
+--------------------------------------------------------------------
+-- |
+-- Module    : Data.MessagePack.Parser
+-- Copyright : (c) Hideyuki Tanaka, 2009-2010
+-- License   : BSD3
+--
+-- Maintainer:  tanaka.hideyuki@gmail.com
+-- Stability :  experimental
+-- Portability: portable
+--
+-- MessagePack Deserializer using @Data.Attoparsec@
+--
+--------------------------------------------------------------------
+
+module Data.MessagePack.Parser(
+  -- * MessagePack deserializer
+  ObjectGet(..),
+  ) where
+
+import Control.Monad
+import qualified Data.Attoparsec as A
+import Data.Binary.Get
+import Data.Binary.IEEE754
+import Data.Bits
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as L
+import Data.Int
+import qualified Data.Vector as V
+import Data.Word
+import Text.Printf
+
+import Data.MessagePack.Object
+
+-- | Deserializable class
+class ObjectGet a where
+  -- | Deserialize a value
+  get :: A.Parser a
+
+instance ObjectGet Int where
+  get = parseInt
+
+instance ObjectGet () where
+  get = parseNil
+
+instance ObjectGet Bool where
+  get = parseBool
+
+instance ObjectGet Double where
+  get = parseDouble
+
+instance ObjectGet B.ByteString where
+  get = parseRAW
+
+instance ObjectGet a => ObjectGet [a] where
+  get = parseArray
+
+instance ObjectGet a => ObjectGet (V.Vector a) where
+  get = parseArrayVector
+
+instance (ObjectGet k, ObjectGet v) => ObjectGet [(k, v)] where
+  get = parseMap
+
+instance (ObjectGet k, ObjectGet v) => ObjectGet (V.Vector (k, v)) where
+  get = parseMapVector
+
+instance ObjectGet Object where
+  get = parseObject
+
+parseInt :: A.Parser Int
+parseInt = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0x80 == 0x00 ->
+      return $ fromIntegral c
+    _ | c .&. 0xE0 == 0xE0 ->
+      return $ fromIntegral (fromIntegral c :: Int8)      
+    0xCC ->
+      return . fromIntegral =<< A.anyWord8
+    0xCD ->
+      return . fromIntegral =<< parseUint16
+    0xCE ->
+      return . fromIntegral =<< parseUint32
+    0xCF ->
+      return . fromIntegral =<< parseUint64
+    0xD0 ->
+      return . fromIntegral =<< parseInt8
+    0xD1 ->
+      return . fromIntegral =<< parseInt16
+    0xD2 ->
+      return . fromIntegral =<< parseInt32
+    0xD3 ->
+      return . fromIntegral =<< parseInt64
+    _ ->
+      fail $ printf "invlid integer tag: 0x%02X" c
+
+parseNil :: A.Parser ()
+parseNil = do
+  _ <- A.word8 0xC0
+  return ()
+
+parseBool :: A.Parser Bool
+parseBool = do
+  c <- A.anyWord8
+  case c of
+    0xC3 ->
+      return True
+    0xC2 ->
+      return False
+    _ ->
+      fail $ printf "invlid bool tag: 0x%02X" c
+
+parseDouble :: A.Parser Double
+parseDouble = do
+  c <- A.anyWord8
+  case c of
+    0xCA ->
+      return . realToFrac . runGet getFloat32be . toLBS =<< A.take 4
+    0xCB ->
+      return . runGet getFloat64be . toLBS =<< A.take 8
+    _ ->
+      fail $ printf "invlid double tag: 0x%02X" c
+
+parseRAW :: A.Parser B.ByteString
+parseRAW = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0xE0 == 0xA0 ->
+      A.take . fromIntegral $ c .&. 0x1F
+    0xDA ->
+      A.take . fromIntegral =<< parseUint16
+    0xDB ->
+      A.take . fromIntegral =<< parseUint32
+    _ ->
+      fail $ printf "invlid raw tag: 0x%02X" c
+  
+parseArray :: ObjectGet a => A.Parser [a]
+parseArray = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0xF0 == 0x90 ->
+      flip replicateM get . fromIntegral $ c .&. 0x0F
+    0xDC ->
+      flip replicateM get . fromIntegral =<< parseUint16
+    0xDD ->
+      flip replicateM get . fromIntegral =<< parseUint32
+    _ ->
+      fail $ printf "invlid array tag: 0x%02X" c
+
+parseArrayVector :: ObjectGet a => A.Parser (V.Vector a)
+parseArrayVector = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0xF0 == 0x90 ->
+      flip V.replicateM get . fromIntegral $ c .&. 0x0F
+    0xDC ->
+      flip V.replicateM get . fromIntegral =<< parseUint16
+    0xDD ->
+      flip V.replicateM get . fromIntegral =<< parseUint32
+    _ ->
+      fail $ printf "invlid array tag: 0x%02X" c
+
+parseMap :: (ObjectGet k, ObjectGet v) => A.Parser [(k, v)]
+parseMap = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0xF0 == 0x80 ->
+      flip replicateM parsePair . fromIntegral $ c .&. 0x0F
+    0xDE ->
+      flip replicateM parsePair . fromIntegral =<< parseUint16
+    0xDF ->
+      flip replicateM parsePair . fromIntegral =<< parseUint32
+    _ ->
+      fail $ printf "invlid map tag: 0x%02X" c
+
+parseMapVector :: (ObjectGet k, ObjectGet v) => A.Parser (V.Vector (k, v))
+parseMapVector = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0xF0 == 0x80 ->
+      flip V.replicateM parsePair . fromIntegral $ c .&. 0x0F
+    0xDE ->
+      flip V.replicateM parsePair . fromIntegral =<< parseUint16
+    0xDF ->
+      flip V.replicateM parsePair . fromIntegral =<< parseUint32
+    _ ->
+      fail $ printf "invlid map tag: 0x%02X" c
+
+parseObject :: A.Parser Object
+parseObject =
+  A.choice
+  [ liftM ObjectInteger parseInt
+  , liftM (const ObjectNil) parseNil
+  , liftM ObjectBool parseBool
+  , liftM ObjectDouble parseDouble
+  , liftM ObjectRAW parseRAW
+  , liftM ObjectArray parseArray
+  , liftM ObjectMap parseMap
+  ]
+
+parsePair :: (ObjectGet k, ObjectGet v) => A.Parser (k, v)
+parsePair = do
+  a <- get
+  b <- get
+  return (a, b)
+
+parseUint16 :: A.Parser Word16
+parseUint16 = do
+  b0 <- A.anyWord8
+  b1 <- A.anyWord8
+  return $ (fromIntegral b0 `shiftL` 8) .|. fromIntegral b1
+
+parseUint32 :: A.Parser Word32
+parseUint32 = do
+  b0 <- A.anyWord8
+  b1 <- A.anyWord8
+  b2 <- A.anyWord8
+  b3 <- A.anyWord8
+  return $ (fromIntegral b0 `shiftL` 24) .|.
+           (fromIntegral b1 `shiftL` 16) .|.
+           (fromIntegral b2 `shiftL` 8) .|.
+           fromIntegral b3
+
+parseUint64 :: A.Parser Word64
+parseUint64 = do
+  b0 <- A.anyWord8
+  b1 <- A.anyWord8
+  b2 <- A.anyWord8
+  b3 <- A.anyWord8
+  b4 <- A.anyWord8
+  b5 <- A.anyWord8
+  b6 <- A.anyWord8
+  b7 <- A.anyWord8
+  return $ (fromIntegral b0 `shiftL` 56) .|.
+           (fromIntegral b1 `shiftL` 48) .|.
+           (fromIntegral b2 `shiftL` 40) .|.
+           (fromIntegral b3 `shiftL` 32) .|.
+           (fromIntegral b4 `shiftL` 24) .|.
+           (fromIntegral b5 `shiftL` 16) .|.
+           (fromIntegral b6 `shiftL` 8) .|.
+           fromIntegral b7
+
+parseInt8 :: A.Parser Int8
+parseInt8 = return . fromIntegral =<< A.anyWord8
+
+parseInt16 :: A.Parser Int16
+parseInt16 = return . fromIntegral =<< parseUint16
+
+parseInt32 :: A.Parser Int32
+parseInt32 = return . fromIntegral =<< parseUint32
+
+parseInt64 :: A.Parser Int64
+parseInt64 = return . fromIntegral =<< parseUint64
+
+toLBS :: B.ByteString -> L.ByteString
+toLBS bs = L.fromChunks [bs]

From 209d8d058c17b1ee92f13942a804eb2868191118 Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Mon, 6 Sep 2010 13:57:47 +0900
Subject: [PATCH 19/43] forgot to remove file

---
 haskell/src/Data/MessagePack/Packer.hs | 147 -------------------------
 1 file changed, 147 deletions(-)
 delete mode 100644 haskell/src/Data/MessagePack/Packer.hs

diff --git a/haskell/src/Data/MessagePack/Packer.hs b/haskell/src/Data/MessagePack/Packer.hs
deleted file mode 100644
index 9c10f5ed..00000000
--- a/haskell/src/Data/MessagePack/Packer.hs
+++ /dev/null
@@ -1,147 +0,0 @@
-{-# Language FlexibleInstances #-}
-{-# Language OverlappingInstances #-}
-
-module Data.MessagePack.Packer(
-  ObjectPut(..),
-  ) where
-
-import Data.Binary.Put
-import Data.Binary.IEEE754
-import Data.Bits
-import qualified Data.ByteString as B
-
-import Data.MessagePack.Object
-
-class ObjectPut a where
-  put :: a -> Put
-
-instance ObjectPut Object where
-  put = putObject
-
-instance ObjectPut Int where
-  put = putInteger
-
-instance ObjectPut () where
-  put _ = putNil
-
-instance ObjectPut Bool where
-  put = putBool
-
-instance ObjectPut Double where
-  put = putDouble
-
-instance ObjectPut B.ByteString where
-  put = putRAW
-
-instance ObjectPut a => ObjectPut [a] where
-  put = putArray
-
-instance (ObjectPut k, ObjectPut v) => ObjectPut [(k, v)] where
-  put = putMap
-
-putObject :: Object -> Put
-putObject obj =
-  case obj of
-    ObjectInteger n ->
-      putInteger n
-    ObjectNil ->
-      putNil
-    ObjectBool b ->
-      putBool b
-    ObjectDouble d ->
-      putDouble d
-    ObjectRAW raw ->
-      putRAW raw
-    ObjectArray arr ->
-      putArray arr
-    ObjectMap m ->
-      putMap m
-
-putInteger :: Int -> Put      
-putInteger n =
-  case n of
-    _ | n >= 0 && n <= 127 ->
-      putWord8 $ fromIntegral n
-    _ | n >= -32 && n <= -1 ->
-      putWord8 $ fromIntegral n
-    _ | n >= 0 && n < 0x100 -> do
-      putWord8 0xCC
-      putWord8 $ fromIntegral n
-    _ | n >= 0 && n < 0x10000 -> do
-      putWord8 0xCD
-      putWord16be $ fromIntegral n
-    _ | n >= 0 && n < 0x100000000 -> do
-      putWord8 0xCE
-      putWord32be $ fromIntegral n
-    _ | n >= 0 -> do
-      putWord8 0xCF
-      putWord64be $ fromIntegral n
-    _ | n >= -0x100 -> do
-      putWord8 0xD0
-      putWord8 $ fromIntegral n
-    _ | n >= -0x10000 -> do
-      putWord8 0xD1
-      putWord16be $ fromIntegral n
-    _ | n >= -0x100000000 -> do
-      putWord8 0xD2
-      putWord32be $ fromIntegral n
-    _ -> do
-      putWord8 0xD3
-      putWord64be $ fromIntegral n
-
-putNil :: Put
-putNil = putWord8 0xC0
-
-putBool :: Bool -> Put
-putBool True = putWord8 0xC3
-putBool False = putWord8 0xC2
-
-putDouble :: Double -> Put
-putDouble d = do
-  putWord8 0xCB
-  putFloat64be d
-
-putRAW :: B.ByteString -> Put
-putRAW bs = do
-  case len of
-    _ | len <= 31 -> do
-      putWord8 $ 0xA0 .|. fromIntegral len
-    _ | len < 0x10000 -> do
-      putWord8 0xDA
-      putWord16be $ fromIntegral len
-    _ -> do
-      putWord8 0xDB
-      putWord32be $ fromIntegral len
-  putByteString bs
-  where
-    len = B.length bs
-
-putArray :: ObjectPut a => [a] -> Put
-putArray arr = do
-  case len of
-    _ | len <= 15 ->
-      putWord8 $ 0x90 .|. fromIntegral len
-    _ | len < 0x10000 -> do
-      putWord8 0xDC
-      putWord16be $ fromIntegral len
-    _ -> do
-      putWord8 0xDD
-      putWord32be $ fromIntegral len
-  mapM_ put arr
-  where
-    len = length arr
-
-putMap :: (ObjectPut k, ObjectPut v) => [(k, v)] -> Put
-putMap m = do
-  case len of
-    _ | len <= 15 ->
-      putWord8 $ 0x80 .|. fromIntegral len
-    _ | len < 0x10000 -> do
-      putWord8 0xDE
-      putWord16be $ fromIntegral len
-    _ -> do
-      putWord8 0xDF
-      putWord16be $ fromIntegral len
-  mapM_ (\(k, v) -> put k >> put v) m
-  where
-    len = length m

From 799935e44c6f27e81d780b324dd69bdbd71066d5 Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Mon, 6 Sep 2010 14:03:47 +0900
Subject: [PATCH 20/43] haskel: incr version and update infos.

---
 haskell/msgpack.cabal | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/haskell/msgpack.cabal b/haskell/msgpack.cabal
index 8346c1f8..18ae3d86 100644
--- a/haskell/msgpack.cabal
+++ b/haskell/msgpack.cabal
@@ -1,15 +1,15 @@
 Name:               msgpack
-Version:            0.3.0
+Version:            0.3.1
 Synopsis:           A Haskell binding to MessagePack
 Description:
-  A Haskell binding to MessagePack <http://msgpack.sourceforge.jp/>
+  A Haskell binding to MessagePack <http://msgpack.org/>
 
 License:            BSD3
 License-File:       LICENSE
 Category:           Data
 Author:             Hideyuki Tanaka
 Maintainer:         Hideyuki Tanaka <tanaka.hideyuki@gmail.com>
-Homepage:           http://github.com/tanakh/hsmsgpack
+Homepage:           http://github.com/msgpack/msgpack
 Stability:          Experimental
 Tested-with:        GHC == 6.12.3
 Cabal-Version:      >= 1.2

From 802589516870df83cf209191e234266b09b1abee Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Sun, 5 Sep 2010 16:20:37 +0900
Subject: [PATCH 21/43] Checking in changes prior to tagging of version
 0.16_01.

Changelog diff is:
---
 perl/MANIFEST.SKIP           | 2 ++
 perl/lib/Data/MessagePack.pm | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/perl/MANIFEST.SKIP b/perl/MANIFEST.SKIP
index f6340354..71a24e5c 100644
--- a/perl/MANIFEST.SKIP
+++ b/perl/MANIFEST.SKIP
@@ -23,3 +23,5 @@
 \.o$
 \.bs$
 ^Data-MessagePack-[0-9.]+/
+^\.testenv/test_pp.pl
+^ppport.h$
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index d53ff226..4da67ff6 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -3,7 +3,7 @@ use strict;
 use warnings;
 use 5.008001;
 
-our $VERSION = '0.16';
+our $VERSION = '0.16_01';
 our $PreferInteger = 0;
 
 our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };

From e781831032c9091ab7e90bbbd9560828a8b69a30 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Mon, 6 Sep 2010 14:19:31 +0900
Subject: [PATCH 22/43] upgraded docs

---
 perl/README                  | 16 +++++++++++++---
 perl/lib/Data/MessagePack.pm | 15 ++++++++++++---
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/perl/README b/perl/README
index 31aae992..2ef686c2 100644
--- a/perl/README
+++ b/perl/README
@@ -1,12 +1,16 @@
 NAME
-    Data::MessagePack - messagepack
+    Data::MessagePack - MessagePack serialising/deserialising
 
 SYNOPSIS
         my $packed = Data::MessagePack->pack($dat);
         my $unpacked = Data::MessagePack->unpack($dat);
 
 DESCRIPTION
-    Data::MessagePack is a binary packer for perl.
+    This module converts Perl data structures to MessagePack and vice versa.
+
+    MessagePack is a binary-based efficient object serialization format. It
+    enables to exchange structured objects between many languages like JSON.
+    But unlike JSON, it is very fast and small.
 
 METHODS
     my $packed = Data::MessagePack->pack($data);
@@ -22,13 +26,19 @@ Configuration Variables
 AUTHORS
     Tokuhiro Matsuno
 
+    Makamaka Hannyaharamitu
+
 THANKS TO
     Jun Kuriyama
 
+    Dan Kogai
+
+    FURUHASHI Sadayuki
+
 LICENSE
     This library is free software; you can redistribute it and/or modify it
     under the same terms as Perl itself.
 
 SEE ALSO
-    <http://msgpack.sourceforge.jp/>
+    <http://msgpack.org/>
 
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index 4da67ff6..ecdc1e48 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -30,7 +30,7 @@ __END__
 
 =head1 NAME
 
-Data::MessagePack - messagepack
+Data::MessagePack - MessagePack serialising/deserialising
 
 =head1 SYNOPSIS
 
@@ -39,7 +39,10 @@ Data::MessagePack - messagepack
 
 =head1 DESCRIPTION
 
-Data::MessagePack is a binary packer for perl.
+This module converts Perl data structures to MessagePack and vice versa.
+
+MessagePack is a binary-based efficient object serialization format.
+It enables to exchange structured objects between many languages like JSON. But unlike JSON, it is very fast and small.
 
 =head1 METHODS
 
@@ -69,10 +72,16 @@ Pack the string as int when the value looks like int(EXPERIMENTAL).
 
 Tokuhiro Matsuno
 
+Makamaka Hannyaharamitu
+
 =head1 THANKS TO
 
 Jun Kuriyama
 
+Dan Kogai
+
+FURUHASHI Sadayuki
+
 =head1 LICENSE
 
 This library is free software; you can redistribute it and/or modify
@@ -81,5 +90,5 @@ it under the same terms as Perl itself.
 
 =head1 SEE ALSO
 
-L<http://msgpack.sourceforge.jp/>
+L<http://msgpack.org/>
 

From c7555f1c3c471278b320db5ca71e5afdbcb52867 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Mon, 6 Sep 2010 14:31:53 +0900
Subject: [PATCH 23/43] Perl: added link to git repository.

---
 perl/Makefile.PL | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/perl/Makefile.PL b/perl/Makefile.PL
index 783e658d..7958bc6b 100644
--- a/perl/Makefile.PL
+++ b/perl/Makefile.PL
@@ -64,7 +64,7 @@ if($Module::Install::AUTHOR) {
     postamble qq{test :: test_pp\n\n};
 }
 
-auto_set_repository();
+repository('http://github.com/msgpack/msgpack');
 auto_include;
 WriteAll;
 

From 9281dba89672862ddf27384909264f4bd6ec12e8 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Mon, 6 Sep 2010 14:34:04 +0900
Subject: [PATCH 24/43] Checking in changes prior to tagging of version
 0.16_02.

Changelog diff is:

diff --git a/perl/Changes b/perl/Changes
index 9b061cf..68b58ba 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,8 @@
+0.16_02
+
+    - document enhancement(tokuhirom)
+    - M::I::XSUtil 0.26 is broken. use 0.27.
+
 0.16_01

     - added PP version (used in cases PERL_DATA_MESSAGEPACK=pp or fail to load XS).
---
 perl/Changes                 | 5 +++++
 perl/lib/Data/MessagePack.pm | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/perl/Changes b/perl/Changes
index 9b061cfb..68b58ba9 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,8 @@
+0.16_02
+
+    - document enhancement(tokuhirom)
+    - M::I::XSUtil 0.26 is broken. use 0.27.
+
 0.16_01
 
     - added PP version (used in cases PERL_DATA_MESSAGEPACK=pp or fail to load XS).
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index ecdc1e48..79cc5311 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -3,7 +3,7 @@ use strict;
 use warnings;
 use 5.008001;
 
-our $VERSION = '0.16_01';
+our $VERSION = '0.16_02';
 our $PreferInteger = 0;
 
 our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };

From 8b90968cb111be903421083d8f3bebbef23e79c7 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Mon, 6 Sep 2010 14:34:48 +0900
Subject: [PATCH 25/43] Checking in changes prior to tagging of version
 0.16_03.

Changelog diff is:

diff --git a/perl/Changes b/perl/Changes
index 68b58ba..a4a3e36 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,7 @@
+0.16_03
+
+    - no feature changes
+
 0.16_02

     - document enhancement(tokuhirom)
---
 perl/Changes                 | 4 ++++
 perl/lib/Data/MessagePack.pm | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/perl/Changes b/perl/Changes
index 68b58ba9..a4a3e364 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,7 @@
+0.16_03
+
+    - no feature changes
+
 0.16_02
 
     - document enhancement(tokuhirom)
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index 79cc5311..b143e4ae 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -3,7 +3,7 @@ use strict;
 use warnings;
 use 5.008001;
 
-our $VERSION = '0.16_02';
+our $VERSION = '0.16_03';
 our $PreferInteger = 0;
 
 our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };

From c5afe7a5739fa48d207d85403771de4a526ff437 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Mon, 6 Sep 2010 14:35:41 +0900
Subject: [PATCH 26/43] Checking in changes prior to tagging of version
 0.16_04.

Changelog diff is:

diff --git a/perl/Changes b/perl/Changes
index a4a3e36..7910882 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,4 +1,4 @@
-0.16_03
+0.16_04

     - no feature changes
---
 perl/Changes                 | 2 +-
 perl/lib/Data/MessagePack.pm | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/perl/Changes b/perl/Changes
index a4a3e364..79108820 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,4 +1,4 @@
-0.16_03
+0.16_04
 
     - no feature changes
 
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index b143e4ae..b08bac2d 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -3,7 +3,7 @@ use strict;
 use warnings;
 use 5.008001;
 
-our $VERSION = '0.16_03';
+our $VERSION = '0.16_04';
 our $PreferInteger = 0;
 
 our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };

From aca2ba13c2f3ce3bc43897beb0a4a8529bab7a03 Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Mon, 6 Sep 2010 15:37:55 +0900
Subject: [PATCH 27/43] haskell: refactoring

---
 haskell/src/Data/MessagePack/Parser.hs | 246 +++++++++++--------------
 haskell/src/Data/MessagePack/Put.hs    | 232 +++++++++--------------
 2 files changed, 195 insertions(+), 283 deletions(-)

diff --git a/haskell/src/Data/MessagePack/Parser.hs b/haskell/src/Data/MessagePack/Parser.hs
index d0cd0846..312e95f3 100644
--- a/haskell/src/Data/MessagePack/Parser.hs
+++ b/haskell/src/Data/MessagePack/Parser.hs
@@ -40,166 +40,113 @@ class ObjectGet a where
   -- | Deserialize a value
   get :: A.Parser a
 
+instance ObjectGet Object where
+  get =
+    A.choice
+    [ liftM ObjectInteger get
+    , liftM (\() -> ObjectNil) get
+    , liftM ObjectBool get
+    , liftM ObjectDouble get
+    , liftM ObjectRAW get
+    , liftM ObjectArray get
+    , liftM ObjectMap get
+    ]
+
 instance ObjectGet Int where
-  get = parseInt
+  get = do
+    c <- A.anyWord8
+    case c of
+      _ | c .&. 0x80 == 0x00 ->
+        return $ fromIntegral c
+      _ | c .&. 0xE0 == 0xE0 ->
+        return $ fromIntegral (fromIntegral c :: Int8)
+      0xCC ->
+        return . fromIntegral =<< A.anyWord8
+      0xCD ->
+        return . fromIntegral =<< parseUint16
+      0xCE ->
+        return . fromIntegral =<< parseUint32
+      0xCF ->
+        return . fromIntegral =<< parseUint64
+      0xD0 ->
+        return . fromIntegral =<< parseInt8
+      0xD1 ->
+        return . fromIntegral =<< parseInt16
+      0xD2 ->
+        return . fromIntegral =<< parseInt32
+      0xD3 ->
+        return . fromIntegral =<< parseInt64
+      _ ->
+        fail $ printf "invlid integer tag: 0x%02X" c
 
 instance ObjectGet () where
-  get = parseNil
+  get = do
+    c <- A.anyWord8
+    case c of
+      0xC0 ->
+        return ()
+      _ ->
+        fail $ printf "invlid nil tag: 0x%02X" c
 
 instance ObjectGet Bool where
-  get = parseBool
+  get = do
+    c <- A.anyWord8
+    case c of
+      0xC3 ->
+        return True
+      0xC2 ->
+        return False
+      _ ->
+        fail $ printf "invlid bool tag: 0x%02X" c
 
 instance ObjectGet Double where
-  get = parseDouble
+  get = do
+    c <- A.anyWord8
+    case c of
+      0xCA ->
+        return . realToFrac . runGet getFloat32be . toLBS =<< A.take 4
+      0xCB ->
+        return . runGet getFloat64be . toLBS =<< A.take 8
+      _ ->
+        fail $ printf "invlid double tag: 0x%02X" c
 
 instance ObjectGet B.ByteString where
-  get = parseRAW
+  get = do
+    c <- A.anyWord8
+    case c of
+      _ | c .&. 0xE0 == 0xA0 ->
+        A.take . fromIntegral $ c .&. 0x1F
+      0xDA ->
+        A.take . fromIntegral =<< parseUint16
+      0xDB ->
+        A.take . fromIntegral =<< parseUint32
+      _ ->
+        fail $ printf "invlid raw tag: 0x%02X" c
 
 instance ObjectGet a => ObjectGet [a] where
-  get = parseArray
+  get = parseArray (flip replicateM get)
 
 instance ObjectGet a => ObjectGet (V.Vector a) where
-  get = parseArrayVector
+  get = parseArray (flip V.replicateM get)
+
+parseArray :: (Int -> A.Parser a) -> A.Parser a
+parseArray aget = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0xF0 == 0x90 ->
+      aget . fromIntegral $ c .&. 0x0F
+    0xDC ->
+      aget . fromIntegral =<< parseUint16
+    0xDD ->
+      aget . fromIntegral =<< parseUint32
+    _ ->
+      fail $ printf "invlid array tag: 0x%02X" c
 
 instance (ObjectGet k, ObjectGet v) => ObjectGet [(k, v)] where
-  get = parseMap
+  get = parseMap (flip replicateM parsePair)
 
 instance (ObjectGet k, ObjectGet v) => ObjectGet (V.Vector (k, v)) where
-  get = parseMapVector
-
-instance ObjectGet Object where
-  get = parseObject
-
-parseInt :: A.Parser Int
-parseInt = do
-  c <- A.anyWord8
-  case c of
-    _ | c .&. 0x80 == 0x00 ->
-      return $ fromIntegral c
-    _ | c .&. 0xE0 == 0xE0 ->
-      return $ fromIntegral (fromIntegral c :: Int8)      
-    0xCC ->
-      return . fromIntegral =<< A.anyWord8
-    0xCD ->
-      return . fromIntegral =<< parseUint16
-    0xCE ->
-      return . fromIntegral =<< parseUint32
-    0xCF ->
-      return . fromIntegral =<< parseUint64
-    0xD0 ->
-      return . fromIntegral =<< parseInt8
-    0xD1 ->
-      return . fromIntegral =<< parseInt16
-    0xD2 ->
-      return . fromIntegral =<< parseInt32
-    0xD3 ->
-      return . fromIntegral =<< parseInt64
-    _ ->
-      fail $ printf "invlid integer tag: 0x%02X" c
-
-parseNil :: A.Parser ()
-parseNil = do
-  _ <- A.word8 0xC0
-  return ()
-
-parseBool :: A.Parser Bool
-parseBool = do
-  c <- A.anyWord8
-  case c of
-    0xC3 ->
-      return True
-    0xC2 ->
-      return False
-    _ ->
-      fail $ printf "invlid bool tag: 0x%02X" c
-
-parseDouble :: A.Parser Double
-parseDouble = do
-  c <- A.anyWord8
-  case c of
-    0xCA ->
-      return . realToFrac . runGet getFloat32be . toLBS =<< A.take 4
-    0xCB ->
-      return . runGet getFloat64be . toLBS =<< A.take 8
-    _ ->
-      fail $ printf "invlid double tag: 0x%02X" c
-
-parseRAW :: A.Parser B.ByteString
-parseRAW = do
-  c <- A.anyWord8
-  case c of
-    _ | c .&. 0xE0 == 0xA0 ->
-      A.take . fromIntegral $ c .&. 0x1F
-    0xDA ->
-      A.take . fromIntegral =<< parseUint16
-    0xDB ->
-      A.take . fromIntegral =<< parseUint32
-    _ ->
-      fail $ printf "invlid raw tag: 0x%02X" c
-  
-parseArray :: ObjectGet a => A.Parser [a]
-parseArray = do
-  c <- A.anyWord8
-  case c of
-    _ | c .&. 0xF0 == 0x90 ->
-      flip replicateM get . fromIntegral $ c .&. 0x0F
-    0xDC ->
-      flip replicateM get . fromIntegral =<< parseUint16
-    0xDD ->
-      flip replicateM get . fromIntegral =<< parseUint32
-    _ ->
-      fail $ printf "invlid array tag: 0x%02X" c
-
-parseArrayVector :: ObjectGet a => A.Parser (V.Vector a)
-parseArrayVector = do
-  c <- A.anyWord8
-  case c of
-    _ | c .&. 0xF0 == 0x90 ->
-      flip V.replicateM get . fromIntegral $ c .&. 0x0F
-    0xDC ->
-      flip V.replicateM get . fromIntegral =<< parseUint16
-    0xDD ->
-      flip V.replicateM get . fromIntegral =<< parseUint32
-    _ ->
-      fail $ printf "invlid array tag: 0x%02X" c
-
-parseMap :: (ObjectGet k, ObjectGet v) => A.Parser [(k, v)]
-parseMap = do
-  c <- A.anyWord8
-  case c of
-    _ | c .&. 0xF0 == 0x80 ->
-      flip replicateM parsePair . fromIntegral $ c .&. 0x0F
-    0xDE ->
-      flip replicateM parsePair . fromIntegral =<< parseUint16
-    0xDF ->
-      flip replicateM parsePair . fromIntegral =<< parseUint32
-    _ ->
-      fail $ printf "invlid map tag: 0x%02X" c
-
-parseMapVector :: (ObjectGet k, ObjectGet v) => A.Parser (V.Vector (k, v))
-parseMapVector = do
-  c <- A.anyWord8
-  case c of
-    _ | c .&. 0xF0 == 0x80 ->
-      flip V.replicateM parsePair . fromIntegral $ c .&. 0x0F
-    0xDE ->
-      flip V.replicateM parsePair . fromIntegral =<< parseUint16
-    0xDF ->
-      flip V.replicateM parsePair . fromIntegral =<< parseUint32
-    _ ->
-      fail $ printf "invlid map tag: 0x%02X" c
-
-parseObject :: A.Parser Object
-parseObject =
-  A.choice
-  [ liftM ObjectInteger parseInt
-  , liftM (const ObjectNil) parseNil
-  , liftM ObjectBool parseBool
-  , liftM ObjectDouble parseDouble
-  , liftM ObjectRAW parseRAW
-  , liftM ObjectArray parseArray
-  , liftM ObjectMap parseMap
-  ]
+  get = parseMap (flip V.replicateM parsePair)
 
 parsePair :: (ObjectGet k, ObjectGet v) => A.Parser (k, v)
 parsePair = do
@@ -207,6 +154,19 @@ parsePair = do
   b <- get
   return (a, b)
 
+parseMap :: (Int -> A.Parser a) -> A.Parser a
+parseMap aget = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0xF0 == 0x80 ->
+      aget . fromIntegral $ c .&. 0x0F
+    0xDE ->
+      aget . fromIntegral =<< parseUint16
+    0xDF ->
+      aget . fromIntegral =<< parseUint32
+    _ ->
+      fail $ printf "invlid map tag: 0x%02X" c
+
 parseUint16 :: A.Parser Word16
 parseUint16 = do
   b0 <- A.anyWord8
diff --git a/haskell/src/Data/MessagePack/Put.hs b/haskell/src/Data/MessagePack/Put.hs
index 8d0af2b2..95582dd8 100644
--- a/haskell/src/Data/MessagePack/Put.hs
+++ b/haskell/src/Data/MessagePack/Put.hs
@@ -35,168 +35,120 @@ class ObjectPut a where
   put :: a -> Put
 
 instance ObjectPut Object where
-  put = putObject
+  put obj =
+    case obj of
+      ObjectInteger n ->
+        put n
+      ObjectNil ->
+        put ()
+      ObjectBool b ->
+        put b
+      ObjectDouble d ->
+        put d
+      ObjectRAW raw ->
+        put raw
+      ObjectArray arr ->
+        put arr
+      ObjectMap m ->
+        put m
 
 instance ObjectPut Int where
-  put = putInteger
+  put n =
+    case n of
+      _ | n >= 0 && n <= 127 ->
+        putWord8 $ fromIntegral n
+      _ | n >= -32 && n <= -1 ->
+        putWord8 $ fromIntegral n
+      _ | n >= 0 && n < 0x100 -> do
+        putWord8 0xCC
+        putWord8 $ fromIntegral n
+      _ | n >= 0 && n < 0x10000 -> do
+        putWord8 0xCD
+        putWord16be $ fromIntegral n
+      _ | n >= 0 && n < 0x100000000 -> do
+        putWord8 0xCE
+        putWord32be $ fromIntegral n
+      _ | n >= 0 -> do
+        putWord8 0xCF
+        putWord64be $ fromIntegral n
+      _ | n >= -0x80 -> do
+        putWord8 0xD0
+        putWord8 $ fromIntegral n
+      _ | n >= -0x8000 -> do
+        putWord8 0xD1
+        putWord16be $ fromIntegral n
+      _ | n >= -0x80000000 -> do
+        putWord8 0xD2
+        putWord32be $ fromIntegral n
+      _ -> do
+        putWord8 0xD3
+        putWord64be $ fromIntegral n
 
 instance ObjectPut () where
-  put _ = putNil
+  put _ = 
+    putWord8 0xC0
 
 instance ObjectPut Bool where
-  put = putBool
+  put True = putWord8 0xC3
+  put False = putWord8 0xC2
 
 instance ObjectPut Double where
-  put = putDouble
+  put d = do
+    putWord8 0xCB
+    putFloat64be d
 
 instance ObjectPut B.ByteString where
-  put = putRAW
+  put bs = do
+    case len of
+      _ | len <= 31 -> do
+        putWord8 $ 0xA0 .|. fromIntegral len
+      _ | len < 0x10000 -> do
+        putWord8 0xDA
+        putWord16be $ fromIntegral len
+      _ -> do
+        putWord8 0xDB
+        putWord32be $ fromIntegral len
+    putByteString bs
+    where
+      len = B.length bs
 
 instance ObjectPut a => ObjectPut [a] where
-  put = putArray
+  put = putArray length (mapM_ put)
 
 instance ObjectPut a => ObjectPut (V.Vector a) where
-  put = putArrayVector
+  put = putArray V.length (V.mapM_ put)
+
+putArray :: (a -> Int) -> (a -> Put) -> a -> Put
+putArray lf pf arr = do
+  case lf arr of
+    len | len <= 15 ->
+      putWord8 $ 0x90 .|. fromIntegral len
+    len | len < 0x10000 -> do
+      putWord8 0xDC
+      putWord16be $ fromIntegral len
+    len -> do
+      putWord8 0xDD
+      putWord32be $ fromIntegral len
+  pf arr
 
 instance (ObjectPut k, ObjectPut v) => ObjectPut [(k, v)] where
-  put = putMap
+  put = putMap length (mapM_ putPair)
 
 instance (ObjectPut k, ObjectPut v) => ObjectPut (V.Vector (k, v)) where
-  put = putMapVector
+  put = putMap V.length (V.mapM_ putPair)
 
-putObject :: Object -> Put
-putObject obj =
-  case obj of
-    ObjectInteger n ->
-      putInteger n
-    ObjectNil ->
-      putNil
-    ObjectBool b ->
-      putBool b
-    ObjectDouble d ->
-      putDouble d
-    ObjectRAW raw ->
-      putRAW raw
-    ObjectArray arr ->
-      putArray arr
-    ObjectMap m ->
-      putMap m
+putPair :: (ObjectPut a, ObjectPut b) => (a, b) -> Put
+putPair (a, b) = put a >> put b
 
-putInteger :: Int -> Put      
-putInteger n =
-  case n of
-    _ | n >= 0 && n <= 127 ->
-      putWord8 $ fromIntegral n
-    _ | n >= -32 && n <= -1 ->
-      putWord8 $ fromIntegral n
-    _ | n >= 0 && n < 0x100 -> do
-      putWord8 0xCC
-      putWord8 $ fromIntegral n
-    _ | n >= 0 && n < 0x10000 -> do
-      putWord8 0xCD
-      putWord16be $ fromIntegral n
-    _ | n >= 0 && n < 0x100000000 -> do
-      putWord8 0xCE
-      putWord32be $ fromIntegral n
-    _ | n >= 0 -> do
-      putWord8 0xCF
-      putWord64be $ fromIntegral n
-    _ | n >= -0x80 -> do
-      putWord8 0xD0
-      putWord8 $ fromIntegral n
-    _ | n >= -0x8000 -> do
-      putWord8 0xD1
-      putWord16be $ fromIntegral n
-    _ | n >= -0x80000000 -> do
-      putWord8 0xD2
-      putWord32be $ fromIntegral n
-    _ -> do
-      putWord8 0xD3
-      putWord64be $ fromIntegral n
-
-putNil :: Put
-putNil = putWord8 0xC0
-
-putBool :: Bool -> Put
-putBool True = putWord8 0xC3
-putBool False = putWord8 0xC2
-
-putDouble :: Double -> Put
-putDouble d = do
-  putWord8 0xCB
-  putFloat64be d
-
-putRAW :: B.ByteString -> Put
-putRAW bs = do
-  case len of
-    _ | len <= 31 -> do
-      putWord8 $ 0xA0 .|. fromIntegral len
-    _ | len < 0x10000 -> do
-      putWord8 0xDA
-      putWord16be $ fromIntegral len
-    _ -> do
-      putWord8 0xDB
-      putWord32be $ fromIntegral len
-  putByteString bs
-  where
-    len = B.length bs
-
-putArray :: ObjectPut a => [a] -> Put
-putArray arr = do
-  case len of
-    _ | len <= 15 ->
-      putWord8 $ 0x90 .|. fromIntegral len
-    _ | len < 0x10000 -> do
-      putWord8 0xDC
-      putWord16be $ fromIntegral len
-    _ -> do
-      putWord8 0xDD
-      putWord32be $ fromIntegral len
-  mapM_ put arr
-  where
-    len = length arr
-
-putArrayVector :: ObjectPut a => V.Vector a -> Put
-putArrayVector arr = do
-  case len of
-    _ | len <= 15 ->
-      putWord8 $ 0x90 .|. fromIntegral len
-    _ | len < 0x10000 -> do
-      putWord8 0xDC
-      putWord16be $ fromIntegral len
-    _ -> do
-      putWord8 0xDD
-      putWord32be $ fromIntegral len
-  V.mapM_ put arr
-  where
-    len = V.length arr
-
-putMap :: (ObjectPut k, ObjectPut v) => [(k, v)] -> Put
-putMap m = do
-  case len of
-    _ | len <= 15 ->
+putMap :: (a -> Int) -> (a -> Put) -> a -> Put
+putMap lf pf m = do
+  case lf m of
+    len | len <= 15 ->
       putWord8 $ 0x80 .|. fromIntegral len
-    _ | len < 0x10000 -> do
+    len | len < 0x10000 -> do
       putWord8 0xDE
       putWord16be $ fromIntegral len
-    _ -> do
+    len -> do
       putWord8 0xDF
       putWord32be $ fromIntegral len
-  mapM_ (\(k, v) -> put k >> put v) m
-  where
-    len = length m
-
-putMapVector :: (ObjectPut k, ObjectPut v) => V.Vector (k, v) -> Put
-putMapVector m = do
-  case len of
-    _ | len <= 15 ->
-      putWord8 $ 0x80 .|. fromIntegral len
-    _ | len < 0x10000 -> do
-      putWord8 0xDE
-      putWord16be $ fromIntegral len
-    _ -> do
-      putWord8 0xDF
-      putWord32be $ fromIntegral len
-  V.mapM_ (\(k, v) -> put k >> put v) m
-  where
-    len = V.length m
+  pf m

From 9e50ba6ec6f48071a5cc31b44864194446b9aa6f Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Mon, 6 Sep 2010 16:33:36 +0900
Subject: [PATCH 28/43] haskell: instance tupples and String and lazy
 ByteString

---
 haskell/src/Data/MessagePack/Parser.hs | 73 ++++++++++++++++++++++----
 haskell/src/Data/MessagePack/Put.hs    | 68 +++++++++++++++++++-----
 haskell/test/Test.hs                   | 25 +++++++--
 3 files changed, 139 insertions(+), 27 deletions(-)

diff --git a/haskell/src/Data/MessagePack/Parser.hs b/haskell/src/Data/MessagePack/Parser.hs
index 312e95f3..200ad962 100644
--- a/haskell/src/Data/MessagePack/Parser.hs
+++ b/haskell/src/Data/MessagePack/Parser.hs
@@ -1,6 +1,7 @@
 {-# Language FlexibleInstances #-}
 {-# Language IncoherentInstances #-}
 {-# Language OverlappingInstances #-}
+{-# Language TypeSynonymInstances #-}
 
 --------------------------------------------------------------------
 -- |
@@ -27,6 +28,7 @@ import Data.Binary.Get
 import Data.Binary.IEEE754
 import Data.Bits
 import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8
 import qualified Data.ByteString.Lazy as L
 import Data.Int
 import qualified Data.Vector as V
@@ -110,18 +112,27 @@ instance ObjectGet Double where
       _ ->
         fail $ printf "invlid double tag: 0x%02X" c
 
+instance ObjectGet String where
+  get = parseString (\n -> return . B8.unpack =<< A.take n)
+
 instance ObjectGet B.ByteString where
-  get = do
-    c <- A.anyWord8
-    case c of
-      _ | c .&. 0xE0 == 0xA0 ->
-        A.take . fromIntegral $ c .&. 0x1F
-      0xDA ->
-        A.take . fromIntegral =<< parseUint16
-      0xDB ->
-        A.take . fromIntegral =<< parseUint32
-      _ ->
-        fail $ printf "invlid raw tag: 0x%02X" c
+  get = parseString A.take
+
+instance ObjectGet L.ByteString where
+  get = parseString (\n -> do bs <- A.take n; return $ L.fromChunks [bs])
+
+parseString :: (Int -> A.Parser a) -> A.Parser a
+parseString aget = do
+  c <- A.anyWord8
+  case c of
+    _ | c .&. 0xE0 == 0xA0 ->
+      aget . fromIntegral $ c .&. 0x1F
+    0xDA ->
+      aget . fromIntegral =<< parseUint16
+    0xDB ->
+      aget . fromIntegral =<< parseUint32
+    _ ->
+      fail $ printf "invlid raw tag: 0x%02X" c
 
 instance ObjectGet a => ObjectGet [a] where
   get = parseArray (flip replicateM get)
@@ -129,6 +140,46 @@ instance ObjectGet a => ObjectGet [a] where
 instance ObjectGet a => ObjectGet (V.Vector a) where
   get = parseArray (flip V.replicateM get)
 
+instance (ObjectGet a1, ObjectGet a2) => ObjectGet (a1, a2) where
+  get = parseArray f where
+    f 2 = get >>= \a1 -> get >>= \a2 -> return (a1, a2)
+    f n = fail $ printf "wrong tupple size: expected 2 but got " n
+
+instance (ObjectGet a1, ObjectGet a2, ObjectGet a3) => ObjectGet (a1, a2, a3) where
+  get = parseArray f where
+    f 3 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> return (a1, a2, a3)
+    f n = fail $ printf "wrong tupple size: expected 3 but got " n
+
+instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4) => ObjectGet (a1, a2, a3, a4) where
+  get = parseArray f where
+    f 4 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> return (a1, a2, a3, a4)
+    f n = fail $ printf "wrong tupple size: expected 4 but got " n
+
+instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5) => ObjectGet (a1, a2, a3, a4, a5) where
+  get = parseArray f where
+    f 5 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> return (a1, a2, a3, a4, a5)
+    f n = fail $ printf "wrong tupple size: expected 5 but got " n
+
+instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5, ObjectGet a6) => ObjectGet (a1, a2, a3, a4, a5, a6) where
+  get = parseArray f where
+    f 6 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> return (a1, a2, a3, a4, a5, a6)
+    f n = fail $ printf "wrong tupple size: expected 6 but got " n
+
+instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5, ObjectGet a6, ObjectGet a7) => ObjectGet (a1, a2, a3, a4, a5, a6, a7) where
+  get = parseArray f where
+    f 7 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> get >>= \a7 -> return (a1, a2, a3, a4, a5, a6, a7)
+    f n = fail $ printf "wrong tupple size: expected 7 but got " n
+
+instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5, ObjectGet a6, ObjectGet a7, ObjectGet a8) => ObjectGet (a1, a2, a3, a4, a5, a6, a7, a8) where
+  get = parseArray f where
+    f 8 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> get >>= \a7 -> get >>= \a8 -> return (a1, a2, a3, a4, a5, a6, a7, a8)
+    f n = fail $ printf "wrong tupple size: expected 8 but got " n
+
+instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5, ObjectGet a6, ObjectGet a7, ObjectGet a8, ObjectGet a9) => ObjectGet (a1, a2, a3, a4, a5, a6, a7, a8, a9) where
+  get = parseArray f where
+    f 9 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> get >>= \a7 -> get >>= \a8 -> get >>= \a9 -> return (a1, a2, a3, a4, a5, a6, a7, a8, a9)
+    f n = fail $ printf "wrong tupple size: expected 9 but got " n
+
 parseArray :: (Int -> A.Parser a) -> A.Parser a
 parseArray aget = do
   c <- A.anyWord8
diff --git a/haskell/src/Data/MessagePack/Put.hs b/haskell/src/Data/MessagePack/Put.hs
index 95582dd8..24ec3059 100644
--- a/haskell/src/Data/MessagePack/Put.hs
+++ b/haskell/src/Data/MessagePack/Put.hs
@@ -1,6 +1,7 @@
 {-# Language FlexibleInstances #-}
 {-# Language IncoherentInstances #-}
 {-# Language OverlappingInstances #-}
+{-# Language TypeSynonymInstances #-}
 
 --------------------------------------------------------------------
 -- |
@@ -25,6 +26,8 @@ import Data.Binary.Put
 import Data.Binary.IEEE754
 import Data.Bits
 import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8
+import qualified Data.ByteString.Lazy as L
 import qualified Data.Vector as V
 
 import Data.MessagePack.Object
@@ -97,20 +100,27 @@ instance ObjectPut Double where
     putWord8 0xCB
     putFloat64be d
 
+instance ObjectPut String where
+  put = putString length (putByteString . B8.pack)
+
 instance ObjectPut B.ByteString where
-  put bs = do
-    case len of
-      _ | len <= 31 -> do
-        putWord8 $ 0xA0 .|. fromIntegral len
-      _ | len < 0x10000 -> do
-        putWord8 0xDA
-        putWord16be $ fromIntegral len
-      _ -> do
-        putWord8 0xDB
-        putWord32be $ fromIntegral len
-    putByteString bs
-    where
-      len = B.length bs
+  put = putString B.length putByteString
+
+instance ObjectPut L.ByteString where
+  put = putString (fromIntegral . L.length) putLazyByteString
+
+putString :: (s -> Int) -> (s -> Put) -> s -> Put
+putString lf pf str = do
+  case lf str of
+    len | len <= 31 -> do
+      putWord8 $ 0xA0 .|. fromIntegral len
+    len | len < 0x10000 -> do
+      putWord8 0xDA
+      putWord16be $ fromIntegral len
+    len -> do
+      putWord8 0xDB
+      putWord32be $ fromIntegral len
+  pf str
 
 instance ObjectPut a => ObjectPut [a] where
   put = putArray length (mapM_ put)
@@ -118,6 +128,38 @@ instance ObjectPut a => ObjectPut [a] where
 instance ObjectPut a => ObjectPut (V.Vector a) where
   put = putArray V.length (V.mapM_ put)
 
+instance (ObjectPut a1, ObjectPut a2) => ObjectPut (a1, a2) where
+  put = putArray (const 2) f where
+    f (a1, a2) = put a1 >> put a2
+
+instance (ObjectPut a1, ObjectPut a2, ObjectPut a3) => ObjectPut (a1, a2, a3) where
+  put = putArray (const 3) f where
+    f (a1, a2, a3) = put a1 >> put a2 >> put a3
+
+instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4) => ObjectPut (a1, a2, a3, a4) where
+  put = putArray (const 4) f where
+    f (a1, a2, a3, a4) = put a1 >> put a2 >> put a3 >> put a4
+
+instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5) => ObjectPut (a1, a2, a3, a4, a5) where
+  put = putArray (const 5) f where
+    f (a1, a2, a3, a4, a5) = put a1 >> put a2 >> put a3 >> put a4 >> put a5
+
+instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5, ObjectPut a6) => ObjectPut (a1, a2, a3, a4, a5, a6) where
+  put = putArray (const 6) f where
+    f (a1, a2, a3, a4, a5, a6) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6
+
+instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5, ObjectPut a6, ObjectPut a7) => ObjectPut (a1, a2, a3, a4, a5, a6, a7) where
+  put = putArray (const 7) f where
+    f (a1, a2, a3, a4, a5, a6, a7) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7
+
+instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5, ObjectPut a6, ObjectPut a7, ObjectPut a8) => ObjectPut (a1, a2, a3, a4, a5, a6, a7, a8) where
+  put = putArray (const 8) f where
+    f (a1, a2, a3, a4, a5, a6, a7, a8) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7 >> put a8
+
+instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5, ObjectPut a6, ObjectPut a7, ObjectPut a8, ObjectPut a9) => ObjectPut (a1, a2, a3, a4, a5, a6, a7, a8, a9) where
+  put = putArray (const 9) f where
+    f (a1, a2, a3, a4, a5, a6, a7, a8, a9) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7 >> put a8 >> put a9
+
 putArray :: (a -> Int) -> (a -> Put) -> a -> Put
 putArray lf pf arr = do
   case lf arr of
diff --git a/haskell/test/Test.hs b/haskell/test/Test.hs
index 1bb551c1..a73ac9ab 100644
--- a/haskell/test/Test.hs
+++ b/haskell/test/Test.hs
@@ -4,6 +4,7 @@ import Test.QuickCheck
 
 import Control.Monad
 import qualified Data.ByteString.Char8 as B
+import qualified Data.ByteString.Lazy.Char8 as L
 import Data.MessagePack
 
 mid :: (ObjectGet a, ObjectPut a) => a -> a
@@ -17,15 +18,27 @@ prop_mid_bool a = a == mid a
   where types = a :: Bool
 prop_mid_double a = a == mid a
   where types = a :: Double
-prop_mid_string a = a == B.unpack (mid (B.pack a))
+prop_mid_string a = a == mid a
+  where types = a :: String
+prop_mid_bytestring a = B.pack a == mid (B.pack a)
+  where types = a :: String
+prop_mid_lazy_bytestring a = (L.pack a) == mid (L.pack a)
   where types = a :: String
 prop_mid_array_int a = a == mid a
   where types = a :: [Int]
-prop_mid_array_string a = a == map B.unpack (mid (map B.pack a))
+prop_mid_array_string a = a == mid a
   where types = a :: [String]
+prop_mid_pair2 a = a == mid a
+  where types = a :: (Int, Int)
+prop_mid_pair3 a = a == mid a
+  where types = a :: (Int, Int, Int)
+prop_mid_pair4 a = a == mid a
+  where types = a :: (Int, Int, Int, Int)
+prop_mid_pair5 a = a == mid a
+  where types = a :: (Int, Int, Int, Int, Int)
 prop_mid_map_int_double a = a == mid a
   where types = a :: [(Int, Double)]
-prop_mid_map_string_string a = a == map (\(x, y) -> (B.unpack x, B.unpack y)) (mid (map (\(x, y) -> (B.pack x, B.pack y)) a))
+prop_mid_map_string_string a = a == mid a
   where types = a :: [(String, String)]
 
 tests =
@@ -35,8 +48,14 @@ tests =
     , testProperty "bool" prop_mid_bool
     , testProperty "double" prop_mid_double
     , testProperty "string" prop_mid_string
+    , testProperty "bytestring" prop_mid_bytestring
+    , testProperty "lazy-bytestring" prop_mid_lazy_bytestring
     , testProperty "[int]" prop_mid_array_int
     , testProperty "[string]" prop_mid_array_string
+    , testProperty "(int, int)" prop_mid_pair2
+    , testProperty "(int, int, int)" prop_mid_pair3
+    , testProperty "(int, int, int, int)" prop_mid_pair4
+    , testProperty "(int, int, int, int, int)" prop_mid_pair5
     , testProperty "[(int, double)]" prop_mid_map_int_double
     , testProperty "[(string, string)]" prop_mid_map_string_string
     ]

From b75db110dceef9bf75c8410ca4b4fc031e1aad89 Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Mon, 6 Sep 2010 17:00:22 +0900
Subject: [PATCH 29/43] haskell: add Iteratee interface

---
 haskell/msgpack.cabal                    |  1 +
 haskell/src/Data/MessagePack.hs          | 45 ++++++++++++-----------
 haskell/src/Data/MessagePack/Iteratee.hs | 46 ++++++++++++++++++++++++
 3 files changed, 72 insertions(+), 20 deletions(-)
 create mode 100644 haskell/src/Data/MessagePack/Iteratee.hs

diff --git a/haskell/msgpack.cabal b/haskell/msgpack.cabal
index 18ae3d86..3baff77f 100644
--- a/haskell/msgpack.cabal
+++ b/haskell/msgpack.cabal
@@ -33,3 +33,4 @@ Library
     Data.MessagePack.Object
     Data.MessagePack.Put
     Data.MessagePack.Parser
+    Data.MessagePack.Iteratee
diff --git a/haskell/src/Data/MessagePack.hs b/haskell/src/Data/MessagePack.hs
index 010eaab0..92353c53 100644
--- a/haskell/src/Data/MessagePack.hs
+++ b/haskell/src/Data/MessagePack.hs
@@ -16,6 +16,7 @@ module Data.MessagePack(
   module Data.MessagePack.Object,
   module Data.MessagePack.Put,
   module Data.MessagePack.Parser,
+  module Data.MessagePack.Iteratee,
   
   -- * Simple functions of Pack and Unpack
   pack,
@@ -30,6 +31,9 @@ module Data.MessagePack(
   unpackFromString,
   unpackFromHandle,
   unpackFromFile,
+  unpackFromStringI,
+  unpackFromHandleI,
+  unpackFromFileI,
   
   ) where
 
@@ -47,6 +51,7 @@ import System.IO
 import Data.MessagePack.Object
 import Data.MessagePack.Put
 import Data.MessagePack.Parser
+import Data.MessagePack.Iteratee
 
 bufferSize :: Int
 bufferSize = 4 * 1024
@@ -67,7 +72,7 @@ pack = packToString . put
 -- | Unpack MessagePack string to Haskell data.
 unpack :: (ObjectGet a, IsByteString s) => s -> a
 unpack bs =
-  runIdentity $ I.run $ I.joinIM $ I.enumPure1Chunk (toBS bs) (parserToIteratee get)
+  runIdentity $ I.run $ I.joinIM $ I.enumPure1Chunk (toBS bs) getI
 
 -- TODO: tryUnpack
 
@@ -86,32 +91,32 @@ packToFile path = L.writeFile path . packToString
 -- | Unpack from ByteString
 unpackFromString :: (Monad m, IsByteString s) => s -> A.Parser a -> m a
 unpackFromString bs =
-  I.run . I.joinIM . I.enumPure1Chunk (toBS bs) . parserToIteratee
+  unpackFromStringI bs . parserToIteratee
 
 -- | Unpack from Handle
 unpackFromHandle :: CIO.MonadCatchIO m => Handle -> A.Parser a -> m a
 unpackFromHandle h =
-  I.run . I.joinIM . I.enumHandle bufferSize h . parserToIteratee
+  unpackFromHandleI h .parserToIteratee
 
 -- | Unpack from File
 unpackFromFile :: CIO.MonadCatchIO m => FilePath -> A.Parser a -> m a
-unpackFromFile path p =
+unpackFromFile path =
+  unpackFromFileI path . parserToIteratee
+
+-- | Iteratee interface to unpack from ByteString
+unpackFromStringI :: (Monad m, IsByteString s) => s -> I.Iteratee B.ByteString m a -> m a
+unpackFromStringI bs =
+  I.run . I.joinIM . I.enumPure1Chunk (toBS bs)
+
+-- | Iteratee interface to unpack from Handle
+unpackFromHandleI :: CIO.MonadCatchIO m => Handle -> I.Iteratee B.ByteString m a -> m a
+unpackFromHandleI h =
+  I.run . I.joinIM . I.enumHandle bufferSize h
+
+-- | Iteratee interface to unpack from File
+unpackFromFileI :: CIO.MonadCatchIO m => FilePath -> I.Iteratee B.ByteString m a -> m a
+unpackFromFileI path p =
   CIO.bracket
   (liftIO $ openBinaryFile path ReadMode)
   (liftIO . hClose)
-  (flip unpackFromHandle p)
-
-parserToIteratee :: Monad m => A.Parser a -> I.Iteratee B.ByteString m a
-parserToIteratee p = I.icont (itr (A.parse p)) Nothing
-  where
-    itr pcont s = case s of
-      I.EOF _ ->
-        I.throwErr (I.setEOF s)
-      I.Chunk bs ->
-        case pcont bs of
-          A.Fail _ _ msg ->
-            I.throwErr (I.iterStrExc msg)
-          A.Partial cont ->
-            I.icont (itr cont) Nothing
-          A.Done remain ret ->
-            I.idone ret (I.Chunk remain)
+  (flip unpackFromHandleI p)
diff --git a/haskell/src/Data/MessagePack/Iteratee.hs b/haskell/src/Data/MessagePack/Iteratee.hs
new file mode 100644
index 00000000..789b714a
--- /dev/null
+++ b/haskell/src/Data/MessagePack/Iteratee.hs
@@ -0,0 +1,46 @@
+--------------------------------------------------------------------
+-- |
+-- Module    : Data.MessagePack.Iteratee
+-- Copyright : (c) Hideyuki Tanaka, 2009-2010
+-- License   : BSD3
+--
+-- Maintainer:  tanaka.hideyuki@gmail.com
+-- Stability :  experimental
+-- Portability: portable
+--
+-- MessagePack Deserializer interface to @Data.Iteratee@
+--
+--------------------------------------------------------------------
+
+module Data.MessagePack.Iteratee(
+  -- * Iteratee version of deserializer
+  getI,
+  -- * Convert Parser to Iteratee
+  parserToIteratee,
+  ) where
+
+import qualified Data.Attoparsec as A
+import qualified Data.ByteString as B
+import qualified Data.Iteratee as I
+
+import Data.MessagePack.Parser
+
+-- | Deserialize a value
+getI :: (Monad m, ObjectGet a) => I.Iteratee B.ByteString m a
+getI = parserToIteratee get
+
+-- | Convert Parser to Iteratee
+parserToIteratee :: Monad m => A.Parser a -> I.Iteratee B.ByteString m a
+parserToIteratee p = I.icont (itr (A.parse p)) Nothing
+  where
+    itr pcont s = case s of
+      I.EOF _ ->
+        I.throwErr (I.setEOF s)
+      I.Chunk bs ->
+        case pcont bs of
+          A.Fail _ _ msg ->
+            I.throwErr (I.iterStrExc msg)
+          A.Partial cont ->
+            I.icont (itr cont) Nothing
+          A.Done remain ret ->
+            I.idone ret (I.Chunk remain)

From dfe19d308caa43e8d763750faafc2baade7d013c Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Mon, 6 Sep 2010 18:14:47 +0900
Subject: [PATCH 30/43] haskell: add overlapping instances

---
 haskell/src/Data/MessagePack/Object.hs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/haskell/src/Data/MessagePack/Object.hs b/haskell/src/Data/MessagePack/Object.hs
index 19a3aeba..df0e89dd 100644
--- a/haskell/src/Data/MessagePack/Object.hs
+++ b/haskell/src/Data/MessagePack/Object.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE TypeSynonymInstances #-}
-{-# LANGUAGE FlexibleInstances #-}
+{-# Language TypeSynonymInstances #-}
+{-# Language FlexibleInstances #-}
+{-# Language OverlappingInstances #-}
 
 --------------------------------------------------------------------
 -- |

From c6424c2ce71f3e79e8aacfe9c76846cf94e168de Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Mon, 6 Sep 2010 23:27:50 +0900
Subject: [PATCH 31/43] haskell: nonblocking enumerator

---
 haskell/src/Data/MessagePack.hs          |  3 +-
 haskell/src/Data/MessagePack/Iteratee.hs | 36 ++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/haskell/src/Data/MessagePack.hs b/haskell/src/Data/MessagePack.hs
index 92353c53..b53066b1 100644
--- a/haskell/src/Data/MessagePack.hs
+++ b/haskell/src/Data/MessagePack.hs
@@ -45,7 +45,6 @@ import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as L
 import Data.Functor.Identity
 import qualified Data.Iteratee as I
-import qualified Data.Iteratee.IO as I
 import System.IO
 
 import Data.MessagePack.Object
@@ -111,7 +110,7 @@ unpackFromStringI bs =
 -- | Iteratee interface to unpack from Handle
 unpackFromHandleI :: CIO.MonadCatchIO m => Handle -> I.Iteratee B.ByteString m a -> m a
 unpackFromHandleI h =
-  I.run . I.joinIM . I.enumHandle bufferSize h
+  I.run . I.joinIM . enumHandleNonBlocking bufferSize h
 
 -- | Iteratee interface to unpack from File
 unpackFromFileI :: CIO.MonadCatchIO m => FilePath -> I.Iteratee B.ByteString m a -> m a
diff --git a/haskell/src/Data/MessagePack/Iteratee.hs b/haskell/src/Data/MessagePack/Iteratee.hs
index 789b714a..4258cf68 100644
--- a/haskell/src/Data/MessagePack/Iteratee.hs
+++ b/haskell/src/Data/MessagePack/Iteratee.hs
@@ -15,13 +15,18 @@
 module Data.MessagePack.Iteratee(
   -- * Iteratee version of deserializer
   getI,
+  -- * Non Blocking Enumerator
+  enumHandleNonBlocking,
   -- * Convert Parser to Iteratee
   parserToIteratee,
   ) where
 
+import Control.Exception
+import Control.Monad.IO.Class
 import qualified Data.Attoparsec as A
 import qualified Data.ByteString as B
 import qualified Data.Iteratee as I
+import System.IO
 
 import Data.MessagePack.Parser
 
@@ -29,6 +34,37 @@ import Data.MessagePack.Parser
 getI :: (Monad m, ObjectGet a) => I.Iteratee B.ByteString m a
 getI = parserToIteratee get
 
+-- | Enumerator
+enumHandleNonBlocking :: MonadIO m => Int -> Handle -> I.Enumerator B.ByteString m a
+enumHandleNonBlocking bufSize h =
+  I.enumFromCallback $ readSome bufSize h
+
+readSome :: MonadIO m => Int -> Handle -> m (Either SomeException (Bool, B.ByteString))
+readSome bufSize h = liftIO $ do
+  ebs <- try $ hGetSome bufSize h
+  case ebs of
+    Left exc ->
+      return $ Left (exc :: SomeException)
+    Right bs | B.null bs ->
+      return $ Right (False, B.empty)
+    Right bs ->
+      return $ Right (True, bs)
+
+hGetSome :: Int -> Handle -> IO B.ByteString
+hGetSome bufSize h = do
+  bs <- B.hGetNonBlocking h bufSize
+  if B.null bs
+    then do
+    hd <- B.hGet h 1
+    if B.null hd
+      then do
+      return B.empty
+      else do
+      rest <- B.hGetNonBlocking h (bufSize - 1)
+      return $ B.cons (B.head hd) rest
+    else do
+    return bs
+
 -- | Convert Parser to Iteratee
 parserToIteratee :: Monad m => A.Parser a -> I.Iteratee B.ByteString m a
 parserToIteratee p = I.icont (itr (A.parse p)) Nothing

From c56926428c2b66fd3f112b9095c46f46e0527cd7 Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Tue, 7 Sep 2010 16:14:00 +0900
Subject: [PATCH 32/43] haskell: add packToHandle'

---
 haskell/src/Data/MessagePack.hs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/haskell/src/Data/MessagePack.hs b/haskell/src/Data/MessagePack.hs
index b53066b1..7137589f 100644
--- a/haskell/src/Data/MessagePack.hs
+++ b/haskell/src/Data/MessagePack.hs
@@ -25,6 +25,7 @@ module Data.MessagePack(
   -- * Pack functions
   packToString,
   packToHandle,
+  packToHandle',
   packToFile,
   
   -- * Unpack functions
@@ -83,6 +84,10 @@ packToString = runPut
 packToHandle :: Handle -> Put -> IO ()
 packToHandle h = L.hPutStr h . packToString
 
+-- | Pack to Handle and Flush Handle
+packToHandle' :: Handle -> Put -> IO ()
+packToHandle' h p = packToHandle h p >> hFlush h
+
 -- | Pack to File
 packToFile :: FilePath -> Put -> IO ()
 packToFile path = L.writeFile path . packToString

From 169f287970a68e52d766b485f9c870ef83916b59 Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Tue, 7 Sep 2010 16:14:29 +0900
Subject: [PATCH 33/43] haskell: Now, Object is an instance of NFData.

---
 haskell/msgpack.cabal                  |  4 +++-
 haskell/src/Data/MessagePack/Object.hs | 12 ++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/haskell/msgpack.cabal b/haskell/msgpack.cabal
index 3baff77f..bd10c4aa 100644
--- a/haskell/msgpack.cabal
+++ b/haskell/msgpack.cabal
@@ -24,7 +24,9 @@ Library
                     iteratee >= 0.4 && < 0.5,
                     attoparsec >= 0.8.1 && < 0.8.2,
                     binary >= 0.5.0 && < 0.5.1,
-                    data-binary-ieee754 >= 0.4 && < 0.5
+                    data-binary-ieee754 >= 0.4 && < 0.5,
+                    deepseq >= 1.1 && <1.2
+
   Ghc-options:      -Wall -O2
   Hs-source-dirs:   src
 
diff --git a/haskell/src/Data/MessagePack/Object.hs b/haskell/src/Data/MessagePack/Object.hs
index df0e89dd..6806722b 100644
--- a/haskell/src/Data/MessagePack/Object.hs
+++ b/haskell/src/Data/MessagePack/Object.hs
@@ -25,6 +25,7 @@ module Data.MessagePack.Object(
   Result,
   ) where
 
+import Control.DeepSeq
 import Control.Monad
 import Control.Monad.Trans.Error ()
 import qualified Data.ByteString as B
@@ -41,6 +42,17 @@ data Object =
   | ObjectMap [(Object, Object)]
   deriving (Show)
 
+instance NFData Object where
+  rnf obj =
+    case obj of
+      ObjectNil -> ()
+      ObjectBool b -> rnf b
+      ObjectInteger n -> rnf n
+      ObjectDouble d -> rnf d
+      ObjectRAW bs -> bs `seq` ()
+      ObjectArray a -> rnf a
+      ObjectMap m -> rnf m
+
 -- | The class of types serializable to and from MessagePack object
 class OBJECT a where
   -- | Encode a value to MessagePack object

From 5e19bc6f844500e729d498ee6275a6a2e6557ba2 Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Tue, 7 Sep 2010 17:35:24 +0900
Subject: [PATCH 34/43] haskell: Object is Eq, Ord, Typeable.

---
 haskell/src/Data/MessagePack/Object.hs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/haskell/src/Data/MessagePack/Object.hs b/haskell/src/Data/MessagePack/Object.hs
index 6806722b..87f24bd9 100644
--- a/haskell/src/Data/MessagePack/Object.hs
+++ b/haskell/src/Data/MessagePack/Object.hs
@@ -1,6 +1,7 @@
 {-# Language TypeSynonymInstances #-}
 {-# Language FlexibleInstances #-}
 {-# Language OverlappingInstances #-}
+{-# Language DeriveDataTypeable #-}
 
 --------------------------------------------------------------------
 -- |
@@ -30,6 +31,7 @@ import Control.Monad
 import Control.Monad.Trans.Error ()
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Char8 as C8
+import Data.Typeable
 
 -- | Object Representation of MessagePack data.
 data Object =
@@ -40,7 +42,7 @@ data Object =
   | ObjectRAW B.ByteString
   | ObjectArray [Object]
   | ObjectMap [(Object, Object)]
-  deriving (Show)
+  deriving (Show, Eq, Ord, Typeable)
 
 instance NFData Object where
   rnf obj =

From a99870645244f9073075a43c30dc20511de89097 Mon Sep 17 00:00:00 2001
From: tanakh <tanaka.hideyuki@gmail.com>
Date: Wed, 8 Sep 2010 13:36:45 +0900
Subject: [PATCH 35/43] haskell: update cabal file

---
 haskell/msgpack.cabal | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/haskell/msgpack.cabal b/haskell/msgpack.cabal
index bd10c4aa..ccdb2f7f 100644
--- a/haskell/msgpack.cabal
+++ b/haskell/msgpack.cabal
@@ -1,18 +1,18 @@
 Name:               msgpack
-Version:            0.3.1
+Version:            0.3.1.1
 Synopsis:           A Haskell binding to MessagePack
 Description:
   A Haskell binding to MessagePack <http://msgpack.org/>
 
 License:            BSD3
 License-File:       LICENSE
+Copyright:          Copyright (c) 2009-2010, Hideyuki Tanaka
 Category:           Data
 Author:             Hideyuki Tanaka
 Maintainer:         Hideyuki Tanaka <tanaka.hideyuki@gmail.com>
 Homepage:           http://github.com/msgpack/msgpack
 Stability:          Experimental
-Tested-with:        GHC == 6.12.3
-Cabal-Version:      >= 1.2
+Cabal-Version:      >= 1.6
 Build-Type:         Simple
 
 Library
@@ -27,7 +27,7 @@ Library
                     data-binary-ieee754 >= 0.4 && < 0.5,
                     deepseq >= 1.1 && <1.2
 
-  Ghc-options:      -Wall -O2
+  Ghc-options:      -Wall
   Hs-source-dirs:   src
 
   Exposed-modules:
@@ -36,3 +36,7 @@ Library
     Data.MessagePack.Put
     Data.MessagePack.Parser
     Data.MessagePack.Iteratee
+
+Source-repository head
+  Type:     git
+  Location: git://github.com/msgpack/msgpack.git

From 9f684e7670877fe04d02afe8377e4a6191d74f31 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Fri, 10 Sep 2010 09:35:39 +0900
Subject: [PATCH 36/43] Checking in changes prior to tagging of version 0.20.

Changelog diff is:

diff --git a/perl/Changes b/perl/Changes
index 7910882..dc3dd5c 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,7 @@
+0.20
+
+    - first production ready release with PP driver.
+
 0.16_04

     - no feature changes
---
 perl/Changes                 | 4 ++++
 perl/lib/Data/MessagePack.pm | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/perl/Changes b/perl/Changes
index 79108820..dc3dd5cf 100644
--- a/perl/Changes
+++ b/perl/Changes
@@ -1,3 +1,7 @@
+0.20
+
+    - first production ready release with PP driver.
+
 0.16_04
 
     - no feature changes
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index b08bac2d..eca24ec6 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -3,7 +3,7 @@ use strict;
 use warnings;
 use 5.008001;
 
-our $VERSION = '0.16_04';
+our $VERSION = '0.20';
 our $PreferInteger = 0;
 
 our $true  = do { bless \(my $dummy = 1), "Data::MessagePack::Boolean" };

From f6f675d1e12b2c5994099df3d1af1513b1d83bf2 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Fri, 10 Sep 2010 20:27:11 +0900
Subject: [PATCH 37/43] updated benchmark script

---
 perl/benchmark/deserialize.pl | 9 ++++++---
 perl/benchmark/serialize.pl   | 5 ++++-
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/perl/benchmark/deserialize.pl b/perl/benchmark/deserialize.pl
index fd21f086..0ddcec93 100644
--- a/perl/benchmark/deserialize.pl
+++ b/perl/benchmark/deserialize.pl
@@ -3,18 +3,21 @@ use warnings;
 use Data::MessagePack;
 use JSON::XS;
 use Benchmark ':all';
+use Storable;
 
 my $a = [0..2**24];
 my $j = JSON::XS::encode_json($a);
 my $m = Data::MessagePack->pack($a);
+my $s = Storable::nfreeze($a);
 
 print "-- deserialize\n";
 print "JSON::XS: $JSON::XS::VERSION\n";
 print "Data::MessagePack: $Data::MessagePack::VERSION\n";
-cmpthese(
+timethese(
     -1 => {
-        json => sub { JSON::XS::decode_json($j)     },
-        mp   => sub { Data::MessagePack->unpack($m) },
+        json     => sub { JSON::XS::decode_json($j)     },
+        mp       => sub { Data::MessagePack->unpack($m) },
+        storable => sub { Storable::thaw($s) },
     }
 );
 
diff --git a/perl/benchmark/serialize.pl b/perl/benchmark/serialize.pl
index 626ae039..b811bfe5 100644
--- a/perl/benchmark/serialize.pl
+++ b/perl/benchmark/serialize.pl
@@ -2,6 +2,7 @@ use strict;
 use warnings;
 use Data::MessagePack;
 use JSON::XS;
+use Storable;
 use Benchmark ':all';
 
 my $a = [0..2**24];
@@ -9,9 +10,11 @@ my $a = [0..2**24];
 print "-- serialize\n";
 print "JSON::XS: $JSON::XS::VERSION\n";
 print "Data::MessagePack: $Data::MessagePack::VERSION\n";
-cmpthese(
+print "Storable: $Storable::VERSION\n";
+timethese(
     -1 => {
         json => sub { JSON::XS::encode_json($a)   },
+        storable => sub { Storable::nfreeze($a)   },
         mp   => sub { Data::MessagePack->pack($a) },
     }
 );

From 5bb8b6f16c426ebfeee0027c1026ab8f610bec05 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Fri, 10 Sep 2010 20:38:37 +0900
Subject: [PATCH 38/43] perl: ugpraded benchmarking script. and added result to
 docs.

---
 perl/benchmark/deserialize.pl | 12 ++++++---
 perl/benchmark/serialize.pl   | 15 +++++++----
 perl/lib/Data/MessagePack.pm  | 50 ++++++++++++++++++++++++++++++++++-
 3 files changed, 68 insertions(+), 9 deletions(-)

diff --git a/perl/benchmark/deserialize.pl b/perl/benchmark/deserialize.pl
index 0ddcec93..750704e9 100644
--- a/perl/benchmark/deserialize.pl
+++ b/perl/benchmark/deserialize.pl
@@ -5,16 +5,22 @@ use JSON::XS;
 use Benchmark ':all';
 use Storable;
 
-my $a = [0..2**24];
+my $a = {
+    "method" => "handleMessage",
+    "params" => [ "user1", "we were just talking" ],
+    "id"     => undef,
+    "array"  => [ 1, 11, 234, -5, 1e5, 1e7, 1, 0 ]
+};
 my $j = JSON::XS::encode_json($a);
 my $m = Data::MessagePack->pack($a);
-my $s = Storable::nfreeze($a);
+my $s = Storable::freeze($a);
 
 print "-- deserialize\n";
 print "JSON::XS: $JSON::XS::VERSION\n";
 print "Data::MessagePack: $Data::MessagePack::VERSION\n";
+print "Storable: $Storable::VERSION\n";
 timethese(
-    -1 => {
+    1000000 => {
         json     => sub { JSON::XS::decode_json($j)     },
         mp       => sub { Data::MessagePack->unpack($m) },
         storable => sub { Storable::thaw($s) },
diff --git a/perl/benchmark/serialize.pl b/perl/benchmark/serialize.pl
index b811bfe5..c5ab15bc 100644
--- a/perl/benchmark/serialize.pl
+++ b/perl/benchmark/serialize.pl
@@ -5,17 +5,22 @@ use JSON::XS;
 use Storable;
 use Benchmark ':all';
 
-my $a = [0..2**24];
+my $a = {
+    "method" => "handleMessage",
+    "params" => [ "user1", "we were just talking" ],
+    "id"     => undef,
+    "array"  => [ 1, 11, 234, -5, 1e5, 1e7, 1, 0 ]
+};
 
 print "-- serialize\n";
 print "JSON::XS: $JSON::XS::VERSION\n";
 print "Data::MessagePack: $Data::MessagePack::VERSION\n";
 print "Storable: $Storable::VERSION\n";
 timethese(
-    -1 => {
-        json => sub { JSON::XS::encode_json($a)   },
-        storable => sub { Storable::nfreeze($a)   },
-        mp   => sub { Data::MessagePack->pack($a) },
+    1000000 => {
+        json     => sub { JSON::XS::encode_json($a) },
+        storable => sub { Storable::freeze($a) },
+        mp       => sub { Data::MessagePack->pack($a) },
     }
 );
 
diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index eca24ec6..fbf305a5 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -41,9 +41,35 @@ Data::MessagePack - MessagePack serialising/deserialising
 
 This module converts Perl data structures to MessagePack and vice versa.
 
+=head1 ABOUT MESSAGEPACK FORMAT
+
 MessagePack is a binary-based efficient object serialization format.
 It enables to exchange structured objects between many languages like JSON. But unlike JSON, it is very fast and small.
 
+=head2 ADVANTAGES
+
+=over 4
+
+=item PORTABILITY
+
+Messagepack is language independent binary serialize format.
+
+=item SMALL SIZE
+
+    say length(JSON::XS::encode_json({a=>1, b=>2}));   # => 13
+    say length(Storable::nfreeze({a=>1, b=>2}));       # => 21
+    say length(Data::MessagePack->pack({a=>1, b=>2})); # => 7
+
+MessagePack format saves memory than JSON and Storable format.
+
+=item STREAMING DESERIALIZER
+
+MessagePack supports streaming deserializer. It is useful for networking such as RPC.
+
+=back
+
+If you want to get more informations about messagepack format, please visit to L<http://msgpack.org/>.
+
 =head1 METHODS
 
 =over 4
@@ -68,6 +94,28 @@ Pack the string as int when the value looks like int(EXPERIMENTAL).
 
 =back
 
+=head1 SPEED
+
+This is result of benchmark/serialize.pl and benchmark/deserialize.pl on my SC440(Linux 2.6.32-23-server #37-Ubuntu SMP).
+
+    -- serialize
+    JSON::XS: 2.3
+    Data::MessagePack: 0.20
+    Storable: 2.21
+    Benchmark: timing 1000000 iterations of json, mp, storable...
+          json:  5 wallclock secs ( 3.95 usr +  0.00 sys =  3.95 CPU) @ 253164.56/s (n=1000000)
+            mp:  3 wallclock secs ( 2.69 usr +  0.00 sys =  2.69 CPU) @ 371747.21/s (n=1000000)
+      storable: 26 wallclock secs (27.21 usr +  0.00 sys = 27.21 CPU) @ 36751.19/s (n=1000000)
+
+    -- deserialize
+    JSON::XS: 2.3
+    Data::MessagePack: 0.20
+    Storable: 2.21
+    Benchmark: timing 1000000 iterations of json, mp, storable...
+          json:  4 wallclock secs ( 4.45 usr +  0.00 sys =  4.45 CPU) @ 224719.10/s (n=1000000)
+            mp:  6 wallclock secs ( 5.45 usr +  0.00 sys =  5.45 CPU) @ 183486.24/s (n=1000000)
+      storable:  7 wallclock secs ( 7.77 usr +  0.00 sys =  7.77 CPU) @ 128700.13/s (n=1000000)
+
 =head1 AUTHORS
 
 Tokuhiro Matsuno
@@ -90,5 +138,5 @@ it under the same terms as Perl itself.
 
 =head1 SEE ALSO
 
-L<http://msgpack.org/>
+L<http://msgpack.org/> is official web site for MessagePack format.
 

From b79c1345b92d8cdb6427e0d83d7191262331fd5a Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Fri, 10 Sep 2010 20:42:40 +0900
Subject: [PATCH 39/43] use gfx's standard header.

---
 perl/README          | 43 ++++++++++++++++++++++++-
 perl/perlxs.h        | 76 ++++++++++++++++++++++++++++++++++++++++++++
 perl/xs-src/pack.c   | 11 +------
 perl/xs-src/unpack.c | 46 ++++++++++++---------------
 4 files changed, 140 insertions(+), 36 deletions(-)
 create mode 100644 perl/perlxs.h

diff --git a/perl/README b/perl/README
index 2ef686c2..d5fc2693 100644
--- a/perl/README
+++ b/perl/README
@@ -8,10 +8,29 @@ SYNOPSIS
 DESCRIPTION
     This module converts Perl data structures to MessagePack and vice versa.
 
+ABOUT MESSAGEPACK FORMAT
     MessagePack is a binary-based efficient object serialization format. It
     enables to exchange structured objects between many languages like JSON.
     But unlike JSON, it is very fast and small.
 
+  ADVANTAGES
+    PORTABILITY
+        Messagepack is language independent binary serialize format.
+
+    SMALL SIZE
+            say length(JSON::XS::encode_json({a=>1, b=>2}));   # => 13
+            say length(Storable::nfreeze({a=>1, b=>2}));       # => 21
+            say length(Data::MessagePack->pack({a=>1, b=>2})); # => 7
+
+        MessagePack format saves memory than JSON and Storable format.
+
+    STREAMING DESERIALIZER
+        MessagePack supports streaming deserializer. It is useful for
+        networking such as RPC.
+
+    If you want to get more informations about messagepack format, please
+    visit to <http://msgpack.org/>.
+
 METHODS
     my $packed = Data::MessagePack->pack($data);
         pack the $data to messagepack format string.
@@ -23,6 +42,28 @@ Configuration Variables
     $Data::MessagePack::PreferInteger
         Pack the string as int when the value looks like int(EXPERIMENTAL).
 
+SPEED
+    This is result of benchmark/serialize.pl and benchmark/deserialize.pl on
+    my SC440(Linux 2.6.32-23-server #37-Ubuntu SMP).
+
+        -- serialize
+        JSON::XS: 2.3
+        Data::MessagePack: 0.20
+        Storable: 2.21
+        Benchmark: timing 1000000 iterations of json, mp, storable...
+              json:  5 wallclock secs ( 3.95 usr +  0.00 sys =  3.95 CPU) @ 253164.56/s (n=1000000)
+                mp:  3 wallclock secs ( 2.69 usr +  0.00 sys =  2.69 CPU) @ 371747.21/s (n=1000000)
+          storable: 26 wallclock secs (27.21 usr +  0.00 sys = 27.21 CPU) @ 36751.19/s (n=1000000)
+
+        -- deserialize
+        JSON::XS: 2.3
+        Data::MessagePack: 0.20
+        Storable: 2.21
+        Benchmark: timing 1000000 iterations of json, mp, storable...
+              json:  4 wallclock secs ( 4.45 usr +  0.00 sys =  4.45 CPU) @ 224719.10/s (n=1000000)
+                mp:  6 wallclock secs ( 5.45 usr +  0.00 sys =  5.45 CPU) @ 183486.24/s (n=1000000)
+          storable:  7 wallclock secs ( 7.77 usr +  0.00 sys =  7.77 CPU) @ 128700.13/s (n=1000000)
+
 AUTHORS
     Tokuhiro Matsuno
 
@@ -40,5 +81,5 @@ LICENSE
     under the same terms as Perl itself.
 
 SEE ALSO
-    <http://msgpack.org/>
+    <http://msgpack.org/> is official web site for MessagePack format.
 
diff --git a/perl/perlxs.h b/perl/perlxs.h
new file mode 100644
index 00000000..441682de
--- /dev/null
+++ b/perl/perlxs.h
@@ -0,0 +1,76 @@
+/*
+    perlxs.h - Standard XS header file
+    Copyright (c) Fuji, Goro (gfx)
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PERL_NO_GET_CONTEXT /* we want efficiency */
+#include <EXTERN.h>
+
+#include <perl.h>
+#define NO_XSLOCKS /* for exceptions */
+#include <XSUB.h>
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include "ppport.h"
+
+/* portability stuff not supported by ppport.h yet */
+
+#ifndef STATIC_INLINE /* from 5.13.4 */
+#   if defined(__GNUC__) || defined(__cplusplus__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
+#       define STATIC_INLINE static inline
+#   else
+#       define STATIC_INLINE static
+#   endif
+#endif /* STATIC_INLINE */
+
+#ifndef __attribute__format__
+#define __attribute__format__(a,b,c) /* nothing */
+#endif
+
+#ifndef LIKELY /* they are just a compiler's hint */
+#define LIKELY(x)   (x)
+#define UNLIKELY(x) (x)
+#endif
+
+#ifndef newSVpvs_share
+#define newSVpvs_share(s) Perl_newSVpvn_share(aTHX_ STR_WITH_LEN(s), 0U)
+#endif
+
+#ifndef get_cvs
+#define get_cvs(name, flags) get_cv(name, flags)
+#endif
+
+#ifndef GvNAME_get
+#define GvNAME_get GvNAME
+#endif
+#ifndef GvNAMELEN_get
+#define GvNAMELEN_get GvNAMELEN
+#endif
+
+#ifndef CvGV_set
+#define CvGV_set(cv, gv) (CvGV(cv) = (gv))
+#endif
+
+/* general utility */
+
+#if PERL_BCDVERSION >= 0x5008005
+#define LooksLikeNumber(x) looks_like_number(x)
+#else
+#define LooksLikeNumber(x) (SvPOKp(x) ? looks_like_number(x) : (I32)SvNIOKp(x))
+#endif
+
+#define newAV_mortal() (AV*)sv_2mortal((SV*)newAV())
+#define newHV_mortal() (HV*)sv_2mortal((SV*)newHV())
+
+#define DECL_BOOT(name) EXTERN_C XS(CAT2(boot_, name))
+#define CALL_BOOT(name) STMT_START {            \
+        PUSHMARK(SP);                           \
+        CALL_FPTR(CAT2(boot_, name))(aTHX_ cv); \
+    } STMT_END
diff --git a/perl/xs-src/pack.c b/perl/xs-src/pack.c
index 93b2e2f4..62eb0024 100644
--- a/perl/xs-src/pack.c
+++ b/perl/xs-src/pack.c
@@ -2,16 +2,7 @@
  * code is written by tokuhirom.
  * buffer alocation technique is taken from JSON::XS. thanks to mlehmann.
  */
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include "EXTERN.h"
-#include "perl.h"
-#include "XSUB.h"
-#include "ppport.h"
-#ifdef __cplusplus
-};
-#endif
+#include "perlxs.h"
 
 #include "msgpack/pack_define.h"
 
diff --git a/perl/xs-src/unpack.c b/perl/xs-src/unpack.c
index eb6e0ddb..20a07372 100644
--- a/perl/xs-src/unpack.c
+++ b/perl/xs-src/unpack.c
@@ -2,13 +2,9 @@
 extern "C" {
 #endif
 
-#include "EXTERN.h"
-#include "perl.h"
-#include "XSUB.h"
-#include "util.h"
 #define NEED_newRV_noinc
 #define NEED_sv_2pv_flags
-#include "ppport.h"
+#include "perlxs.h"
 
 #ifdef __cplusplus
 };
@@ -38,7 +34,7 @@ typedef struct {
 /* ---------------------------------------------------------------------- */
 /* utility functions                                                      */
 
-static INLINE SV *
+STATIC_INLINE SV *
 get_bool (const char *name) {
     SV * sv = sv_mortalcopy(get_sv( name, 1 ));
 
@@ -60,19 +56,19 @@ static SV* template_data(msgpack_unpack_t* u);
 static int template_execute(msgpack_unpack_t* u,
     const char* data, size_t len, size_t* off);
 
-static INLINE SV* template_callback_root(unpack_user* u)
+STATIC_INLINE SV* template_callback_root(unpack_user* u)
 { return &PL_sv_undef; }
 
-static INLINE int template_callback_uint8(unpack_user* u, uint8_t d, SV** o)
+STATIC_INLINE int template_callback_uint8(unpack_user* u, uint8_t d, SV** o)
 { *o = sv_2mortal(newSVuv(d)); return 0; }
 
-static INLINE int template_callback_uint16(unpack_user* u, uint16_t d, SV** o)
+STATIC_INLINE int template_callback_uint16(unpack_user* u, uint16_t d, SV** o)
 { *o = sv_2mortal(newSVuv(d)); return 0; }
 
-static INLINE int template_callback_uint32(unpack_user* u, uint32_t d, SV** o)
+STATIC_INLINE int template_callback_uint32(unpack_user* u, uint32_t d, SV** o)
 { *o = sv_2mortal(newSVuv(d)); return 0; }
 
-static INLINE int template_callback_uint64(unpack_user* u, uint64_t d, SV** o)
+STATIC_INLINE int template_callback_uint64(unpack_user* u, uint64_t d, SV** o)
 {
 #if IVSIZE==4
     *o = sv_2mortal(newSVnv(d));
@@ -82,47 +78,47 @@ static INLINE int template_callback_uint64(unpack_user* u, uint64_t d, SV** o)
     return 0;
 }
 
-static INLINE int template_callback_int8(unpack_user* u, int8_t d, SV** o)
+STATIC_INLINE int template_callback_int8(unpack_user* u, int8_t d, SV** o)
 { *o = sv_2mortal(newSViv((long)d)); return 0; }
 
-static INLINE int template_callback_int16(unpack_user* u, int16_t d, SV** o)
+STATIC_INLINE int template_callback_int16(unpack_user* u, int16_t d, SV** o)
 { *o = sv_2mortal(newSViv((long)d)); return 0; }
 
-static INLINE int template_callback_int32(unpack_user* u, int32_t d, SV** o)
+STATIC_INLINE int template_callback_int32(unpack_user* u, int32_t d, SV** o)
 { *o = sv_2mortal(newSViv((long)d)); return 0; }
 
-static INLINE int template_callback_int64(unpack_user* u, int64_t d, SV** o)
+STATIC_INLINE int template_callback_int64(unpack_user* u, int64_t d, SV** o)
 { *o = sv_2mortal(newSViv(d)); return 0; }
 
-static INLINE int template_callback_float(unpack_user* u, float d, SV** o)
+STATIC_INLINE int template_callback_float(unpack_user* u, float d, SV** o)
 { *o = sv_2mortal(newSVnv(d)); return 0; }
 
-static INLINE int template_callback_double(unpack_user* u, double d, SV** o)
+STATIC_INLINE int template_callback_double(unpack_user* u, double d, SV** o)
 { *o = sv_2mortal(newSVnv(d)); return 0; }
 
 /* &PL_sv_undef is not so good. see http://gist.github.com/387743 */
-static INLINE int template_callback_nil(unpack_user* u, SV** o)
+STATIC_INLINE int template_callback_nil(unpack_user* u, SV** o)
 { *o = sv_newmortal(); return 0; }
 
-static INLINE int template_callback_true(unpack_user* u, SV** o)
+STATIC_INLINE int template_callback_true(unpack_user* u, SV** o)
 { *o = get_bool("Data::MessagePack::true") ; return 0; }
 
-static INLINE int template_callback_false(unpack_user* u, SV** o)
+STATIC_INLINE int template_callback_false(unpack_user* u, SV** o)
 { *o = get_bool("Data::MessagePack::false") ; return 0; }
 
-static INLINE int template_callback_array(unpack_user* u, unsigned int n, SV** o)
+STATIC_INLINE int template_callback_array(unpack_user* u, unsigned int n, SV** o)
 { AV* a = (AV*)sv_2mortal((SV*)newAV()); *o = sv_2mortal((SV*)newRV_inc((SV*)a)); av_extend(a, n); return 0; }
 
-static INLINE int template_callback_array_item(unpack_user* u, SV** c, SV* o)
+STATIC_INLINE int template_callback_array_item(unpack_user* u, SV** c, SV* o)
 { av_push((AV*)SvRV(*c), o); SvREFCNT_inc(o); return 0; }  /* FIXME set value directry RARRAY_PTR(obj)[RARRAY_LEN(obj)++] */
 
-static INLINE int template_callback_map(unpack_user* u, unsigned int n, SV** o)
+STATIC_INLINE int template_callback_map(unpack_user* u, unsigned int n, SV** o)
 { HV * h = (HV*)sv_2mortal((SV*)newHV()); *o = sv_2mortal(newRV_inc((SV*)h)); return 0; }
 
-static INLINE int template_callback_map_item(unpack_user* u, SV** c, SV* k, SV* v)
+STATIC_INLINE int template_callback_map_item(unpack_user* u, SV** c, SV* k, SV* v)
 { hv_store_ent((HV*)SvRV(*c), k, v, 0); SvREFCNT_inc(v); return 0; }
 
-static INLINE int template_callback_raw(unpack_user* u, const char* b, const char* p, unsigned int l, SV** o)
+STATIC_INLINE int template_callback_raw(unpack_user* u, const char* b, const char* p, unsigned int l, SV** o)
 { *o = sv_2mortal((l==0) ? newSVpv("", 0) : newSVpv(p, l)); return 0; }
 /* { *o = newSVpvn_flags(p, l, SVs_TEMP); return 0; }  <= this does not works. */
 

From ef0a86e7ccc78bf632a3dea4b49fe8507d711151 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Fri, 10 Sep 2010 20:45:17 +0900
Subject: [PATCH 40/43] perl: more inline

---
 perl/xs-src/unpack.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/perl/xs-src/unpack.c b/perl/xs-src/unpack.c
index 20a07372..16a52d78 100644
--- a/perl/xs-src/unpack.c
+++ b/perl/xs-src/unpack.c
@@ -131,7 +131,7 @@ STATIC_INLINE int template_callback_raw(unpack_user* u, const char* b, const cha
 
 #include "msgpack/unpack_template.h"
 
-SV* _msgpack_unpack(SV* data, int limit) {
+STATIC_INLINE SV* _msgpack_unpack(SV* data, int limit) {
     msgpack_unpack_t mp;
     unpack_user u = {0, &PL_sv_undef};
 	int ret;
@@ -194,7 +194,7 @@ XS(xs_unpack) {
 /* ------------------------------ stream -- */
 /* http://twitter.com/frsyuki/status/13249304748 */
 
-static void _reset(SV* self) {
+STATIC_INLINE void _reset(SV* self) {
 	unpack_user u = {0, &PL_sv_undef, 0};
 
 	UNPACKER(self, mp);
@@ -220,7 +220,7 @@ XS(xs_unpacker_new) {
     XSRETURN(1);
 }
 
-static SV* _execute_impl(SV* self, SV* data, UV off, I32 limit) {
+STATIC_INLINE SV* _execute_impl(SV* self, SV* data, UV off, I32 limit) {
     UNPACKER(self, mp);
 
     size_t from = off;

From 0cd31a4b96d1b8b4084083d3b7ed99b403338e2b Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Fri, 10 Sep 2010 21:00:27 +0900
Subject: [PATCH 41/43] perl: inlining utility functions

---
 perl/xs-src/unpack.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/perl/xs-src/unpack.c b/perl/xs-src/unpack.c
index 16a52d78..f82fe072 100644
--- a/perl/xs-src/unpack.c
+++ b/perl/xs-src/unpack.c
@@ -22,7 +22,7 @@ typedef struct {
     struct template ## name
 
 #define msgpack_unpack_func(ret, name) \
-    ret template ## name
+    STATIC_INLINE ret template ## name
 
 #define msgpack_unpack_callback(name) \
     template_callback ## name

From 0c4f0de13dd9cfaa2f50b48177a0545e258c81b7 Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Fri, 10 Sep 2010 21:18:45 +0900
Subject: [PATCH 42/43] perl: inlining the small functions

---
 perl/xs-src/pack.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/perl/xs-src/pack.c b/perl/xs-src/pack.c
index 62eb0024..e7a7c35b 100644
--- a/perl/xs-src/pack.c
+++ b/perl/xs-src/pack.c
@@ -43,7 +43,7 @@ static void need(enc_t *enc, STRLEN len);
 #define ERR_NESTING_EXCEEDED "perl structure exceeds maximum nesting level (max_depth set too low?)"
 
 
-static void need(enc_t *enc, STRLEN len)
+STATIC_INLINE void need(enc_t *enc, STRLEN len)
 {
     if (enc->cur + len >= enc->end) {
         STRLEN cur = enc->cur - (char *)SvPVX (enc->sv);
@@ -56,7 +56,7 @@ static void need(enc_t *enc, STRLEN len)
 
 static int s_pref_int = 0;
 
-static int pref_int_set(pTHX_ SV* sv, MAGIC* mg) {
+STATIC_INLINE int pref_int_set(pTHX_ SV* sv, MAGIC* mg) {
     if (SvTRUE(sv)) {
         s_pref_int = 1;
     } else {
@@ -85,7 +85,7 @@ void boot_Data__MessagePack_pack(void) {
 }
 
 
-static int try_int(enc_t* enc, const char *p, size_t len) {
+STATIC_INLINE int try_int(enc_t* enc, const char *p, size_t len) {
     int negative = 0;
     const char* pe = p + len;
     uint64_t num = 0;
@@ -141,7 +141,7 @@ static int try_int(enc_t* enc, const char *p, size_t len) {
 
 static void _msgpack_pack_rv(enc_t *enc, SV* sv, int depth);
 
-static void _msgpack_pack_sv(enc_t *enc, SV* sv, int depth) {
+STATIC_INLINE void _msgpack_pack_sv(enc_t *enc, SV* sv, int depth) {
     if (depth <= 0) Perl_croak(aTHX_ ERR_NESTING_EXCEEDED);
     SvGETMAGIC(sv);
 
@@ -176,7 +176,7 @@ static void _msgpack_pack_sv(enc_t *enc, SV* sv, int depth) {
     }
 }
 
-static void _msgpack_pack_rv(enc_t *enc, SV* sv, int depth) {
+STATIC_INLINE void _msgpack_pack_rv(enc_t *enc, SV* sv, int depth) {
     svtype svt;
     if (depth <= 0) Perl_croak(aTHX_ ERR_NESTING_EXCEEDED);
     SvGETMAGIC(sv);

From beb22844408b218a9ae7f494f3caa2aefe779a0e Mon Sep 17 00:00:00 2001
From: tokuhirom <tokuhirom@gmail.com>
Date: Fri, 10 Sep 2010 21:25:46 +0900
Subject: [PATCH 43/43] perl: added docs for circular reference and blessed
 object.

---
 perl/lib/Data/MessagePack.pm | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm
index fbf305a5..0229bcab 100644
--- a/perl/lib/Data/MessagePack.pm
+++ b/perl/lib/Data/MessagePack.pm
@@ -74,9 +74,13 @@ If you want to get more informations about messagepack format, please visit to L
 
 =over 4
 
-=item my $packed = Data::MessagePack->pack($data);
+=item my $packed = Data::MessagePack->pack($data[, $max_depth]);
 
-pack the $data to messagepack format string.
+Pack the $data to messagepack format string.
+
+This method throws exception when nesting perl structure more than $max_depth(default: 512) for detecting circular reference.
+
+Data::MessagePack->pack() throws exception when encountered blessed object. Because MessagePack is language independent format.
 
 =item my $unpacked = Data::MessagePack->unpack($msgpackstr);