1111using System . Linq ;
1212using System . Linq . Expressions ;
1313using System . Numerics ;
14- using System . Runtime . InteropServices ;
1514using System . Text ;
1615
1716using Microsoft . Scripting . Runtime ;
1817using Microsoft . Scripting . Utils ;
1918
2019using IronPython . Runtime . Operations ;
2120using IronPython . Runtime . Types ;
22- using IronPython . Hosting ;
21+ using NotNullWhenAttribute = System . Diagnostics . CodeAnalysis . NotNullWhenAttribute ;
2322
2423namespace IronPython . Runtime {
2524 [ PythonType ( "bytes" ) , Serializable ]
@@ -31,53 +30,110 @@ public Bytes() {
3130 _bytes = new byte [ 0 ] ;
3231 }
3332
34- public Bytes ( [ NotNull ] IEnumerable < byte > bytes ) {
33+ public Bytes ( [ NotNull ] Bytes bytes ) {
34+ _bytes = bytes . _bytes ;
35+ }
36+
37+ public Bytes ( [ NotNull ] IEnumerable < byte > bytes ) {
3538 _bytes = bytes . ToArray ( ) ;
3639 }
3740
38- public Bytes ( [ BytesLike , NotNull ] IBufferProtocol source ) {
41+ public Bytes ( [ NotNull ] IBufferProtocol source ) {
3942 using IPythonBuffer buffer = source . GetBuffer ( BufferFlags . FullRO ) ;
4043 _bytes = buffer . ToArray ( ) ;
4144 }
4245
43- public Bytes ( CodeContext context , object ? source ) {
44- if ( PythonTypeOps . TryInvokeUnaryOperator ( context , source , "__bytes__" , out object ? res ) ) {
45- if ( res is Bytes bytes ) {
46- _bytes = bytes . _bytes ;
46+ [ StaticExtensionMethod ]
47+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls ) {
48+ if ( cls == TypeCache . Bytes ) {
49+ return Empty ;
50+ } else {
51+ return cls . CreateInstance ( context ) ;
52+ }
53+ }
54+
55+ [ StaticExtensionMethod ]
56+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls , [ NotNull ] IBufferProtocol source ) {
57+ if ( cls == TypeCache . Bytes ) {
58+ if ( source . GetType ( ) == typeof ( Bytes ) ) {
59+ return source ;
60+ } else if ( TryInvokeBytesOperator ( context , source , out Bytes ? res ) ) {
61+ return res ;
4762 } else {
48- throw PythonOps . TypeError ( "__bytes__ returned non-bytes (got '{0}' from type '{1}')" , PythonOps . GetPythonTypeName ( res ) , PythonOps . GetPythonTypeName ( source ) ) ;
63+ return new Bytes ( source ) ;
4964 }
50- } else if ( Converter . TryConvertToIndex ( source , throwOverflowError : true , out int size ) ) {
51- if ( size < 0 ) throw PythonOps . ValueError ( "negative count" ) ;
52- _bytes = new byte [ size ] ;
5365 } else {
54- _bytes = ByteArray . GetBytes ( source , useHint : true ) . ToArray ( ) ;
66+ return cls . CreateInstance ( context , __new__ ( context , TypeCache . Bytes , source ) ) ;
5567 }
5668 }
5769
58- public Bytes ( [ NotNull ] IEnumerable < object ? > source ) {
59- _bytes = source . Select ( b => ( ( int ) PythonOps . Index ( b ) ) . ToByteChecked ( ) ) . ToArray ( ) ;
70+ [ StaticExtensionMethod ]
71+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls , object ? @object ) {
72+ if ( cls == TypeCache . Bytes ) {
73+ return FromObject ( context , @object ) ;
74+ } else {
75+ return cls . CreateInstance ( context , __new__ ( context , TypeCache . Bytes , @object ) ) ;
76+ }
6077 }
6178
62- public Bytes ( [ NotNull ] PythonList bytes ) {
63- _bytes = ByteOps . GetBytes ( bytes ) . ToArray ( ) ;
79+ [ StaticExtensionMethod ]
80+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls , [ NotNull ] Extensible < int > size ) {
81+ if ( cls == TypeCache . Bytes ) {
82+ if ( TryInvokeBytesOperator ( context , size , out Bytes ? res ) ) {
83+ return res ;
84+ } else {
85+ if ( size < 0 ) throw PythonOps . ValueError ( "negative count" ) ;
86+ return new Bytes ( new byte [ size ] ) ;
87+ }
88+ } else {
89+ return cls . CreateInstance ( context , __new__ ( context , TypeCache . Bytes , size ) ) ;
90+ }
6491 }
6592
66- public Bytes ( int size ) {
67- if ( size < 0 ) throw PythonOps . ValueError ( "negative count" ) ;
68- _bytes = new byte [ size ] ;
93+ [ StaticExtensionMethod ]
94+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls , int size ) {
95+ if ( cls == TypeCache . Bytes ) {
96+ if ( size < 0 ) throw PythonOps . ValueError ( "negative count" ) ;
97+ return new Bytes ( new byte [ size ] ) ;
98+ } else {
99+ return cls . CreateInstance ( context , __new__ ( context , TypeCache . Bytes , size ) ) ;
100+ }
69101 }
70102
71- public Bytes ( [ NotNull ] string @string ) {
103+ [ StaticExtensionMethod ]
104+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls , [ NotNull ] ExtensibleString @string ) {
105+ if ( cls == TypeCache . Bytes ) {
106+ if ( TryInvokeBytesOperator ( context , @string , out Bytes ? res ) ) {
107+ return res ;
108+ } else {
109+ throw PythonOps . TypeError ( "string argument without an encoding" ) ;
110+ }
111+ } else {
112+ return cls . CreateInstance ( context , __new__ ( context , TypeCache . Bytes , @string ) ) ;
113+ }
114+ }
115+
116+ [ StaticExtensionMethod ]
117+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls , [ NotNull ] string @string ) {
72118 throw PythonOps . TypeError ( "string argument without an encoding" ) ;
73119 }
74120
75- public Bytes ( CodeContext context , [ NotNull ] string @string , [ NotNull ] string encoding ) {
76- _bytes = StringOps . encode ( context , @string , encoding , "strict" ) . UnsafeByteArray ;
121+ [ StaticExtensionMethod ]
122+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls , [ NotNull ] string @string , [ NotNull ] string encoding ) {
123+ if ( cls == TypeCache . Bytes ) {
124+ return StringOps . encode ( context , @string , encoding ) ;
125+ } else {
126+ return cls . CreateInstance ( context , __new__ ( context , TypeCache . Bytes , @string , encoding ) ) ;
127+ }
77128 }
78129
79- public Bytes ( CodeContext context , [ NotNull ] string @string , [ NotNull ] string encoding , [ NotNull ] string errors ) {
80- _bytes = StringOps . encode ( context , @string , encoding , errors ) . UnsafeByteArray ;
130+ [ StaticExtensionMethod ]
131+ public static object __new__ ( CodeContext context , [ NotNull ] PythonType cls , [ NotNull ] string @string , [ NotNull ] string encoding , [ NotNull ] string errors ) {
132+ if ( cls == TypeCache . Bytes ) {
133+ return StringOps . encode ( context , @string , encoding , errors ) ;
134+ } else {
135+ return cls . CreateInstance ( context , __new__ ( context , TypeCache . Bytes , @string , encoding , errors ) ) ;
136+ }
81137 }
82138
83139 private Bytes ( byte [ ] bytes ) {
@@ -89,6 +145,21 @@ private Bytes(byte[] bytes) {
89145 internal static Bytes FromByte ( byte b )
90146 => oneByteBytes [ b ] ;
91147
148+ internal static Bytes FromObject ( CodeContext context , object ? o ) {
149+ if ( o == null ) {
150+ throw PythonOps . TypeError ( "cannot convert 'NoneType' object to bytes" ) ;
151+ } else if ( o . GetType ( ) == typeof ( Bytes ) ) {
152+ return ( Bytes ) o ;
153+ } else if ( TryInvokeBytesOperator ( context , o , out Bytes ? res ) ) {
154+ return res ;
155+ } else if ( Converter . TryConvertToIndex ( o , throwOverflowError : true , out int size ) ) {
156+ if ( size < 0 ) throw PythonOps . ValueError ( "negative count" ) ;
157+ return new Bytes ( new byte [ size ] ) ;
158+ } else {
159+ return new Bytes ( ByteOps . GetBytes ( o , useHint : true , context ) . ToArray ( ) ) ;
160+ }
161+ }
162+
92163 internal static Bytes Make ( byte [ ] bytes )
93164 => new Bytes ( bytes ) ;
94165
@@ -364,7 +435,7 @@ public Bytes join(object? sequence) {
364435
365436 public Bytes join ( [ NotNull ] PythonList sequence ) {
366437 if ( sequence . __len__ ( ) == 0 ) {
367- return new Bytes ( ) ;
438+ return Empty ;
368439 } else if ( sequence . __len__ ( ) == 1 ) {
369440 return JoinOne ( sequence [ 0 ] ) ;
370441 }
@@ -892,6 +963,20 @@ internal ReadOnlyMemory<byte> AsMemory() {
892963 return _bytes . AsMemory ( ) ;
893964 }
894965
966+ private static bool TryInvokeBytesOperator ( CodeContext context , object ? obj , [ NotNullWhen ( true ) ] out Bytes ? bytes ) {
967+ if ( PythonTypeOps . TryInvokeUnaryOperator ( context , obj , "__bytes__" , out object ? res ) ) {
968+ if ( res is Bytes b ) {
969+ bytes = b ;
970+ return true ;
971+ } else {
972+ throw PythonOps . TypeError ( "__bytes__ returned non-bytes (got '{0}' from type '{1}')" , PythonOps . GetPythonTypeName ( res ) , PythonOps . GetPythonTypeName ( obj ) ) ;
973+ }
974+ } else {
975+ bytes = null ;
976+ return false ;
977+ }
978+ }
979+
895980 private static Bytes JoinOne ( object ? curVal ) {
896981 if ( curVal ? . GetType ( ) == typeof ( Bytes ) ) {
897982 return ( Bytes ) curVal ;
0 commit comments