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