diff --git a/apiCount.include.md b/apiCount.include.md
index 200d7720..bf6bbc26 100644
--- a/apiCount.include.md
+++ b/apiCount.include.md
@@ -1,28 +1,28 @@
-**API count: 1016**
+**API count: 1020**
 
 ### Per Target Framework
 
 | Target | APIs |
 | -- | -- |
-| `net461` | 963 |
-| `net462` | 963 |
-| `net47` | 962 |
-| `net471` | 961 |
-| `net472` | 957 |
-| `net48` | 957 |
-| `net481` | 957 |
-| `netstandard2.0` | 959 |
-| `netstandard2.1` | 811 |
-| `netcoreapp2.0` | 880 |
-| `netcoreapp2.1` | 822 |
-| `netcoreapp2.2` | 822 |
-| `netcoreapp3.0` | 769 |
-| `netcoreapp3.1` | 768 |
-| `net5.0` | 640 |
-| `net6.0` | 545 |
-| `net7.0` | 392 |
-| `net8.0` | 273 |
-| `net9.0` | 179 |
-| `net10.0` | 126 |
-| `net11.0` | 58 |
-| `uap10.0` | 949 |
+| `net461` | 967 |
+| `net462` | 967 |
+| `net47` | 966 |
+| `net471` | 965 |
+| `net472` | 961 |
+| `net48` | 961 |
+| `net481` | 961 |
+| `netstandard2.0` | 963 |
+| `netstandard2.1` | 815 |
+| `netcoreapp2.0` | 884 |
+| `netcoreapp2.1` | 826 |
+| `netcoreapp2.2` | 826 |
+| `netcoreapp3.0` | 773 |
+| `netcoreapp3.1` | 772 |
+| `net5.0` | 644 |
+| `net6.0` | 549 |
+| `net7.0` | 396 |
+| `net8.0` | 277 |
+| `net9.0` | 183 |
+| `net10.0` | 130 |
+| `net11.0` | 62 |
+| `uap10.0` | 953 |
diff --git a/api_list.include.md b/api_list.include.md
index a1d1ab73..ec671003 100644
--- a/api_list.include.md
+++ b/api_list.include.md
@@ -1505,3 +1505,11 @@
 
 #### UnreachableException
 
+#### StringStream
+
+#### ReadOnlyMemoryStream
+
+#### WritableMemoryStream
+
+#### ReadOnlySequenceStream
+
diff --git a/assemblySize.include.md b/assemblySize.include.md
index 8bab779b..27bcf822 100644
--- a/assemblySize.include.md
+++ b/assemblySize.include.md
@@ -2,51 +2,51 @@
 
 |                | Empty Assembly | With Polyfill | Diff      | Ensure    | ArgumentExceptions | StringInterpolation | Nullability |
 |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------|
-| netstandard2.0 |          8.0KB |       342.5KB |  +334.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netstandard2.1 |          8.5KB |       297.0KB |  +288.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net461         |          8.5KB |       341.0KB |  +332.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net462         |          7.0KB |       345.0KB |  +338.0KB |    +8.5KB |             +6.0KB |              +9.0KB |     +13.5KB |
-| net47          |          7.0KB |       344.5KB |  +337.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net471         |          8.5KB |       343.5KB |  +335.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net472         |          8.5KB |       342.5KB |  +334.0KB |    +8.5KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net48          |          8.5KB |       342.5KB |  +334.0KB |    +8.5KB |             +6.0KB |              +9.0KB |     +13.5KB |
-| net481         |          8.5KB |       342.5KB |  +334.0KB |    +8.5KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp2.0  |          9.0KB |       318.5KB |  +309.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp2.1  |          9.0KB |       299.5KB |  +290.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp2.2  |          9.0KB |       299.5KB |  +290.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp3.0  |          9.5KB |       292.0KB |  +282.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp3.1  |          9.5KB |       290.0KB |  +280.5KB |    +9.0KB |             +6.5KB |              +9.5KB |     +14.0KB |
-| net5.0         |          9.5KB |       254.0KB |  +244.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +14.0KB |
-| net6.0         |         10.0KB |       195.0KB |  +185.0KB |   +10.0KB |             +7.0KB |              +1.0KB |      +3.5KB |
-| net7.0         |         10.0KB |       157.5KB |  +147.5KB |    +9.5KB |             +5.5KB |           +512bytes |      +3.5KB |
-| net8.0         |          9.5KB |       129.0KB |  +119.5KB |    +8.5KB |                    |           +512bytes |      +3.5KB |
-| net9.0         |          9.5KB |        82.5KB |   +73.0KB |    +8.5KB |                    |           +512bytes |      +3.5KB |
-| net10.0        |         10.0KB |        60.0KB |   +50.0KB |    +9.0KB |                    |           +512bytes |      +3.5KB |
-| net11.0        |         10.0KB |        20.5KB |   +10.5KB |    +9.0KB |                    |           +512bytes |      +3.5KB |
+| netstandard2.0 |          8.0KB |       347.5KB |  +339.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +14.0KB |
+| netstandard2.1 |          8.5KB |       302.0KB |  +293.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +14.0KB |
+| net461         |          8.5KB |       346.5KB |  +338.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net462         |          7.0KB |       350.0KB |  +343.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net47          |          7.0KB |       349.5KB |  +342.5KB |    +9.0KB |             +6.5KB |              +9.5KB |     +14.0KB |
+| net471         |          8.5KB |       349.0KB |  +340.5KB |    +9.0KB |             +6.0KB |              +9.0KB |     +13.5KB |
+| net472         |          8.5KB |       347.5KB |  +339.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net48          |          8.5KB |       347.5KB |  +339.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net481         |          8.5KB |       347.5KB |  +339.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| netcoreapp2.0  |          9.0KB |       323.5KB |  +314.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| netcoreapp2.1  |          9.0KB |       304.5KB |  +295.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| netcoreapp2.2  |          9.0KB |       304.5KB |  +295.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| netcoreapp3.0  |          9.5KB |       297.0KB |  +287.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +14.0KB |
+| netcoreapp3.1  |          9.5KB |       295.5KB |  +286.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net5.0         |          9.5KB |       259.0KB |  +249.5KB |    +9.0KB |             +6.5KB |              +9.5KB |     +14.0KB |
+| net6.0         |         10.0KB |       201.0KB |  +191.0KB |   +10.0KB |             +6.5KB |           +512bytes |      +3.5KB |
+| net7.0         |         10.0KB |       163.5KB |  +153.5KB |    +9.0KB |             +5.5KB |           +512bytes |      +3.0KB |
+| net8.0         |          9.5KB |       135.0KB |  +125.5KB |    +8.0KB |                    |           +512bytes |      +3.0KB |
+| net9.0         |          9.5KB |        88.5KB |   +79.0KB |    +8.5KB |                    |           +512bytes |      +3.5KB |
+| net10.0        |         10.0KB |        66.0KB |   +56.0KB |    +9.0KB |                    |           +512bytes |      +3.5KB |
+| net11.0        |         10.0KB |        27.0KB |   +17.0KB |    +9.0KB |                    |              +1.0KB |      +3.5KB |
 
 
 ### Assembly Sizes with EmbedUntrackedSources
 
 |                | Empty Assembly | With Polyfill | Diff      | Ensure    | ArgumentExceptions | StringInterpolation | Nullability |
 |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------|
-| netstandard2.0 |          8.0KB |       498.3KB |  +490.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netstandard2.1 |          8.5KB |       427.1KB |  +418.6KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net461         |          8.5KB |       497.8KB |  +489.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net462         |          7.0KB |       501.8KB |  +494.8KB |   +16.2KB |             +7.7KB |             +13.9KB |     +18.9KB |
-| net47          |          7.0KB |       501.1KB |  +494.1KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net471         |          8.5KB |       499.7KB |  +491.2KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net472         |          8.5KB |       497.7KB |  +489.2KB |   +16.2KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net48          |          8.5KB |       497.7KB |  +489.2KB |   +16.2KB |             +7.7KB |             +13.9KB |     +18.9KB |
-| net481         |          8.5KB |       497.7KB |  +489.2KB |   +16.2KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp2.0  |          9.0KB |       463.7KB |  +454.7KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp2.1  |          9.0KB |       433.3KB |  +424.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp2.2  |          9.0KB |       433.3KB |  +424.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp3.0  |          9.5KB |       417.0KB |  +407.5KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp3.1  |          9.5KB |       415.0KB |  +405.5KB |   +16.7KB |             +8.2KB |             +14.4KB |     +19.4KB |
-| net5.0         |          9.5KB |       360.8KB |  +351.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +19.4KB |
-| net6.0         |         10.0KB |       281.8KB |  +271.8KB |   +17.7KB |             +8.7KB |              +1.6KB |      +4.2KB |
-| net7.0         |         10.0KB |       225.8KB |  +215.8KB |   +17.1KB |             +6.9KB |              +1.1KB |      +4.2KB |
-| net8.0         |          9.5KB |       182.2KB |  +172.7KB |   +16.0KB |          +299bytes |              +1.1KB |      +4.2KB |
-| net9.0         |          9.5KB |       114.7KB |  +105.2KB |   +16.0KB |                    |              +1.1KB |      +4.2KB |
-| net10.0        |         10.0KB |        83.9KB |   +73.9KB |   +16.5KB |                    |              +1.1KB |      +4.2KB |
-| net11.0        |         10.0KB |        30.3KB |   +20.3KB |   +16.5KB |                    |              +1.1KB |      +4.2KB |
+| netstandard2.0 |          8.0KB |       507.8KB |  +499.8KB |   +16.7KB |             +8.2KB |             +13.9KB |     +19.4KB |
+| netstandard2.1 |          8.5KB |       436.6KB |  +428.1KB |   +16.7KB |             +8.2KB |             +13.9KB |     +19.4KB |
+| net461         |          8.5KB |       507.8KB |  +499.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net462         |          7.0KB |       511.3KB |  +504.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net47          |          7.0KB |       510.6KB |  +503.6KB |   +16.7KB |             +8.2KB |             +14.4KB |     +19.4KB |
+| net471         |          8.5KB |       509.7KB |  +501.2KB |   +16.7KB |             +7.7KB |             +13.9KB |     +18.9KB |
+| net472         |          8.5KB |       507.2KB |  +498.7KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net48          |          8.5KB |       507.2KB |  +498.7KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net481         |          8.5KB |       507.2KB |  +498.7KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| netcoreapp2.0  |          9.0KB |       473.2KB |  +464.2KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| netcoreapp2.1  |          9.0KB |       442.8KB |  +433.8KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| netcoreapp2.2  |          9.0KB |       442.8KB |  +433.8KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| netcoreapp3.0  |          9.5KB |       426.5KB |  +417.0KB |   +16.7KB |             +8.2KB |             +13.9KB |     +19.4KB |
+| netcoreapp3.1  |          9.5KB |       425.0KB |  +415.5KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net5.0         |          9.5KB |       370.3KB |  +360.8KB |   +16.7KB |             +8.2KB |             +14.4KB |     +19.4KB |
+| net6.0         |         10.0KB |       292.3KB |  +282.3KB |   +17.7KB |             +8.2KB |              +1.1KB |      +4.2KB |
+| net7.0         |         10.0KB |       236.2KB |  +226.2KB |   +16.6KB |             +6.9KB |              +1.1KB |      +3.7KB |
+| net8.0         |          9.5KB |       192.7KB |  +183.2KB |   +15.5KB |          +299bytes |              +1.1KB |      +3.7KB |
+| net9.0         |          9.5KB |       125.2KB |  +115.7KB |   +16.0KB |                    |              +1.1KB |      +4.2KB |
+| net10.0        |         10.0KB |        94.4KB |   +84.4KB |   +16.5KB |                    |              +1.1KB |      +4.2KB |
+| net11.0        |         10.0KB |        41.3KB |   +31.3KB |   +16.5KB |                    |              +1.6KB |      +4.2KB |
diff --git a/readme.md b/readme.md
index 63ae2db0..f3a2578c 100644
--- a/readme.md
+++ b/readme.md
@@ -13,34 +13,34 @@ The package targets `netstandard2.0` and is designed to support the following ru
  * `uap10`
 
 
