21
22
import type {CallServerCallback} from './ReactFlightReplyClient';
23
24
+import {enableBinaryFlight} from 'shared/ReactFeatureFlags';
25
+
26
import {
27
resolveClientReference,
28
preloadModule,
299
return new Chunk(INITIALIZED, value, null, response);
300
}
301
302
+function createInitializedBufferChunk(
303
+ response: Response,
304
+ value: $ArrayBufferView | ArrayBuffer,
305
+): InitializedChunk<Uint8Array> {
306
+ // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
307
+ return new Chunk(INITIALIZED, value, null, response);
308
+}
309
+
310
function resolveModelChunk<T>(
311
chunk: SomeChunk<T>,
312
value: UninitializedModel,
748
chunks.set(id, createInitializedTextChunk(response, text));
749
}
750
751
+function resolveBuffer(
752
+ response: Response,
753
+ id: number,
754
+ buffer: $ArrayBufferView | ArrayBuffer,
755
+): void {
756
+ const chunks = response._chunks;
757
+ // We assume that we always reference buffers after they've been emitted.
758
+ chunks.set(id, createInitializedBufferChunk(response, buffer));
759
+}
760
+
761
function resolveModule(
762
response: Response,
763
id: number,
876
dispatchHint(code, hintModel);
877
}
878
879
+function mergeBuffer(
880
+ buffer: Array<Uint8Array>,
881
+ lastChunk: Uint8Array,
882
+): Uint8Array {
883
+ const l = buffer.length;
884
+ // Count the bytes we'll need
885
+ let byteLength = lastChunk.length;
886
+ for (let i = 0; i < l; i++) {
887
+ byteLength += buffer[i].byteLength;
888
+ }
889
+ // Allocate enough contiguous space
890
+ const result = new Uint8Array(byteLength);
891
+ let offset = 0;
892
+ // Copy all the buffers into it.
893
+ for (let i = 0; i < l; i++) {
894
+ const chunk = buffer[i];
895
+ result.set(chunk, offset);
896
+ offset += chunk.byteLength;
897
+ }
898
+ result.set(lastChunk, offset);
899
+ return result;
900
+}
901
+
902
+function resolveTypedArray(
903
+ response: Response,
904
+ id: number,
905
+ buffer: Array<Uint8Array>,
906
+ lastChunk: Uint8Array,
907
+ constructor: any,
908
+ bytesPerElement: number,
909
+): void {
910
+ // If the view fits into one original buffer, we just reuse that buffer instead of
911
+ // copying it out to a separate copy. This means that it's not always possible to
912
+ // transfer these values to other threads without copying first since they may
913
+ // share array buffer. For this to work, it must also have bytes aligned to a
914
+ // multiple of a size of the type.
915
+ const chunk =
916
+ buffer.length === 0 && lastChunk.byteOffset % bytesPerElement === 0
917
+ ? lastChunk
918
+ : mergeBuffer(buffer, lastChunk);
919
+ // TODO: The transfer protocol of RSC is little-endian. If the client isn't little-endian
920
+ // we should convert it instead. In practice big endian isn't really Web compatible so it's
921
+ // somewhat safe to assume that browsers aren't going to run it, but maybe there's some SSR
922
+ // server that's affected.
923
+ const view: $ArrayBufferView = new constructor(
924
+ chunk.buffer,
925
+ chunk.byteOffset,
926
+ chunk.byteLength / bytesPerElement,
927
+ );
928
+ resolveBuffer(response, id, view);
929
+}
930
+
931
function processFullRow(
932
response: Response,
933
id: number,
934
tag: number,
935
buffer: Array<Uint8Array>,
864
- lastChunk: string | Uint8Array,
936
+ chunk: Uint8Array,
937
): void {
866
- let row = '';
938
+ if (enableBinaryFlight) {
939
+ switch (tag) {
940
+ case 65 /* "A" */:
941
+ // We must always clone to extract it into a separate buffer instead of just a view.
942
+ resolveBuffer(response, id, mergeBuffer(buffer, chunk).buffer);
943
+ return;
944
+ case 67 /* "C" */:
945
+ resolveTypedArray(response, id, buffer, chunk, Int8Array, 1);
946
+ return;
947
+ case 99 /* "c" */:
948
+ resolveBuffer(
949
+ response,
950
+ id,
951
+ buffer.length === 0 ? chunk : mergeBuffer(buffer, chunk),
952
+ );
953
+ return;
954
+ case 85 /* "U" */:
955
+ resolveTypedArray(response, id, buffer, chunk, Uint8ClampedArray, 1);
956
+ return;
957
+ case 83 /* "S" */:
958
+ resolveTypedArray(response, id, buffer, chunk, Int16Array, 2);
959
+ return;
960
+ case 115 /* "s" */:
961
+ resolveTypedArray(response, id, buffer, chunk, Uint16Array, 2);
962
+ return;
963
+ case 76 /* "L" */:
964
+ resolveTypedArray(response, id, buffer, chunk, Int32Array, 4);
965
+ return;
966
+ case 108 /* "l" */:
967
+ resolveTypedArray(response, id, buffer, chunk, Uint32Array, 4);
968
+ return;
969
+ case 70 /* "F" */:
970
+ resolveTypedArray(response, id, buffer, chunk, Float32Array, 4);
971
+ return;
972
+ case 68 /* "D" */:
973
+ resolveTypedArray(response, id, buffer, chunk, Float64Array, 8);
974
+ return;
975
+ case 78 /* "N" */:
976
+ resolveTypedArray(response, id, buffer, chunk, BigInt64Array, 8);
977
+ return;
978
+ case 109 /* "m" */:
979
+ resolveTypedArray(response, id, buffer, chunk, BigUint64Array, 8);
980
+ return;
981
+ case 86 /* "V" */:
982
+ resolveTypedArray(response, id, buffer, chunk, DataView, 1);
983
+ return;
984
+ }
985
+ }
986
+
987
const stringDecoder = response._stringDecoder;
988
+ let row = '';
989
for (let i = 0; i < buffer.length; i++) {
869
- const chunk = buffer[i];
870
- row += readPartialStringChunk(stringDecoder, chunk);
871
- }
872
- if (typeof lastChunk === 'string') {
873
- row += lastChunk;
874
- } else {
875
- row += readFinalStringChunk(stringDecoder, lastChunk);
990
+ row += readPartialStringChunk(stringDecoder, buffer[i]);
991
}
992
+ row += readFinalStringChunk(stringDecoder, chunk);
993
switch (tag) {
994
case 73 /* "I" */: {
995
resolveModule(response, id, row);
1019
resolveText(response, id, row);
1020
return;
1021
}
906
- default: {
1022
+ default: /* """ "{" "[" "t" "f" "n" "0" - "9" */ {
1023
// We assume anything else is JSON.
1024
resolveModel(response, id, row);
1025
return;
1053
}
1054
case ROW_TAG: {
1055
const resolvedRowTag = chunk[i];
940
- if (resolvedRowTag === 84 /* "T" */) {
1056
+ if (
1057
+ resolvedRowTag === 84 /* "T" */ ||
1058
+ (enableBinaryFlight &&
1059
+ (resolvedRowTag === 65 /* "A" */ ||
1060
+ resolvedRowTag === 67 /* "C" */ ||
1061
+ resolvedRowTag === 99 /* "c" */ ||
1062
+ resolvedRowTag === 85 /* "U" */ ||
1063
+ resolvedRowTag === 83 /* "S" */ ||
1064
+ resolvedRowTag === 115 /* "s" */ ||
1065
+ resolvedRowTag === 76 /* "L" */ ||
1066
+ resolvedRowTag === 108 /* "l" */ ||
1067
+ resolvedRowTag === 70 /* "F" */ ||
1068
+ resolvedRowTag === 68 /* "D" */ ||
1069
+ resolvedRowTag === 78 /* "N" */ ||
1070
+ resolvedRowTag === 109 /* "m" */ ||
1071
+ resolvedRowTag === 86)) /* "V" */
1072
+ ) {
1073
rowTag = resolvedRowTag;
1074
rowState = ROW_LENGTH;
1075
i++;