save development progress
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
using ZstdSharp;
|
||||
|
||||
namespace StellaOps.Concelier.Federation.Compression;
|
||||
|
||||
/// <summary>
|
||||
/// ZStandard compression utilities for federation bundles.
|
||||
/// </summary>
|
||||
public static class ZstdCompression
|
||||
{
|
||||
/// <summary>Default compression level (balanced speed/ratio).</summary>
|
||||
public const int DefaultLevel = 3;
|
||||
|
||||
/// <summary>Minimum compression level.</summary>
|
||||
public const int MinLevel = 1;
|
||||
|
||||
/// <summary>Maximum compression level.</summary>
|
||||
public const int MaxLevel = 19;
|
||||
|
||||
/// <summary>
|
||||
/// Create a compression stream wrapping the output.
|
||||
/// </summary>
|
||||
/// <param name="output">Target stream for compressed data.</param>
|
||||
/// <param name="level">Compression level (1-19, default 3).</param>
|
||||
/// <returns>Stream that compresses data written to it.</returns>
|
||||
public static CompressionStream CreateCompressionStream(Stream output, int level = DefaultLevel)
|
||||
{
|
||||
ValidateLevel(level);
|
||||
return new CompressionStream(output, level);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a decompression stream wrapping the input.
|
||||
/// </summary>
|
||||
/// <param name="input">Source stream of compressed data.</param>
|
||||
/// <returns>Stream that decompresses data read from it.</returns>
|
||||
public static DecompressionStream CreateDecompressionStream(Stream input)
|
||||
{
|
||||
return new DecompressionStream(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress data in memory.
|
||||
/// </summary>
|
||||
/// <param name="data">Uncompressed data.</param>
|
||||
/// <param name="level">Compression level (1-19, default 3).</param>
|
||||
/// <returns>Compressed data.</returns>
|
||||
public static byte[] Compress(ReadOnlySpan<byte> data, int level = DefaultLevel)
|
||||
{
|
||||
ValidateLevel(level);
|
||||
using var compressor = new Compressor(level);
|
||||
return compressor.Wrap(data).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompress data in memory.
|
||||
/// </summary>
|
||||
/// <param name="compressed">Compressed data.</param>
|
||||
/// <returns>Decompressed data.</returns>
|
||||
public static byte[] Decompress(ReadOnlySpan<byte> compressed)
|
||||
{
|
||||
using var decompressor = new Decompressor();
|
||||
return decompressor.Unwrap(compressed).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress a file to another file.
|
||||
/// </summary>
|
||||
public static async Task CompressFileAsync(
|
||||
string inputPath,
|
||||
string outputPath,
|
||||
int level = DefaultLevel,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
ValidateLevel(level);
|
||||
await using var input = File.OpenRead(inputPath);
|
||||
await using var output = File.Create(outputPath);
|
||||
await using var compressor = CreateCompressionStream(output, level);
|
||||
await input.CopyToAsync(compressor, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompress a file to another file.
|
||||
/// </summary>
|
||||
public static async Task DecompressFileAsync(
|
||||
string inputPath,
|
||||
string outputPath,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
await using var input = File.OpenRead(inputPath);
|
||||
await using var decompressor = CreateDecompressionStream(input);
|
||||
await using var output = File.Create(outputPath);
|
||||
await decompressor.CopyToAsync(output, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompress from one stream to another.
|
||||
/// </summary>
|
||||
public static async Task DecompressAsync(
|
||||
Stream input,
|
||||
Stream output,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
await using var decompressor = CreateDecompressionStream(input);
|
||||
await decompressor.CopyToAsync(output, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress from one stream to another.
|
||||
/// </summary>
|
||||
public static async Task CompressAsync(
|
||||
Stream input,
|
||||
Stream output,
|
||||
int level = DefaultLevel,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
ValidateLevel(level);
|
||||
await using var compressor = CreateCompressionStream(output, level);
|
||||
await input.CopyToAsync(compressor, ct);
|
||||
}
|
||||
|
||||
private static void ValidateLevel(int level)
|
||||
{
|
||||
if (level < MinLevel || level > MaxLevel)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(level),
|
||||
level,
|
||||
$"Compression level must be between {MinLevel} and {MaxLevel}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user