@@ -50,40 +50,34 @@ internal static ITranslator GetWriteTranslator(Stream stream)
50
50
return new BinaryWriteTranslator ( stream ) ;
51
51
}
52
52
53
- // TODO: Avoid expsoing write translator?
54
- internal static ITranslator GetWriteTranslator ( Stream stream , InterningWriteTranslator interner )
55
- {
56
- return new BinaryWriteTranslator ( stream , interner , isInterning : true ) ;
57
- }
58
-
59
53
/// <summary>
60
54
/// Implementation of ITranslator for reading from a stream.
61
55
/// </summary>
62
56
private class BinaryReadTranslator : ITranslator
63
57
{
64
58
/// <summary>
65
- /// The stream used as a source or destination for data .
59
+ /// The intern reader used in an intern scope .
66
60
/// </summary>
67
- private Stream _packetStream ;
61
+ private readonly InterningReadTranslator _interner ;
68
62
69
63
/// <summary>
70
64
/// The binary reader used in read mode.
71
65
/// </summary>
72
66
private BinaryReader _reader ;
73
67
74
- private InterningReadTranslator _interner ;
75
-
76
- public bool IsInterning { get ; private set ; }
68
+ /// <summary>
69
+ /// Whether the caller has entered an intern scope.
70
+ /// </summary>
71
+ private bool _isInterning ;
77
72
78
73
#nullable enable
79
74
/// <summary>
80
75
/// Constructs a serializer from the specified stream, operating in the designated mode.
81
76
/// </summary>
82
77
public BinaryReadTranslator ( Stream packetStream , BinaryReaderFactory buffer )
83
78
{
84
- _packetStream = packetStream ;
85
79
_reader = buffer . Create ( packetStream ) ;
86
- _interner = new ( this ) ;
80
+ _interner = new InterningReadTranslator ( this ) ;
87
81
}
88
82
#nullable disable
89
83
@@ -802,71 +796,76 @@ public bool TranslateNullable<T>(T value)
802
796
803
797
public void WithInterning ( IEqualityComparer < string > comparer , int initialCapacity , Action < ITranslator > internBlock )
804
798
{
805
- if ( IsInterning )
799
+ if ( _isInterning )
806
800
{
807
801
throw new InvalidOperationException ( "Cannot enter recursive intern block." ) ;
808
802
}
809
803
810
- IsInterning = true ;
804
+ _isInterning = true ;
811
805
806
+ // Deserialize the intern header before entering the intern scope.
812
807
_interner . Translate ( this ) ;
808
+
809
+ // No other setup is needed since we can parse the packet directly from the stream.
813
810
internBlock ( this ) ;
814
811
815
- IsInterning = false ;
812
+ _isInterning = false ;
816
813
}
817
814
818
- public void Intern ( ref string str , bool nullable )
815
+ public void Intern ( ref string str , bool nullable = true )
819
816
{
820
- if ( ! IsInterning )
817
+ if ( ! _isInterning )
821
818
{
822
819
Translate ( ref str ) ;
820
+ return ;
823
821
}
824
- else if ( nullable )
825
- {
826
- str = _interner . ReadNullable ( ) ;
827
- }
828
- else
822
+
823
+ if ( nullable && ! TranslateNullable ( string . Empty ) )
829
824
{
830
- str = _interner . Read ( ) ;
825
+ str = null ;
826
+ return ;
831
827
}
828
+
829
+ str = _interner . Read ( ) ;
832
830
}
833
831
834
832
public void Intern ( ref string [ ] array )
835
833
{
836
- if ( ! IsInterning )
834
+ if ( ! _isInterning )
837
835
{
838
836
Translate ( ref array ) ;
837
+ return ;
839
838
}
840
839
841
840
if ( ! TranslateNullable ( array ) )
842
841
{
843
842
return ;
844
843
}
845
844
846
-
847
845
int count = _reader . ReadInt32 ( ) ;
848
846
array = new string [ count ] ;
849
847
850
848
for ( int i = 0 ; i < count ; i ++ )
851
849
{
852
- array [ i ] = _interner . ReadNullable ( ) ;
850
+ array [ i ] = _interner . Read ( ) ;
853
851
}
854
852
}
855
853
856
- public void InternPath ( ref string str , bool nullable )
854
+ public void InternPath ( ref string str , bool nullable = true )
857
855
{
858
- if ( ! IsInterning )
856
+ if ( ! _isInterning )
859
857
{
860
858
Translate ( ref str ) ;
859
+ return ;
861
860
}
862
- else if ( nullable )
863
- {
864
- str = _interner . ReadNullablePath ( ) ;
865
- }
866
- else
861
+
862
+ if ( nullable && ! TranslateNullable ( string . Empty ) )
867
863
{
868
- str = _interner . ReadPath ( ) ;
864
+ str = null ;
865
+ return ;
869
866
}
867
+
868
+ str = _interner . ReadPath ( ) ;
870
869
}
871
870
}
872
871
@@ -875,35 +874,30 @@ public void InternPath(ref string str, bool nullable)
875
874
/// </summary>
876
875
private class BinaryWriteTranslator : ITranslator
877
876
{
878
- /// <summary>
879
- /// The stream used as a source or destination for data.
880
- /// </summary>
881
- private Stream _packetStream ;
882
-
883
877
/// <summary>
884
878
/// The binary writer used in write mode.
885
879
/// </summary>
886
880
private BinaryWriter _writer ;
887
881
888
- private readonly InterningWriteTranslator _interner = new ( ) ;
882
+ /// <summary>
883
+ /// The intern writer used in an intern scope.
884
+ /// This must be lazily instantiated since the interner has its own internal write translator, and
885
+ /// would otherwise go into a recursive loop on initalization.
886
+ /// </summary>
887
+ private InterningWriteTranslator _interner ;
889
888
890
- public bool IsInterning { get ; private set ; }
889
+ /// <summary>
890
+ /// Whether the caller has entered an intern scope.
891
+ /// </summary>
892
+ private bool _isInterning ;
891
893
892
894
/// <summary>
893
895
/// Constructs a serializer from the specified stream, operating in the designated mode.
894
896
/// </summary>
895
897
/// <param name="packetStream">The stream serving as the source or destination of data.</param>
896
898
public BinaryWriteTranslator ( Stream packetStream )
897
- : this ( packetStream , new InterningWriteTranslator ( ) )
898
- {
899
- }
900
-
901
- internal BinaryWriteTranslator ( Stream packetStream , InterningWriteTranslator interner , bool isInterning = false )
902
899
{
903
- _packetStream = packetStream ;
904
900
_writer = new BinaryWriter ( packetStream ) ;
905
- _interner = interner ;
906
- IsInterning = isInterning ;
907
901
}
908
902
909
903
/// <summary>
@@ -1604,67 +1598,88 @@ public bool TranslateNullable<T>(T value)
1604
1598
1605
1599
public void WithInterning ( IEqualityComparer < string > comparer , int initialCapacity , Action < ITranslator > internBlock )
1606
1600
{
1607
- if ( IsInterning )
1601
+ if ( _isInterning )
1608
1602
{
1609
1603
throw new InvalidOperationException ( "Cannot enter recursive intern block." ) ;
1610
1604
}
1611
1605
1612
- _interner . InitCapacity ( comparer , initialCapacity ) ;
1613
- internBlock ( _interner . Translator ) ;
1606
+ // Every new scope requires the interner's state to be reset.
1607
+ _interner ??= new InterningWriteTranslator ( ) ;
1608
+ _interner . Setup ( comparer , initialCapacity ) ;
1609
+
1610
+ // Temporaily swap our writer with the interner.
1611
+ // This forwards all writes to this translator into the interning buffer, so that any non-interned
1612
+ // writes which are interleaved will be in the correct order.
1613
+ BinaryWriter streamWriter = _writer ;
1614
+ _writer = _interner . Writer ;
1615
+ _isInterning = true ;
1616
+
1617
+ try
1618
+ {
1619
+ internBlock ( this ) ;
1620
+ }
1621
+ finally
1622
+ {
1623
+ _writer = streamWriter ;
1624
+ _isInterning = false ;
1625
+ }
1626
+
1627
+ // Write the interned buffer into the real output stream.
1614
1628
_interner . Translate ( this ) ;
1615
1629
}
1616
1630
1617
- public void Intern ( ref string str , bool nullable )
1631
+ public void Intern ( ref string str , bool nullable = true )
1618
1632
{
1619
- if ( ! IsInterning )
1633
+ if ( ! _isInterning )
1620
1634
{
1621
1635
Translate ( ref str ) ;
1636
+ return ;
1622
1637
}
1623
- else if ( nullable )
1624
- {
1625
- _interner . InternNullable ( str ) ;
1626
- }
1627
- else
1638
+
1639
+ if ( nullable && ! TranslateNullable ( str ) )
1628
1640
{
1629
- _interner . Intern ( str ) ;
1641
+ return ;
1630
1642
}
1643
+
1644
+ _interner . Intern ( str ) ;
1631
1645
}
1632
1646
1633
1647
public void Intern ( ref string [ ] array )
1634
1648
{
1635
- if ( ! IsInterning )
1649
+ if ( ! _isInterning )
1636
1650
{
1637
1651
Translate ( ref array ) ;
1652
+ return ;
1638
1653
}
1639
1654
1640
- if ( ! _interner . Translator . TranslateNullable ( array ) )
1655
+ if ( ! TranslateNullable ( array ) )
1641
1656
{
1642
1657
return ;
1643
1658
}
1644
1659
1645
1660
int count = array . Length ;
1646
- _interner . Translator . Translate ( ref count ) ;
1661
+ Translate ( ref count ) ;
1647
1662
1648
1663
for ( int i = 0 ; i < count ; i ++ )
1649
1664
{
1650
- _interner . InternNullable ( array [ i ] ) ;
1665
+ _interner . Intern ( array [ i ] ) ;
1651
1666
}
1652
1667
}
1653
1668
1654
- public void InternPath ( ref string str , bool nullable )
1669
+ public void InternPath ( ref string str , bool nullable = true )
1655
1670
{
1656
- if ( ! IsInterning )
1671
+ if ( ! _isInterning )
1657
1672
{
1658
1673
Translate ( ref str ) ;
1674
+ return ;
1659
1675
}
1660
- else if ( nullable )
1661
- {
1662
- _interner . InternNullablePath ( str ) ;
1663
- }
1664
- else
1676
+
1677
+ if ( nullable && ! TranslateNullable ( str ) )
1665
1678
{
1666
- _interner . InternPath ( str ) ;
1679
+ return ;
1667
1680
}
1681
+
1682
+ _interner . InternPath ( str ) ;
1668
1683
}
1669
1684
}
1670
1685
}
0 commit comments