-**API count: 1016**<!-- include: apiCount. path: /apiCount.include.md -->
+**API count: 1020**<!-- include: apiCount. path: /apiCount.include.md -->
 
 ### Per Target Framework
 
 | Target | APIs |
 | -- | -- |
-| `net461` | 963 |
-| `net462` | 963 |
-| `net47` | 962 |
-| `net471` | 961 |
-| `net472` | 957 |
-| `net48` | 957 |
-| `net481` | 957 |
-| `netstandard2.0` | 959 |
-| `netstandard2.1` | 811 |
-| `netcoreapp2.0` | 880 |
-| `netcoreapp2.1` | 822 |
-| `netcoreapp2.2` | 822 |
-| `netcoreapp3.0` | 769 |
-| `netcoreapp3.1` | 768 |
-| `net5.0` | 640 |
-| `net6.0` | 545 |
-| `net7.0` | 392 |
-| `net8.0` | 273 |
-| `net9.0` | 179 |
-| `net10.0` | 126 |
-| `net11.0` | 58 |
-| `uap10.0` | 949 |
+| `net461` | 967 |
+| `net462` | 967 |
+| `net47` | 966 |
+| `net471` | 965 |
+| `net472` | 961 |
+| `net48` | 961 |
+| `net481` | 961 |
+| `netstandard2.0` | 963 |
+| `netstandard2.1` | 815 |
+| `netcoreapp2.0` | 884 |
+| `netcoreapp2.1` | 826 |
+| `netcoreapp2.2` | 826 |
+| `netcoreapp3.0` | 773 |
+| `netcoreapp3.1` | 772 |
+| `net5.0` | 644 |
+| `net6.0` | 549 |
+| `net7.0` | 396 |
+| `net8.0` | 277 |
+| `net9.0` | 183 |
+| `net10.0` | 130 |
+| `net11.0` | 62 |
+| `uap10.0` | 953 |
 <!-- endInclude -->
 
 
@@ -96,54 +96,54 @@ This project uses features from the newest stable SDK and C# language. As such c
 
 |                | Empty Assembly | With Polyfill | Diff      | Ensure    | ArgumentExceptions | StringInterpolation | Nullability |
 |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------|
-| netstandard2.0 |          8.0KB |       342.5KB |  +334.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netstandard2.1 |          8.5KB |       297.0KB |  +288.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net461         |          8.5KB |       341.0KB |  +332.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net462         |          7.0KB |       345.0KB |  +338.0KB |    +8.5KB |             +6.0KB |              +9.0KB |     +13.5KB |
-| net47          |          7.0KB |       344.5KB |  +337.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net471         |          8.5KB |       343.5KB |  +335.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net472         |          8.5KB |       342.5KB |  +334.0KB |    +8.5KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| net48          |          8.5KB |       342.5KB |  +334.0KB |    +8.5KB |             +6.0KB |              +9.0KB |     +13.5KB |
-| net481         |          8.5KB |       342.5KB |  +334.0KB |    +8.5KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp2.0  |          9.0KB |       318.5KB |  +309.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp2.1  |          9.0KB |       299.5KB |  +290.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp2.2  |          9.0KB |       299.5KB |  +290.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp3.0  |          9.5KB |       292.0KB |  +282.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
-| netcoreapp3.1  |          9.5KB |       290.0KB |  +280.5KB |    +9.0KB |             +6.5KB |              +9.5KB |     +14.0KB |
-| net5.0         |          9.5KB |       254.0KB |  +244.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +14.0KB |
-| net6.0         |         10.0KB |       195.0KB |  +185.0KB |   +10.0KB |             +7.0KB |              +1.0KB |      +3.5KB |
-| net7.0         |         10.0KB |       157.5KB |  +147.5KB |    +9.5KB |             +5.5KB |           +512bytes |      +3.5KB |
-| net8.0         |          9.5KB |       129.0KB |  +119.5KB |    +8.5KB |                    |           +512bytes |      +3.5KB |
-| net9.0         |          9.5KB |        82.5KB |   +73.0KB |    +8.5KB |                    |           +512bytes |      +3.5KB |
-| net10.0        |         10.0KB |        60.0KB |   +50.0KB |    +9.0KB |                    |           +512bytes |      +3.5KB |
-| net11.0        |         10.0KB |        20.5KB |   +10.5KB |    +9.0KB |                    |           +512bytes |      +3.5KB |
+| netstandard2.0 |          8.0KB |       347.5KB |  +339.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +14.0KB |
+| netstandard2.1 |          8.5KB |       302.0KB |  +293.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +14.0KB |
+| net461         |          8.5KB |       346.5KB |  +338.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net462         |          7.0KB |       350.0KB |  +343.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net47          |          7.0KB |       349.5KB |  +342.5KB |    +9.0KB |             +6.5KB |              +9.5KB |     +14.0KB |
+| net471         |          8.5KB |       349.0KB |  +340.5KB |    +9.0KB |             +6.0KB |              +9.0KB |     +13.5KB |
+| net472         |          8.5KB |       347.5KB |  +339.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net48          |          8.5KB |       347.5KB |  +339.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net481         |          8.5KB |       347.5KB |  +339.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| netcoreapp2.0  |          9.0KB |       323.5KB |  +314.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| netcoreapp2.1  |          9.0KB |       304.5KB |  +295.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| netcoreapp2.2  |          9.0KB |       304.5KB |  +295.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| netcoreapp3.0  |          9.5KB |       297.0KB |  +287.5KB |    +9.0KB |             +6.5KB |              +9.0KB |     +14.0KB |
+| netcoreapp3.1  |          9.5KB |       295.5KB |  +286.0KB |    +9.0KB |             +6.5KB |              +9.0KB |     +13.5KB |
+| net5.0         |          9.5KB |       259.0KB |  +249.5KB |    +9.0KB |             +6.5KB |              +9.5KB |     +14.0KB |
+| net6.0         |         10.0KB |       201.0KB |  +191.0KB |   +10.0KB |             +6.5KB |           +512bytes |      +3.5KB |
+| net7.0         |         10.0KB |       163.5KB |  +153.5KB |    +9.0KB |             +5.5KB |           +512bytes |      +3.0KB |
+| net8.0         |          9.5KB |       135.0KB |  +125.5KB |    +8.0KB |                    |           +512bytes |      +3.0KB |
+| net9.0         |          9.5KB |        88.5KB |   +79.0KB |    +8.5KB |                    |           +512bytes |      +3.5KB |
+| net10.0        |         10.0KB |        66.0KB |   +56.0KB |    +9.0KB |                    |           +512bytes |      +3.5KB |
+| net11.0        |         10.0KB |        27.0KB |   +17.0KB |    +9.0KB |                    |              +1.0KB |      +3.5KB |
 
 
 ### Assembly Sizes with EmbedUntrackedSources
 
 |                | Empty Assembly | With Polyfill | Diff      | Ensure    | ArgumentExceptions | StringInterpolation | Nullability |
 |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------|
-| netstandard2.0 |          8.0KB |       498.3KB |  +490.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netstandard2.1 |          8.5KB |       427.1KB |  +418.6KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net461         |          8.5KB |       497.8KB |  +489.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net462         |          7.0KB |       501.8KB |  +494.8KB |   +16.2KB |             +7.7KB |             +13.9KB |     +18.9KB |
-| net47          |          7.0KB |       501.1KB |  +494.1KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net471         |          8.5KB |       499.7KB |  +491.2KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net472         |          8.5KB |       497.7KB |  +489.2KB |   +16.2KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| net48          |          8.5KB |       497.7KB |  +489.2KB |   +16.2KB |             +7.7KB |             +13.9KB |     +18.9KB |
-| net481         |          8.5KB |       497.7KB |  +489.2KB |   +16.2KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp2.0  |          9.0KB |       463.7KB |  +454.7KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp2.1  |          9.0KB |       433.3KB |  +424.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp2.2  |          9.0KB |       433.3KB |  +424.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp3.0  |          9.5KB |       417.0KB |  +407.5KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
-| netcoreapp3.1  |          9.5KB |       415.0KB |  +405.5KB |   +16.7KB |             +8.2KB |             +14.4KB |     +19.4KB |
-| net5.0         |          9.5KB |       360.8KB |  +351.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +19.4KB |
-| net6.0         |         10.0KB |       281.8KB |  +271.8KB |   +17.7KB |             +8.7KB |              +1.6KB |      +4.2KB |
-| net7.0         |         10.0KB |       225.8KB |  +215.8KB |   +17.1KB |             +6.9KB |              +1.1KB |      +4.2KB |
-| net8.0         |          9.5KB |       182.2KB |  +172.7KB |   +16.0KB |          +299bytes |              +1.1KB |      +4.2KB |
-| net9.0         |          9.5KB |       114.7KB |  +105.2KB |   +16.0KB |                    |              +1.1KB |      +4.2KB |
-| net10.0        |         10.0KB |        83.9KB |   +73.9KB |   +16.5KB |                    |              +1.1KB |      +4.2KB |
-| net11.0        |         10.0KB |        30.3KB |   +20.3KB |   +16.5KB |                    |              +1.1KB |      +4.2KB |
+| netstandard2.0 |          8.0KB |       507.8KB |  +499.8KB |   +16.7KB |             +8.2KB |             +13.9KB |     +19.4KB |
+| netstandard2.1 |          8.5KB |       436.6KB |  +428.1KB |   +16.7KB |             +8.2KB |             +13.9KB |     +19.4KB |
+| net461         |          8.5KB |       507.8KB |  +499.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net462         |          7.0KB |       511.3KB |  +504.3KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net47          |          7.0KB |       510.6KB |  +503.6KB |   +16.7KB |             +8.2KB |             +14.4KB |     +19.4KB |
+| net471         |          8.5KB |       509.7KB |  +501.2KB |   +16.7KB |             +7.7KB |             +13.9KB |     +18.9KB |
+| net472         |          8.5KB |       507.2KB |  +498.7KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net48          |          8.5KB |       507.2KB |  +498.7KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net481         |          8.5KB |       507.2KB |  +498.7KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| netcoreapp2.0  |          9.0KB |       473.2KB |  +464.2KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| netcoreapp2.1  |          9.0KB |       442.8KB |  +433.8KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| netcoreapp2.2  |          9.0KB |       442.8KB |  +433.8KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| netcoreapp3.0  |          9.5KB |       426.5KB |  +417.0KB |   +16.7KB |             +8.2KB |             +13.9KB |     +19.4KB |
+| netcoreapp3.1  |          9.5KB |       425.0KB |  +415.5KB |   +16.7KB |             +8.2KB |             +13.9KB |     +18.9KB |
+| net5.0         |          9.5KB |       370.3KB |  +360.8KB |   +16.7KB |             +8.2KB |             +14.4KB |     +19.4KB |
+| net6.0         |         10.0KB |       292.3KB |  +282.3KB |   +17.7KB |             +8.2KB |              +1.1KB |      +4.2KB |
+| net7.0         |         10.0KB |       236.2KB |  +226.2KB |   +16.6KB |             +6.9KB |              +1.1KB |      +3.7KB |
+| net8.0         |          9.5KB |       192.7KB |  +183.2KB |   +15.5KB |          +299bytes |              +1.1KB |      +3.7KB |
+| net9.0         |          9.5KB |       125.2KB |  +115.7KB |   +16.0KB |                    |              +1.1KB |      +4.2KB |
+| net10.0        |         10.0KB |        94.4KB |   +84.4KB |   +16.5KB |                    |              +1.1KB |      +4.2KB |
+| net11.0        |         10.0KB |        41.3KB |   +31.3KB |   +16.5KB |                    |              +1.6KB |      +4.2KB |
 <!-- endInclude -->
 
 
@@ -2035,6 +2035,14 @@ The class `Polyfill` includes the following extension methods:
 #### TaskCompletionSource
 
 #### UnreachableException
+
+#### StringStream
+
+#### ReadOnlyMemoryStream
+
+#### WritableMemoryStream
+
+#### ReadOnlySequenceStream
 <!-- endInclude -->
 
 
@@ -2233,7 +2241,7 @@ void ObjectDisposedExceptionExample(bool isDisposed)
     ObjectDisposedException.ThrowIf(isDisposed, typeof(Consume));
 }
 ```
-<sup><a href='/src/Consume/Consume.cs#L734-L758' title='Snippet source file'>snippet source</a> | <a href='#snippet-ArgumentExceptionUsage' title='Start of snippet'>anchor</a></sup>
+<sup><a href='/src/Consume/Consume.cs#L767-L791' title='Snippet source file'>snippet source</a> | <a href='#snippet-ArgumentExceptionUsage' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 
@@ -2252,7 +2260,7 @@ void EnsureExample(Order order, Customer customer, string customerId, string ema
     this.quantity = Ensure.NotNegativeOrZero(quantity);
 }
 ```
-<sup><a href='/src/Consume/Consume.cs#L764-L776' title='Snippet source file'>snippet source</a> | <a href='#snippet-EnsureUsage' title='Start of snippet'>anchor</a></sup>
+<sup><a href='/src/Consume/Consume.cs#L797-L809' title='Snippet source file'>snippet source</a> | <a href='#snippet-EnsureUsage' title='Start of snippet'>anchor</a></sup>
 <!-- endSnippet -->
 
 
diff --git a/src/ApiBuilderTests/BuildApiTest.cs b/src/ApiBuilderTests/BuildApiTest.cs
index 047b78a3..77d97df2 100644
--- a/src/ApiBuilderTests/BuildApiTest.cs
+++ b/src/ApiBuilderTests/BuildApiTest.cs
@@ -23,6 +23,10 @@ public Task RunWithRoslyn()
         WriteHelper("Utf16", writer, ref count);
         WriteType(nameof(TaskCompletionSource), writer, ref count);
         WriteType(nameof(UnreachableException), writer, ref count);
+        WriteType("StringStream", writer, ref count);
+        WriteType("ReadOnlyMemoryStream", writer, ref count);
+        WriteType("WritableMemoryStream", writer, ref count);
+        WriteType("ReadOnlySequenceStream", writer, ref count);
 
         count += Directory.EnumerateFiles(polyfillDir, "*Attribute.cs", SearchOption.AllDirectories).Count();
         // Index and Range
diff --git a/src/ApiBuilderTests/StreamWrapperBclDetectionTests.cs b/src/ApiBuilderTests/StreamWrapperBclDetectionTests.cs
new file mode 100644
index 00000000..fe4bda33
--- /dev/null
+++ b/src/ApiBuilderTests/StreamWrapperBclDetectionTests.cs
@@ -0,0 +1,84 @@
+using System.Text;
+
+/// <summary>
+/// The Stream wrapper types from dotnet/runtime#126669 (StringStream, ReadOnlyMemoryStream,
+/// WritableMemoryStream, ReadOnlySequenceStream) were approved/merged for net11 but are NOT in the
+/// current net11 preview/RC. Polyfill therefore ships them as ACTIVE on net11 too.
+///
+/// This project (ApiBuilderTests) targets net11.0 and does NOT compile the polyfill source into
+/// itself, so it keeps building once the BCL gains these types. This test runs on the net11 runtime
+/// and fails the moment the real types appear, telling you exactly which guards to flip.
+/// </summary>
+public class StreamWrapperBclDetectionTests
+{
+    static readonly (string FullName, string File)[] pending =
+    [
+        ("System.IO.StringStream", "StringStream.cs"),
+        ("System.IO.ReadOnlyMemoryStream", "ReadOnlyMemoryStream.cs"),
+        ("System.IO.WritableMemoryStream", "WritableMemoryStream.cs"),
+        ("System.Buffers.ReadOnlySequenceStream", "ReadOnlySequenceStream.cs"),
+    ];
+
+    [Test]
+    public void StreamWrapperPolyfillsStillNeededOnNet11()
+    {
+        var present = new List<(string FullName, string File, string Assembly)>();
+        foreach (var (fullName, file) in pending)
+        {
+            var type = FindBclType(fullName);
+            if (type != null)
+            {
+                present.Add((fullName, file, type.Assembly.GetName().Name!));
+            }
+        }
+
+        if (present.Count == 0)
+        {
+            return;
+        }
+
+        var builder = new StringBuilder();
+        builder.AppendLine($"{present.Count} Stream wrapper type(s) from dotnet/runtime#126669 are now provided by the BCL");
+        builder.AppendLine($"on this runtime ({System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}).");
+        builder.AppendLine("The matching Polyfill source now collides with the real type and must be retired for net11.");
+        builder.AppendLine("For EACH type below, edit the listed file under src/Polyfill/:");
+        builder.AppendLine();
+
+        foreach (var (fullName, file, assembly) in present)
+        {
+            builder.AppendLine($"  {fullName}  (now in {assembly})");
+            builder.AppendLine($"    file: src/Polyfill/{file}");
+            builder.AppendLine("    1. change `#if FeatureMemory` to `#if FeatureMemory && !NET11_0_OR_GREATER`");
+            builder.AppendLine("    2. append after the final #endif:");
+            builder.AppendLine("         #if NET11_0_OR_GREATER");
+            builder.AppendLine($"         [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof({fullName}))]");
+            builder.AppendLine("         #endif");
+            builder.AppendLine();
+        }
+
+        builder.AppendLine("Then re-run ApiBuilderTests in Debug to regenerate Split + api_list, and drop any now-redundant");
+        builder.AppendLine("usage from src/Consume/Consume.cs.");
+
+        throw new(builder.ToString());
+    }
+
+    static System.Type? FindBclType(string fullName)
+    {
+        foreach (var assembly in new[]
+                 {
+                     "System.Private.CoreLib",
+                     "System.Runtime",
+                     "System.Memory",
+                     "mscorlib"
+                 })
+        {
+            var type = System.Type.GetType($"{fullName}, {assembly}", throwOnError: false);
+            if (type is { IsPublic: true })
+            {
+                return type;
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/src/Consume/Consume.cs b/src/Consume/Consume.cs
index 443df782..cc72a8e8 100644
--- a/src/Consume/Consume.cs
+++ b/src/Consume/Consume.cs
@@ -258,6 +258,39 @@ void Base64UrlUsage()
     }
 #endif
 
+#if FeatureMemory
+    void StreamWrappersUsage()
+    {
+        var bytes = new byte[10];
+
+        using (Stream stringStream = new StringStream("text", Encoding.UTF8))
+        {
+            stringStream.Read(bytes, 0, bytes.Length);
+        }
+
+        using (var stringStream = new StringStream("text".AsMemory(), Encoding.UTF8))
+        {
+            Encoding encoding = stringStream.Encoding;
+            stringStream.ReadByte();
+        }
+
+        using (MemoryStream readOnly = new ReadOnlyMemoryStream(new ReadOnlyMemory<byte>(bytes)))
+        {
+            readOnly.Read(bytes, 0, bytes.Length);
+        }
+
+        using (MemoryStream writable = new WritableMemoryStream(new Memory<byte>(bytes)))
+        {
+            writable.Write(bytes, 0, bytes.Length);
+        }
+
+        using (Stream sequenceStream = new System.Buffers.ReadOnlySequenceStream(new System.Buffers.ReadOnlySequence<byte>(bytes)))
+        {
+            sequenceStream.Read(bytes, 0, bytes.Length);
+        }
+    }
+#endif
+
 #if FeatureMemory && !RefsBclMemory
     void Base64Usage()
     {
diff --git a/src/Polyfill/ReadOnlyMemoryStream.cs b/src/Polyfill/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..13bb791b
--- /dev/null
+++ b/src/Polyfill/ReadOnlyMemoryStream.cs
@@ -0,0 +1,74 @@
+#nullable enable
+
+// === Polyfill target window =====================================================================
+// System.IO.ReadOnlyMemoryStream was approved and merged into dotnet/runtime for net11
+// (https://github.com/dotnet/runtime/pull/126669) but is NOT in the current net11 preview/RC SDK,
+// so this polyfill is intentionally ACTIVE on net11 as well.
+// When you upgrade to a net11 SDK that actually ships this type, the build will collide (CS0436)
+// and the ApiBuilderTests "StreamWrapperBclDetectionTests" test FAILS with these exact steps.
+// To retire this polyfill for net11:
+//   1. change `#if FeatureMemory` below to `#if FeatureMemory && !NET11_0_OR_GREATER`
+//   2. add at the bottom of this file (after the final #endif):
+//        #if NET11_0_OR_GREATER
+//        [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.IO.ReadOnlyMemoryStream))]
+//        #endif
+//   3. re-run ApiBuilderTests in Debug to regenerate Split + api_list.
+// ================================================================================================
+#if FeatureMemory
+
+#pragma warning disable
+
+namespace System.IO;
+
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+//Link: https://learn.microsoft.com/en-us/dotnet/api/system.io.readonlymemorystream?view=net-11.0
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+    MemoryStream
+{
+    /// <summary>
+    /// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+    /// </summary>
+    //Link: https://learn.microsoft.com/en-us/dotnet/api/system.io.readonlymemorystream.-ctor?view=net-11.0
+    public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+        : base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+    {
+    }
+
+    static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+    {
+        if (MemoryMarshal.TryGetArray(source, out var segment) &&
+            segment.Array != null)
+        {
+            offset = segment.Offset;
+            count = segment.Count;
+            return segment.Array;
+        }
+
+        var array = source.ToArray();
+        offset = 0;
+        count = array.Length;
+        return array;
+    }
+}
+
+#endif
diff --git a/src/Polyfill/ReadOnlySequenceStream.cs b/src/Polyfill/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..be82092c
--- /dev/null
+++ b/src/Polyfill/ReadOnlySequenceStream.cs
@@ -0,0 +1,236 @@
+#nullable enable
+
+// === Polyfill target window =====================================================================
+// System.Buffers.ReadOnlySequenceStream was approved and merged into dotnet/runtime for net11
+// (https://github.com/dotnet/runtime/pull/126669) but is NOT in the current net11 preview/RC SDK,
+// so this polyfill is intentionally ACTIVE on net11 as well.
+// When you upgrade to a net11 SDK that actually ships this type, the build will collide (CS0436)
+// and the ApiBuilderTests "StreamWrapperBclDetectionTests" test FAILS with these exact steps.
+// To retire this polyfill for net11:
+//   1. change `#if FeatureMemory` below to `#if FeatureMemory && !NET11_0_OR_GREATER`
+//   2. add at the bottom of this file (after the final #endif):
+//        #if NET11_0_OR_GREATER
+//        [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Buffers.ReadOnlySequenceStream))]
+//        #endif
+//   3. re-run ApiBuilderTests in Debug to regenerate Split + api_list.
+// ================================================================================================
+#if FeatureMemory
+
+#pragma warning disable
+
+namespace System.Buffers;
+
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+//Link: https://learn.microsoft.com/en-us/dotnet/api/system.buffers.readonlysequencestream?view=net-11.0
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+    Stream
+{
+    ReadOnlySequence<byte> sequence;
+    long position;
+    bool disposed;
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+    /// </summary>
+    //Link: https://learn.microsoft.com/en-us/dotnet/api/system.buffers.readonlysequencestream.-ctor?view=net-11.0
+    public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+        sequence = source;
+
+    /// <inheritdoc/>
+    public override bool CanRead => !disposed;
+
+    /// <inheritdoc/>
+    public override bool CanSeek => !disposed;
+
+    /// <inheritdoc/>
+    public override bool CanWrite => false;
+
+    /// <inheritdoc/>
+    public override long Length
+    {
+        get
+        {
+            ThrowIfDisposed();
+            return sequence.Length;
+        }
+    }
+
+    /// <inheritdoc/>
+    public override long Position
+    {
+        get
+        {
+            ThrowIfDisposed();
+            return position;
+        }
+        set
+        {
+            ThrowIfDisposed();
+            if (value < 0)
+            {
+                throw new ArgumentOutOfRangeException(nameof(value));
+            }
+
+            position = value;
+        }
+    }
+
+    /// <inheritdoc/>
+    public override int Read(byte[] buffer, int offset, int count)
+    {
+        GuardRange(buffer, offset, count);
+        ThrowIfDisposed();
+
+        if (position >= sequence.Length)
+        {
+            return 0;
+        }
+
+        var remaining = sequence.Slice(position);
+        var toRead = (int)Math.Min(remaining.Length, count);
+        if (toRead <= 0)
+        {
+            return 0;
+        }
+
+        remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+        position += toRead;
+        return toRead;
+    }
+
+    /// <inheritdoc/>
+    public override int ReadByte()
+    {
+        ThrowIfDisposed();
+
+        if (position >= sequence.Length)
+        {
+            return -1;
+        }
+
+        var result = sequence.Slice(position, 1).First.Span[0];
+        position++;
+        return result;
+    }
+
+    /// <inheritdoc/>
+    public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+    {
+        GuardRange(buffer, offset, count);
+
+        if (cancellationToken.IsCancellationRequested)
+        {
+            return Task.FromCanceled<int>(cancellationToken);
+        }
+
+        try
+        {
+            return Task.FromResult(Read(buffer, offset, count));
+        }
+        catch (Exception exception)
+        {
+            return Task.FromException<int>(exception);
+        }
+    }
+
+    /// <inheritdoc/>
+    public override long Seek(long offset, SeekOrigin origin)
+    {
+        ThrowIfDisposed();
+
+        var basePosition = origin switch
+        {
+            SeekOrigin.Begin => 0L,
+            SeekOrigin.Current => position,
+            SeekOrigin.End => sequence.Length,
+            _ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+        };
+
+        var newPosition = basePosition + offset;
+        if (newPosition < 0)
+        {
+            throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+        }
+
+        position = newPosition;
+        return position;
+    }
+
+    /// <inheritdoc/>
+    public override void Flush()
+    {
+    }
+
+    /// <inheritdoc/>
+    public override Task FlushAsync(CancellationToken cancellationToken) =>
+        cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+
+    /// <inheritdoc/>
+    public override void SetLength(long value) =>
+        throw new NotSupportedException("Stream does not support writing.");
+
+    /// <inheritdoc/>
+    public override void Write(byte[] buffer, int offset, int count) =>
+        throw new NotSupportedException("Stream does not support writing.");
+
+    /// <inheritdoc/>
+    protected override void Dispose(bool disposing)
+    {
+        disposed = true;
+        sequence = default;
+        base.Dispose(disposing);
+    }
+
+    void ThrowIfDisposed()
+    {
+        if (disposed)
+        {
+            throw new ObjectDisposedException(GetType().FullName);
+        }
+    }
+
+    static void GuardRange(byte[] buffer, int offset, int count)
+    {
+        if (buffer == null)
+        {
+            throw new ArgumentNullException(nameof(buffer));
+        }
+
+        if (offset < 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(offset));
+        }
+
+        if (count < 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(count));
+        }
+
+        if (buffer.Length - offset < count)
+        {
+            throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+        }
+    }
+}
+
+#endif
diff --git a/src/Polyfill/StringStream.cs b/src/Polyfill/StringStream.cs
new file mode 100644
index 00000000..87cd6090
--- /dev/null
+++ b/src/Polyfill/StringStream.cs
@@ -0,0 +1,241 @@
+#nullable enable
+
+// === Polyfill target window =====================================================================
+// System.IO.StringStream was approved and merged into dotnet/runtime for net11
+// (https://github.com/dotnet/runtime/pull/126669) but is NOT in the current net11 preview/RC SDK,
+// so this polyfill is intentionally ACTIVE on net11 as well.
+// When you upgrade to a net11 SDK that actually ships this type, the build will collide (CS0436)
+// and the ApiBuilderTests "StreamWrapperBclDetectionTests" test FAILS with these exact steps.
+// To retire this polyfill for net11:
+//   1. change `#if FeatureMemory` below to `#if FeatureMemory && !NET11_0_OR_GREATER`
+//   2. add at the bottom of this file (after the final #endif):
+//        #if NET11_0_OR_GREATER
+//        [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.IO.StringStream))]
+//        #endif
+//   3. re-run ApiBuilderTests in Debug to regenerate Split + api_list.
+// ================================================================================================
+#if FeatureMemory
+
+#pragma warning disable
+
+namespace System.IO;
+
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+//Link: https://learn.microsoft.com/en-us/dotnet/api/system.io.stringstream?view=net-11.0
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+    Stream
+{
+    ReadOnlyMemory<char> text;
+    Encoding encoding;
+    byte[]? encoded;
+    int position;
+    bool disposed;
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+    /// </summary>
+    //Link: https://learn.microsoft.com/en-us/dotnet/api/system.io.stringstream.-ctor?view=net-11.0#system-io-stringstream-ctor(system-string-system-text-encoding)
+    public StringStream(string text, Encoding encoding)
+    {
+        if (text == null)
+        {
+            throw new ArgumentNullException(nameof(text));
+        }
+
+        if (encoding == null)
+        {
+            throw new ArgumentNullException(nameof(encoding));
+        }
+
+        this.text = text.AsMemory();
+        this.encoding = encoding;
+    }
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+    /// </summary>
+    //Link: https://learn.microsoft.com/en-us/dotnet/api/system.io.stringstream.-ctor?view=net-11.0#system-io-stringstream-ctor(system-readonlymemory((system-char))-system-text-encoding)
+    public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+    {
+        if (encoding == null)
+        {
+            throw new ArgumentNullException(nameof(encoding));
+        }
+
+        this.text = text;
+        this.encoding = encoding;
+    }
+
+    /// <summary>
+    /// Gets the encoding used by this stream.
+    /// </summary>
+    //Link: https://learn.microsoft.com/en-us/dotnet/api/system.io.stringstream.encoding?view=net-11.0
+    public Encoding Encoding => encoding;
+
+    /// <inheritdoc/>
+    public override bool CanRead => !disposed;
+
+    /// <inheritdoc/>
+    public override bool CanSeek => false;
+
+    /// <inheritdoc/>
+    public override bool CanWrite => false;
+
+    /// <inheritdoc/>
+    public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+
+    /// <inheritdoc/>
+    public override long Position
+    {
+        get => throw new NotSupportedException("Stream does not support seeking.");
+        set => throw new NotSupportedException("Stream does not support seeking.");
+    }
+
+    byte[] GetEncoded()
+    {
+        if (encoded == null)
+        {
+            var chars = text.ToArray();
+            encoded = encoding.GetBytes(chars, 0, chars.Length);
+        }
+
+        return encoded;
+    }
+
+    /// <inheritdoc/>
+    public override int Read(byte[] buffer, int offset, int count)
+    {
+        GuardRange(buffer, offset, count);
+        ThrowIfDisposed();
+
+        var all = GetEncoded();
+        var remaining = all.Length - position;
+        if (remaining <= 0 ||
+            count == 0)
+        {
+            return 0;
+        }
+
+        var toRead = Math.Min(remaining, count);
+        Array.Copy(all, position, buffer, offset, toRead);
+        position += toRead;
+        return toRead;
+    }
+
+    /// <inheritdoc/>
+    public override int ReadByte()
+    {
+        ThrowIfDisposed();
+
+        var all = GetEncoded();
+        if (position < all.Length)
+        {
+            return all[position++];
+        }
+
+        return -1;
+    }
+
+    /// <inheritdoc/>
+    public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+    {
+        GuardRange(buffer, offset, count);
+
+        if (cancellationToken.IsCancellationRequested)
+        {
+            return Task.FromCanceled<int>(cancellationToken);
+        }
+
+        try
+        {
+            return Task.FromResult(Read(buffer, offset, count));
+        }
+        catch (Exception exception)
+        {
+            return Task.FromException<int>(exception);
+        }
+    }
+
+    /// <inheritdoc/>
+    public override void Flush()
+    {
+    }
+
+    /// <inheritdoc/>
+    public override Task FlushAsync(CancellationToken cancellationToken) =>
+        cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+
+    /// <inheritdoc/>
+    public override long Seek(long offset, SeekOrigin origin) =>
+        throw new NotSupportedException("Stream does not support seeking.");
+
+    /// <inheritdoc/>
+    public override void SetLength(long value) =>
+        throw new NotSupportedException("Stream does not support writing.");
+
+    /// <inheritdoc/>
+    public override void Write(byte[] buffer, int offset, int count) =>
+        throw new NotSupportedException("Stream does not support writing.");
+
+    /// <inheritdoc/>
+    protected override void Dispose(bool disposing)
+    {
+        disposed = true;
+        base.Dispose(disposing);
+    }
+
+    void ThrowIfDisposed()
+    {
+        if (disposed)
+        {
+            throw new ObjectDisposedException(GetType().FullName);
+        }
+    }
+
+    static void GuardRange(byte[] buffer, int offset, int count)
+    {
+        if (buffer == null)
+        {
+            throw new ArgumentNullException(nameof(buffer));
+        }
+
+        if (offset < 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(offset));
+        }
+
+        if (count < 0)
+        {
+            throw new ArgumentOutOfRangeException(nameof(count));
+        }
+
+        if (buffer.Length - offset < count)
+        {
+            throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+        }
+    }
+}
+
+#endif
diff --git a/src/Polyfill/WritableMemoryStream.cs b/src/Polyfill/WritableMemoryStream.cs
new file mode 100644
index 00000000..5189f658
--- /dev/null
+++ b/src/Polyfill/WritableMemoryStream.cs
@@ -0,0 +1,75 @@
+#nullable enable
+
+// === Polyfill target window =====================================================================
+// System.IO.WritableMemoryStream was approved and merged into dotnet/runtime for net11
+// (https://github.com/dotnet/runtime/pull/126669) but is NOT in the current net11 preview/RC SDK,
+// so this polyfill is intentionally ACTIVE on net11 as well.
+// When you upgrade to a net11 SDK that actually ships this type, the build will collide (CS0436)
+// and the ApiBuilderTests "StreamWrapperBclDetectionTests" test FAILS with these exact steps.
+// To retire this polyfill for net11:
+//   1. change `#if FeatureMemory` below to `#if FeatureMemory && !NET11_0_OR_GREATER`
+//   2. add at the bottom of this file (after the final #endif):
+//        #if NET11_0_OR_GREATER
+//        [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.IO.WritableMemoryStream))]
+//        #endif
+//   3. re-run ApiBuilderTests in Debug to regenerate Split + api_list.
+// ================================================================================================
+#if FeatureMemory
+
+#pragma warning disable
+
+namespace System.IO;
+
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+//Link: https://learn.microsoft.com/en-us/dotnet/api/system.io.writablememorystream?view=net-11.0
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+    MemoryStream
+{
+    /// <summary>
+    /// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+    /// </summary>
+    //Link: https://learn.microsoft.com/en-us/dotnet/api/system.io.writablememorystream.-ctor?view=net-11.0
+    public WritableMemoryStream(Memory<byte> buffer)
+        : base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+        // The base constructor reports the whole region as content; reset to an empty, ready-to-write stream.
+        base.SetLength(0);
+
+    /// <inheritdoc/>
+    public override void SetLength(long value) =>
+        throw new NotSupportedException("Memory stream is not expandable.");
+
+    static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+    {
+        if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+            segment.Array != null)
+        {
+            offset = segment.Offset;
+            count = segment.Count;
+            return segment.Array;
+        }
+
+        throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+    }
+}
+
+#endif
diff --git a/src/Split/net10.0/ReadOnlyMemoryStream.cs b/src/Split/net10.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net10.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net10.0/ReadOnlySequenceStream.cs b/src/Split/net10.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net10.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net10.0/StringStream.cs b/src/Split/net10.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net10.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net10.0/WritableMemoryStream.cs b/src/Split/net10.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net10.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net11.0/ReadOnlyMemoryStream.cs b/src/Split/net11.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net11.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net11.0/ReadOnlySequenceStream.cs b/src/Split/net11.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net11.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net11.0/StringStream.cs b/src/Split/net11.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net11.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net11.0/WritableMemoryStream.cs b/src/Split/net11.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net11.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net461/ReadOnlyMemoryStream.cs b/src/Split/net461/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net461/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net461/ReadOnlySequenceStream.cs b/src/Split/net461/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net461/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net461/StringStream.cs b/src/Split/net461/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net461/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net461/WritableMemoryStream.cs b/src/Split/net461/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net461/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net462/ReadOnlyMemoryStream.cs b/src/Split/net462/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net462/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net462/ReadOnlySequenceStream.cs b/src/Split/net462/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net462/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net462/StringStream.cs b/src/Split/net462/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net462/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net462/WritableMemoryStream.cs b/src/Split/net462/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net462/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net47/ReadOnlyMemoryStream.cs b/src/Split/net47/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net47/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net47/ReadOnlySequenceStream.cs b/src/Split/net47/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net47/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net47/StringStream.cs b/src/Split/net47/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net47/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net47/WritableMemoryStream.cs b/src/Split/net47/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net47/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net471/ReadOnlyMemoryStream.cs b/src/Split/net471/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net471/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net471/ReadOnlySequenceStream.cs b/src/Split/net471/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net471/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net471/StringStream.cs b/src/Split/net471/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net471/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net471/WritableMemoryStream.cs b/src/Split/net471/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net471/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net472/ReadOnlyMemoryStream.cs b/src/Split/net472/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net472/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net472/ReadOnlySequenceStream.cs b/src/Split/net472/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net472/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net472/StringStream.cs b/src/Split/net472/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net472/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net472/WritableMemoryStream.cs b/src/Split/net472/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net472/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net48/ReadOnlyMemoryStream.cs b/src/Split/net48/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net48/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net48/ReadOnlySequenceStream.cs b/src/Split/net48/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net48/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net48/StringStream.cs b/src/Split/net48/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net48/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net48/WritableMemoryStream.cs b/src/Split/net48/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net48/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net481/ReadOnlyMemoryStream.cs b/src/Split/net481/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net481/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net481/ReadOnlySequenceStream.cs b/src/Split/net481/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net481/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net481/StringStream.cs b/src/Split/net481/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net481/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net481/WritableMemoryStream.cs b/src/Split/net481/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net481/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net5.0/ReadOnlyMemoryStream.cs b/src/Split/net5.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net5.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net5.0/ReadOnlySequenceStream.cs b/src/Split/net5.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net5.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net5.0/StringStream.cs b/src/Split/net5.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net5.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net5.0/WritableMemoryStream.cs b/src/Split/net5.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net5.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net6.0/ReadOnlyMemoryStream.cs b/src/Split/net6.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net6.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net6.0/ReadOnlySequenceStream.cs b/src/Split/net6.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net6.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net6.0/StringStream.cs b/src/Split/net6.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net6.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net6.0/WritableMemoryStream.cs b/src/Split/net6.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net6.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net7.0/ReadOnlyMemoryStream.cs b/src/Split/net7.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net7.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net7.0/ReadOnlySequenceStream.cs b/src/Split/net7.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net7.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net7.0/StringStream.cs b/src/Split/net7.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net7.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net7.0/WritableMemoryStream.cs b/src/Split/net7.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net7.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net8.0/ReadOnlyMemoryStream.cs b/src/Split/net8.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net8.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net8.0/ReadOnlySequenceStream.cs b/src/Split/net8.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net8.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net8.0/StringStream.cs b/src/Split/net8.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net8.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net8.0/WritableMemoryStream.cs b/src/Split/net8.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net8.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/net9.0/ReadOnlyMemoryStream.cs b/src/Split/net9.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/net9.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/net9.0/ReadOnlySequenceStream.cs b/src/Split/net9.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/net9.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net9.0/StringStream.cs b/src/Split/net9.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/net9.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/net9.0/WritableMemoryStream.cs b/src/Split/net9.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/net9.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.0/ReadOnlyMemoryStream.cs b/src/Split/netcoreapp2.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/netcoreapp2.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.0/ReadOnlySequenceStream.cs b/src/Split/netcoreapp2.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/netcoreapp2.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.0/StringStream.cs b/src/Split/netcoreapp2.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/netcoreapp2.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.0/WritableMemoryStream.cs b/src/Split/netcoreapp2.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/netcoreapp2.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.1/ReadOnlyMemoryStream.cs b/src/Split/netcoreapp2.1/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/netcoreapp2.1/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.1/ReadOnlySequenceStream.cs b/src/Split/netcoreapp2.1/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/netcoreapp2.1/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.1/StringStream.cs b/src/Split/netcoreapp2.1/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/netcoreapp2.1/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.1/WritableMemoryStream.cs b/src/Split/netcoreapp2.1/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/netcoreapp2.1/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.2/ReadOnlyMemoryStream.cs b/src/Split/netcoreapp2.2/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/netcoreapp2.2/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.2/ReadOnlySequenceStream.cs b/src/Split/netcoreapp2.2/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/netcoreapp2.2/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.2/StringStream.cs b/src/Split/netcoreapp2.2/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/netcoreapp2.2/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp2.2/WritableMemoryStream.cs b/src/Split/netcoreapp2.2/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/netcoreapp2.2/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp3.0/ReadOnlyMemoryStream.cs b/src/Split/netcoreapp3.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/netcoreapp3.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp3.0/ReadOnlySequenceStream.cs b/src/Split/netcoreapp3.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/netcoreapp3.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp3.0/StringStream.cs b/src/Split/netcoreapp3.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/netcoreapp3.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp3.0/WritableMemoryStream.cs b/src/Split/netcoreapp3.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/netcoreapp3.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp3.1/ReadOnlyMemoryStream.cs b/src/Split/netcoreapp3.1/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/netcoreapp3.1/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp3.1/ReadOnlySequenceStream.cs b/src/Split/netcoreapp3.1/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/netcoreapp3.1/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp3.1/StringStream.cs b/src/Split/netcoreapp3.1/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/netcoreapp3.1/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netcoreapp3.1/WritableMemoryStream.cs b/src/Split/netcoreapp3.1/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/netcoreapp3.1/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/netstandard2.0/ReadOnlyMemoryStream.cs b/src/Split/netstandard2.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/netstandard2.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/netstandard2.0/ReadOnlySequenceStream.cs b/src/Split/netstandard2.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/netstandard2.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netstandard2.0/StringStream.cs b/src/Split/netstandard2.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/netstandard2.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netstandard2.0/WritableMemoryStream.cs b/src/Split/netstandard2.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/netstandard2.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/netstandard2.1/ReadOnlyMemoryStream.cs b/src/Split/netstandard2.1/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/netstandard2.1/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/netstandard2.1/ReadOnlySequenceStream.cs b/src/Split/netstandard2.1/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/netstandard2.1/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netstandard2.1/StringStream.cs b/src/Split/netstandard2.1/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/netstandard2.1/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/netstandard2.1/WritableMemoryStream.cs b/src/Split/netstandard2.1/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/netstandard2.1/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Split/uap10.0/ReadOnlyMemoryStream.cs b/src/Split/uap10.0/ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..7a03bfdb
--- /dev/null
+++ b/src/Split/uap10.0/ReadOnlyMemoryStream.cs
@@ -0,0 +1,52 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-only <see cref="MemoryStream"/> over a <see cref="ReadOnlyMemory{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The stream cannot be written to. <see cref="MemoryStream.CanWrite"/> always returns <see langword="false"/>.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// When the supplied memory is not backed by an array (for example native memory) the polyfill copies it;
+/// the BCL always wraps the memory without copying.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlyMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlyMemoryStream"/> class over the specified <see cref="ReadOnlyMemory{Byte}"/>.
+	/// </summary>
+	public ReadOnlyMemoryStream(ReadOnlyMemory<byte> source)
+		: base(GetArray(source, out var offset, out var count), offset, count, writable: false, publiclyVisible: false)
+	{
+	}
+	static byte[] GetArray(ReadOnlyMemory<byte> source, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray(source, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		var array = source.ToArray();
+		offset = 0;
+		count = array.Length;
+		return array;
+	}
+}
+#endif
diff --git a/src/Split/uap10.0/ReadOnlySequenceStream.cs b/src/Split/uap10.0/ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..1b9bd979
--- /dev/null
+++ b/src/Split/uap10.0/ReadOnlySequenceStream.cs
@@ -0,0 +1,185 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.Buffers;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a seekable, read-only <see cref="Stream"/> over a <see cref="ReadOnlySequence{Byte}"/>.
+/// </summary>
+/// <remarks>
+/// The underlying sequence is not copied; reads are served directly from its segments.
+/// The stream cannot be written to. <see cref="CanWrite"/> always returns <see langword="false"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class ReadOnlySequenceStream :
+	Stream
+{
+	ReadOnlySequence<byte> sequence;
+	long position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="ReadOnlySequenceStream"/> class over the specified <see cref="ReadOnlySequence{Byte}"/>.
+	/// </summary>
+	public ReadOnlySequenceStream(ReadOnlySequence<byte> source) =>
+		sequence = source;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => !disposed;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return sequence.Length;
+		}
+	}
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get
+		{
+			ThrowIfDisposed();
+			return position;
+		}
+		set
+		{
+			ThrowIfDisposed();
+			if (value < 0)
+			{
+				throw new ArgumentOutOfRangeException(nameof(value));
+			}
+			position = value;
+		}
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return 0;
+		}
+		var remaining = sequence.Slice(position);
+		var toRead = (int)Math.Min(remaining.Length, count);
+		if (toRead <= 0)
+		{
+			return 0;
+		}
+		remaining.Slice(0, toRead).CopyTo(buffer.AsSpan(offset, toRead));
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		if (position >= sequence.Length)
+		{
+			return -1;
+		}
+		var result = sequence.Slice(position, 1).First.Span[0];
+		position++;
+		return result;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin)
+	{
+		ThrowIfDisposed();
+		var basePosition = origin switch
+		{
+			SeekOrigin.Begin => 0L,
+			SeekOrigin.Current => position,
+			SeekOrigin.End => sequence.Length,
+			_ => throw new ArgumentException("Invalid seek origin.", nameof(origin))
+		};
+		var newPosition = basePosition + offset;
+		if (newPosition < 0)
+		{
+			throw new IOException("An attempt was made to move the position before the beginning of the stream.");
+		}
+		position = newPosition;
+		return position;
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		sequence = default;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/uap10.0/StringStream.cs b/src/Split/uap10.0/StringStream.cs
new file mode 100644
index 00000000..b4cd3943
--- /dev/null
+++ b/src/Split/uap10.0/StringStream.cs
@@ -0,0 +1,186 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Text;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+/// <summary>
+/// Provides a read-only, non-seekable <see cref="Stream"/> that encodes a <see cref="string"/> or
+/// <see cref="ReadOnlyMemory{Char}"/> into bytes using a specified <see cref="System.Text.Encoding"/>.
+/// </summary>
+/// <remarks>
+/// This stream never emits a byte order mark (BOM). Callers who need a BOM can prepend it themselves.
+/// The polyfill encodes the whole text into a single buffer on first read rather than encoding
+/// on-the-fly; this is a non-observable performance difference from the BCL implementation.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class StringStream :
+	Stream
+{
+	ReadOnlyMemory<char> text;
+	Encoding encoding;
+	byte[]? encoded;
+	int position;
+	bool disposed;
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified string and encoding.
+	/// </summary>
+	public StringStream(string text, Encoding encoding)
+	{
+		if (text == null)
+		{
+			throw new ArgumentNullException(nameof(text));
+		}
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text.AsMemory();
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Initializes a new instance of the <see cref="StringStream"/> class with the specified character memory and encoding.
+	/// </summary>
+	public StringStream(ReadOnlyMemory<char> text, Encoding encoding)
+	{
+		if (encoding == null)
+		{
+			throw new ArgumentNullException(nameof(encoding));
+		}
+		this.text = text;
+		this.encoding = encoding;
+	}
+	/// <summary>
+	/// Gets the encoding used by this stream.
+	/// </summary>
+	public Encoding Encoding => encoding;
+	/// <inheritdoc/>
+	public override bool CanRead => !disposed;
+	/// <inheritdoc/>
+	public override bool CanSeek => false;
+	/// <inheritdoc/>
+	public override bool CanWrite => false;
+	/// <inheritdoc/>
+	public override long Length => throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override long Position
+	{
+		get => throw new NotSupportedException("Stream does not support seeking.");
+		set => throw new NotSupportedException("Stream does not support seeking.");
+	}
+	byte[] GetEncoded()
+	{
+		if (encoded == null)
+		{
+			var chars = text.ToArray();
+			encoded = encoding.GetBytes(chars, 0, chars.Length);
+		}
+		return encoded;
+	}
+	/// <inheritdoc/>
+	public override int Read(byte[] buffer, int offset, int count)
+	{
+		GuardRange(buffer, offset, count);
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		var remaining = all.Length - position;
+		if (remaining <= 0 ||
+			count == 0)
+		{
+			return 0;
+		}
+		var toRead = Math.Min(remaining, count);
+		Array.Copy(all, position, buffer, offset, toRead);
+		position += toRead;
+		return toRead;
+	}
+	/// <inheritdoc/>
+	public override int ReadByte()
+	{
+		ThrowIfDisposed();
+		var all = GetEncoded();
+		if (position < all.Length)
+		{
+			return all[position++];
+		}
+		return -1;
+	}
+	/// <inheritdoc/>
+	public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+	{
+		GuardRange(buffer, offset, count);
+		if (cancellationToken.IsCancellationRequested)
+		{
+			return Task.FromCanceled<int>(cancellationToken);
+		}
+		try
+		{
+			return Task.FromResult(Read(buffer, offset, count));
+		}
+		catch (Exception exception)
+		{
+			return Task.FromException<int>(exception);
+		}
+	}
+	/// <inheritdoc/>
+	public override void Flush()
+	{
+	}
+	/// <inheritdoc/>
+	public override Task FlushAsync(CancellationToken cancellationToken) =>
+		cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : Task.CompletedTask;
+	/// <inheritdoc/>
+	public override long Seek(long offset, SeekOrigin origin) =>
+		throw new NotSupportedException("Stream does not support seeking.");
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	public override void Write(byte[] buffer, int offset, int count) =>
+		throw new NotSupportedException("Stream does not support writing.");
+	/// <inheritdoc/>
+	protected override void Dispose(bool disposing)
+	{
+		disposed = true;
+		base.Dispose(disposing);
+	}
+	void ThrowIfDisposed()
+	{
+		if (disposed)
+		{
+			throw new ObjectDisposedException(GetType().FullName);
+		}
+	}
+	static void GuardRange(byte[] buffer, int offset, int count)
+	{
+		if (buffer == null)
+		{
+			throw new ArgumentNullException(nameof(buffer));
+		}
+		if (offset < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(offset));
+		}
+		if (count < 0)
+		{
+			throw new ArgumentOutOfRangeException(nameof(count));
+		}
+		if (buffer.Length - offset < count)
+		{
+			throw new ArgumentException("The sum of offset and count is larger than the buffer length.");
+		}
+	}
+}
+#endif
diff --git a/src/Split/uap10.0/WritableMemoryStream.cs b/src/Split/uap10.0/WritableMemoryStream.cs
new file mode 100644
index 00000000..f8e0ecb6
--- /dev/null
+++ b/src/Split/uap10.0/WritableMemoryStream.cs
@@ -0,0 +1,51 @@
+// <auto-generated />
+#pragma warning disable
+#nullable enable
+#if FeatureMemory
+#pragma warning disable
+namespace System.IO;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+/// <summary>
+/// Provides a seekable, read-write <see cref="MemoryStream"/> over a <see cref="Memory{Byte}"/> with fixed capacity.
+/// </summary>
+/// <remarks>
+/// The stream cannot expand beyond the initial memory capacity.
+/// <see cref="MemoryStream.GetBuffer"/> throws and <see cref="MemoryStream.TryGetBuffer"/> returns <see langword="false"/>.
+/// The polyfill requires an array-backed <see cref="Memory{Byte}"/>; memory backed by native (or other non-array)
+/// buffers is not supported and the constructor throws <see cref="NotSupportedException"/>.
+/// </remarks>
+[ExcludeFromCodeCoverage]
+[DebuggerNonUserCode]
+#if PolyUseEmbeddedAttribute
+[global::Microsoft.CodeAnalysis.EmbeddedAttribute]
+#endif
+#if PolyPublic
+public
+#endif
+sealed class WritableMemoryStream :
+	MemoryStream
+{
+	/// <summary>
+	/// Initializes a new instance of the <see cref="WritableMemoryStream"/> class over the specified <see cref="Memory{Byte}"/>.
+	/// </summary>
+	public WritableMemoryStream(Memory<byte> buffer)
+		: base(GetArray(buffer, out var offset, out var count), offset, count, writable: true, publiclyVisible: false) =>
+		base.SetLength(0);
+	/// <inheritdoc/>
+	public override void SetLength(long value) =>
+		throw new NotSupportedException("Memory stream is not expandable.");
+	static byte[] GetArray(Memory<byte> buffer, out int offset, out int count)
+	{
+		if (MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)buffer, out var segment) &&
+			segment.Array != null)
+		{
+			offset = segment.Offset;
+			count = segment.Count;
+			return segment.Array;
+		}
+		throw new NotSupportedException("WritableMemoryStream polyfill requires an array-backed Memory<byte>.");
+	}
+}
+#endif
diff --git a/src/Tests/PolyfillTests_ReadOnlyMemoryStream.cs b/src/Tests/PolyfillTests_ReadOnlyMemoryStream.cs
new file mode 100644
index 00000000..6f6a2035
--- /dev/null
+++ b/src/Tests/PolyfillTests_ReadOnlyMemoryStream.cs
@@ -0,0 +1,113 @@
+#if FeatureMemory
+using System.IO;
+
+partial class PolyfillTests
+{
+    [Test]
+    public async Task ReadOnlyMemoryStream_IsAMemoryStream()
+    {
+        using var stream = new ReadOnlyMemoryStream(new byte[] { 1, 2, 3 });
+
+        await Assert.That(stream).IsAssignableTo<MemoryStream>();
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_Capabilities()
+    {
+        using var stream = new ReadOnlyMemoryStream(new byte[] { 1, 2, 3 });
+
+        await Assert.That(stream.CanRead).IsTrue();
+        await Assert.That(stream.CanSeek).IsTrue();
+        await Assert.That(stream.CanWrite).IsFalse();
+        await Assert.That(stream.Length).IsEqualTo(3L);
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_ReadsAllBytes()
+    {
+        using var stream = new ReadOnlyMemoryStream(new byte[] { 10, 20, 30, 40, 50 });
+
+        var buffer = new byte[5];
+        var read = stream.Read(buffer, 0, 5);
+
+        await Assert.That(read).IsEqualTo(5);
+        await Assert.That(buffer).IsEquivalentTo(new byte[] { 10, 20, 30, 40, 50 });
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_WorksWithSlicedMemory()
+    {
+        var largeBuffer = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+        var slice = largeBuffer.AsMemory(3, 4);
+        using var stream = new ReadOnlyMemoryStream(slice);
+
+        await Assert.That(stream.Length).IsEqualTo(4L);
+
+        var result = new byte[4];
+        var read = stream.Read(result, 0, 4);
+
+        await Assert.That(read).IsEqualTo(4);
+        await Assert.That(result).IsEquivalentTo(new byte[] { 3, 4, 5, 6 });
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_SeekAndPosition()
+    {
+        using var stream = new ReadOnlyMemoryStream(new byte[] { 1, 2, 3, 4, 5 });
+
+        stream.Seek(2, SeekOrigin.Begin);
+        await Assert.That(stream.Position).IsEqualTo(2L);
+        await Assert.That(stream.ReadByte()).IsEqualTo(3);
+
+        stream.Position = 0;
+        await Assert.That(stream.ReadByte()).IsEqualTo(1);
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_GetBufferThrows_TryGetBufferFalse()
+    {
+        using var stream = new ReadOnlyMemoryStream(new byte[] { 1, 2, 3 });
+
+        await Assert.That(() => stream.GetBuffer()).Throws<UnauthorizedAccessException>();
+        await Assert.That(stream.TryGetBuffer(out var segment)).IsFalse();
+        await Assert.That(segment.Array).IsNull();
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_WritingThrows()
+    {
+        using var stream = new ReadOnlyMemoryStream(new byte[] { 1, 2, 3 });
+
+        await Assert.That(() => stream.Write(new byte[1], 0, 1)).Throws<NotSupportedException>();
+        await Assert.That(() => stream.WriteByte(1)).Throws<NotSupportedException>();
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_ToArrayReturnsContent()
+    {
+        using var stream = new ReadOnlyMemoryStream(new byte[] { 9, 8, 7 });
+
+        await Assert.That(stream.ToArray()).IsEquivalentTo(new byte[] { 9, 8, 7 });
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_CopyTo()
+    {
+        using var stream = new ReadOnlyMemoryStream(new byte[] { 1, 2, 3, 4 });
+        using var target = new MemoryStream();
+
+        stream.CopyTo(target);
+
+        await Assert.That(target.ToArray()).IsEquivalentTo(new byte[] { 1, 2, 3, 4 });
+    }
+
+    [Test]
+    public async Task ReadOnlyMemoryStream_Empty()
+    {
+        using var stream = new ReadOnlyMemoryStream(ReadOnlyMemory<byte>.Empty);
+
+        await Assert.That(stream.Length).IsEqualTo(0L);
+        await Assert.That(stream.Read(new byte[4], 0, 4)).IsEqualTo(0);
+    }
+}
+#endif
diff --git a/src/Tests/PolyfillTests_ReadOnlySequenceStream.cs b/src/Tests/PolyfillTests_ReadOnlySequenceStream.cs
new file mode 100644
index 00000000..66cc44d8
--- /dev/null
+++ b/src/Tests/PolyfillTests_ReadOnlySequenceStream.cs
@@ -0,0 +1,143 @@
+#if FeatureMemory
+using System.Buffers;
+using System.IO;
+
+partial class PolyfillTests
+{
+    [Test]
+    public async Task ReadOnlySequenceStream_Capabilities()
+    {
+        using var stream = new ReadOnlySequenceStream(new ReadOnlySequence<byte>(new byte[] { 1, 2, 3 }));
+
+        await Assert.That(stream.CanRead).IsTrue();
+        await Assert.That(stream.CanSeek).IsTrue();
+        await Assert.That(stream.CanWrite).IsFalse();
+        await Assert.That(stream.Length).IsEqualTo(3L);
+    }
+
+    [Test]
+    public async Task ReadOnlySequenceStream_SingleSegment_ReadsAll()
+    {
+        using var stream = new ReadOnlySequenceStream(new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }));
+
+        var result = ReadToEnd(stream);
+
+        await Assert.That(result).IsEquivalentTo(new byte[] { 1, 2, 3, 4, 5 });
+    }
+
+    [Test]
+    public async Task ReadOnlySequenceStream_MultiSegment_ReadsAcrossSegments()
+    {
+        var sequence = CreateMultiSegment(new byte[] { 1, 2, 3 }, new byte[] { 4, 5 }, new byte[] { 6, 7, 8, 9 });
+        using var stream = new ReadOnlySequenceStream(sequence);
+
+        await Assert.That(stream.Length).IsEqualTo(9L);
+
+        // Read in small chunks so reads straddle segment boundaries.
+        using var accumulator = new MemoryStream();
+        var buffer = new byte[2];
+        int read;
+        while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
+        {
+            accumulator.Write(buffer, 0, read);
+        }
+
+        await Assert.That(accumulator.ToArray()).IsEquivalentTo(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
+    }
+
+    [Test]
+    public async Task ReadOnlySequenceStream_ReadByte_AcrossSegments()
+    {
+        var sequence = CreateMultiSegment(new byte[] { 1 }, new byte[] { 2, 3 });
+        using var stream = new ReadOnlySequenceStream(sequence);
+
+        await Assert.That(stream.ReadByte()).IsEqualTo(1);
+        await Assert.That(stream.ReadByte()).IsEqualTo(2);
+        await Assert.That(stream.ReadByte()).IsEqualTo(3);
+        await Assert.That(stream.ReadByte()).IsEqualTo(-1);
+    }
+
+    [Test]
+    public async Task ReadOnlySequenceStream_Seek()
+    {
+        using var stream = new ReadOnlySequenceStream(new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }));
+
+        stream.Seek(3, SeekOrigin.Begin);
+        await Assert.That(stream.Position).IsEqualTo(3L);
+        await Assert.That(stream.ReadByte()).IsEqualTo(4);
+
+        stream.Seek(-2, SeekOrigin.Current);
+        await Assert.That(stream.ReadByte()).IsEqualTo(3);
+
+        stream.Seek(-1, SeekOrigin.End);
+        await Assert.That(stream.ReadByte()).IsEqualTo(5);
+    }
+
+    [Test]
+    public async Task ReadOnlySequenceStream_SeekBeforeBeginThrows()
+    {
+        using var stream = new ReadOnlySequenceStream(new ReadOnlySequence<byte>(new byte[] { 1, 2, 3 }));
+
+        await Assert.That(() => stream.Seek(-1, SeekOrigin.Begin)).Throws<IOException>();
+    }
+
+    [Test]
+    public async Task ReadOnlySequenceStream_WritingThrows()
+    {
+        using var stream = new ReadOnlySequenceStream(new ReadOnlySequence<byte>(new byte[] { 1, 2, 3 }));
+
+        await Assert.That(() => stream.Write(new byte[1], 0, 1)).Throws<NotSupportedException>();
+        await Assert.That(() => stream.SetLength(1)).Throws<NotSupportedException>();
+    }
+
+    [Test]
+    public async Task ReadOnlySequenceStream_ReadAsync()
+    {
+        using var stream = new ReadOnlySequenceStream(new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4 }));
+
+        var buffer = new byte[4];
+        var read = await stream.ReadAsync(buffer, 0, 4);
+
+        await Assert.That(read).IsEqualTo(4);
+        await Assert.That(buffer).IsEquivalentTo(new byte[] { 1, 2, 3, 4 });
+    }
+
+    [Test]
+    public async Task ReadOnlySequenceStream_Empty()
+    {
+        using var stream = new ReadOnlySequenceStream(ReadOnlySequence<byte>.Empty);
+
+        await Assert.That(stream.Length).IsEqualTo(0L);
+        await Assert.That(stream.Read(new byte[4], 0, 4)).IsEqualTo(0);
+    }
+
+    static ReadOnlySequence<byte> CreateMultiSegment(params byte[][] parts)
+    {
+        var first = new ReadOnlySequenceStreamSegment(parts[0]);
+        var last = first;
+        for (var index = 1; index < parts.Length; index++)
+        {
+            last = last.Append(parts[index]);
+        }
+
+        return new(first, 0, last, last.Memory.Length);
+    }
+
+    class ReadOnlySequenceStreamSegment :
+        ReadOnlySequenceSegment<byte>
+    {
+        public ReadOnlySequenceStreamSegment(ReadOnlyMemory<byte> memory) =>
+            Memory = memory;
+
+        public ReadOnlySequenceStreamSegment Append(ReadOnlyMemory<byte> memory)
+        {
+            var segment = new ReadOnlySequenceStreamSegment(memory)
+            {
+                RunningIndex = RunningIndex + Memory.Length
+            };
+            Next = segment;
+            return segment;
+        }
+    }
+}
+#endif
diff --git a/src/Tests/PolyfillTests_StringStream.cs b/src/Tests/PolyfillTests_StringStream.cs
new file mode 100644
index 00000000..c75e79b7
--- /dev/null
+++ b/src/Tests/PolyfillTests_StringStream.cs
@@ -0,0 +1,173 @@
+#if FeatureMemory
+using System.IO;
+using System.Text;
+
+partial class PolyfillTests
+{
+    [Test]
+    public async Task StringStream_ReadsExpectedUtf8Bytes()
+    {
+        var expected = Encoding.UTF8.GetBytes("Hello, World!");
+        using var stream = new StringStream("Hello, World!", Encoding.UTF8);
+
+        var actual = ReadToEnd(stream);
+
+        await Assert.That(actual).IsEquivalentTo(expected);
+    }
+
+    [Test]
+    public async Task StringStream_FromReadOnlyMemory_ReadsExpectedBytes()
+    {
+        var expected = Encoding.UTF8.GetBytes("chars");
+        using var stream = new StringStream("chars".AsMemory(), Encoding.UTF8);
+
+        var actual = ReadToEnd(stream);
+
+        await Assert.That(actual).IsEquivalentTo(expected);
+    }
+
+    [Test]
+    public async Task StringStream_Unicode_RoundTripsThroughEncoding()
+    {
+        const string input = "Unicode: 你好世界 🌍";
+        var expected = Encoding.UTF8.GetBytes(input);
+        using var stream = new StringStream(input, Encoding.UTF8);
+
+        var actual = ReadToEnd(stream);
+
+        await Assert.That(actual).IsEquivalentTo(expected);
+    }
+
+    [Test]
+    public async Task StringStream_ReadInSmallChunks_ReconstructsOutput()
+    {
+        var expected = Encoding.UTF8.GetBytes("The quick brown fox");
+        using var stream = new StringStream("The quick brown fox", Encoding.UTF8);
+
+        using var accumulator = new MemoryStream();
+        var buffer = new byte[3];
+        int read;
+        while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
+        {
+            accumulator.Write(buffer, 0, read);
+        }
+
+        await Assert.That(accumulator.ToArray()).IsEquivalentTo(expected);
+    }
+
+    [Test]
+    public async Task StringStream_ReadByte_ReturnsBytesThenMinusOne()
+    {
+        using var stream = new StringStream("AB", Encoding.ASCII);
+
+        var first = stream.ReadByte();
+        var second = stream.ReadByte();
+        var third = stream.ReadByte();
+
+        await Assert.That(first).IsEqualTo((int)'A');
+        await Assert.That(second).IsEqualTo((int)'B');
+        await Assert.That(third).IsEqualTo(-1);
+    }
+
+    [Test]
+    public async Task StringStream_Empty_ReadsZero()
+    {
+        using var stream = new StringStream("", Encoding.UTF8);
+
+        var buffer = new byte[8];
+        var read = stream.Read(buffer, 0, buffer.Length);
+
+        await Assert.That(read).IsEqualTo(0);
+    }
+
+    [Test]
+    public async Task StringStream_NeverEmitsBom()
+    {
+        // UTF8 with BOM preamble: StringStream must not write the preamble.
+        var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true);
+        using var stream = new StringStream("x", encoding);
+
+        var actual = ReadToEnd(stream);
+
+        await Assert.That(actual).IsEquivalentTo(new byte[] { (byte)'x' });
+    }
+
+    [Test]
+    public async Task StringStream_ReadAsync_ReadsExpectedBytes()
+    {
+        var expected = Encoding.UTF8.GetBytes("async");
+        using var stream = new StringStream("async", Encoding.UTF8);
+
+        var buffer = new byte[expected.Length];
+        var total = 0;
+        int read;
+        while (total < buffer.Length &&
+               (read = await stream.ReadAsync(buffer, total, buffer.Length - total)) > 0)
+        {
+            total += read;
+        }
+
+        await Assert.That(total).IsEqualTo(expected.Length);
+        await Assert.That(buffer).IsEquivalentTo(expected);
+    }
+
+    [Test]
+    public async Task StringStream_Capabilities()
+    {
+        using var stream = new StringStream("data", Encoding.UTF8);
+
+        await Assert.That(stream.CanRead).IsTrue();
+        await Assert.That(stream.CanSeek).IsFalse();
+        await Assert.That(stream.CanWrite).IsFalse();
+        await Assert.That(stream.Encoding).IsEqualTo((Encoding)Encoding.UTF8);
+    }
+
+    [Test]
+    public async Task StringStream_SeekingMembersThrow()
+    {
+        using var stream = new StringStream("data", Encoding.UTF8);
+
+        await Assert.That(() => stream.Length).Throws<NotSupportedException>();
+        await Assert.That(() => stream.Position).Throws<NotSupportedException>();
+        await Assert.That(() => stream.Seek(0, SeekOrigin.Begin)).Throws<NotSupportedException>();
+    }
+
+    [Test]
+    public async Task StringStream_WritingMembersThrow()
+    {
+        using var stream = new StringStream("data", Encoding.UTF8);
+
+        await Assert.That(() => stream.Write(new byte[1], 0, 1)).Throws<NotSupportedException>();
+        await Assert.That(() => stream.SetLength(1)).Throws<NotSupportedException>();
+    }
+
+    [Test]
+    public async Task StringStream_NullArgumentsThrow()
+    {
+        await Assert.That(() => new StringStream((string)null!, Encoding.UTF8)).Throws<ArgumentNullException>();
+        await Assert.That(() => new StringStream("x", null!)).Throws<ArgumentNullException>();
+    }
+
+    [Test]
+    public async Task StringStream_AfterDispose_CanReadIsFalse()
+    {
+        var stream = new StringStream("data", Encoding.UTF8);
+        stream.Dispose();
+
+        await Assert.That(stream.CanRead).IsFalse();
+    }
+
+    static byte[] ReadToEnd(Stream stream)
+    {
+        using var memory = new MemoryStream();
+        var buffer = new byte[16];
+        int read;
+        while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
+        {
+            memory.Write(buffer, 0, read);
+        }
+
+        return memory.ToArray();
+    }
+}
+#endif
diff --git a/src/Tests/PolyfillTests_WritableMemoryStream.cs b/src/Tests/PolyfillTests_WritableMemoryStream.cs
new file mode 100644
index 00000000..c0f14262
--- /dev/null
+++ b/src/Tests/PolyfillTests_WritableMemoryStream.cs
@@ -0,0 +1,100 @@
+#if FeatureMemory
+using System.IO;
+
+partial class PolyfillTests
+{
+    [Test]
+    public async Task WritableMemoryStream_IsAMemoryStream()
+    {
+        using var stream = new WritableMemoryStream(new byte[4]);
+
+        await Assert.That(stream).IsAssignableTo<MemoryStream>();
+    }
+
+    [Test]
+    public async Task WritableMemoryStream_StartsEmptyWithFixedCapacity()
+    {
+        using var stream = new WritableMemoryStream(new byte[8]);
+
+        await Assert.That(stream.Length).IsEqualTo(0L);
+        await Assert.That(stream.Position).IsEqualTo(0L);
+        await Assert.That(stream.CanWrite).IsTrue();
+        await Assert.That(stream.CanRead).IsTrue();
+        await Assert.That(stream.CanSeek).IsTrue();
+        await Assert.That(stream.Capacity).IsEqualTo(8);
+    }
+
+    [Test]
+    public async Task WritableMemoryStream_WritesIntoBackingArray()
+    {
+        var backing = new byte[5];
+        using var stream = new WritableMemoryStream(backing);
+
+        stream.Write(new byte[] { 1, 2, 3 }, 0, 3);
+
+        await Assert.That(stream.Length).IsEqualTo(3L);
+        await Assert.That(backing).IsEquivalentTo(new byte[] { 1, 2, 3, 0, 0 });
+    }
+
+    [Test]
+    public async Task WritableMemoryStream_WritesIntoSlicedBackingMemory()
+    {
+        var backing = new byte[8];
+        using var stream = new WritableMemoryStream(backing.AsMemory(2, 3));
+
+        stream.WriteByte(7);
+        stream.WriteByte(8);
+
+        await Assert.That(backing).IsEquivalentTo(new byte[] { 0, 0, 7, 8, 0, 0, 0, 0 });
+    }
+
+    [Test]
+    public async Task WritableMemoryStream_ReadBackWhatWasWritten()
+    {
+        using var stream = new WritableMemoryStream(new byte[16]);
+        stream.Write(new byte[] { 4, 5, 6 }, 0, 3);
+
+        stream.Position = 0;
+        var buffer = new byte[3];
+        var read = stream.Read(buffer, 0, 3);
+
+        await Assert.That(read).IsEqualTo(3);
+        await Assert.That(buffer).IsEquivalentTo(new byte[] { 4, 5, 6 });
+    }
+
+    [Test]
+    public async Task WritableMemoryStream_WritingBeyondCapacityThrows()
+    {
+        using var stream = new WritableMemoryStream(new byte[3]);
+
+        await Assert.That(() => stream.Write(new byte[] { 1, 2, 3, 4 }, 0, 4)).Throws<NotSupportedException>();
+    }
+
+    [Test]
+    public async Task WritableMemoryStream_SetLengthThrows()
+    {
+        using var stream = new WritableMemoryStream(new byte[4]);
+
+        await Assert.That(() => stream.SetLength(2)).Throws<NotSupportedException>();
+    }
+
+    [Test]
+    public async Task WritableMemoryStream_GetBufferThrows_TryGetBufferFalse()
+    {
+        using var stream = new WritableMemoryStream(new byte[4]);
+
+        await Assert.That(() => stream.GetBuffer()).Throws<UnauthorizedAccessException>();
+        await Assert.That(stream.TryGetBuffer(out var segment)).IsFalse();
+        await Assert.That(segment.Array).IsNull();
+    }
+
+    [Test]
+    public async Task WritableMemoryStream_ToArrayReturnsWrittenContent()
+    {
+        using var stream = new WritableMemoryStream(new byte[16]);
+        stream.Write(new byte[] { 1, 2, 3 }, 0, 3);
+
+        await Assert.That(stream.ToArray()).IsEquivalentTo(new byte[] { 1, 2, 3 });
+    }
+}
+#endif
