Skip to content

Abstract algorithm options into an Options class #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 3, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/php/io/streams/compress/Algorithm.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public abstract function extension(): string;
public abstract function level(int $select): int;

/** Compresses data */
public abstract function compress(string $data, int $level= Compression::DEFAULT): string;
public abstract function compress(string $data, $options= null): string;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes create a BC break for classes extending this base class:

use io\streams\compress\Algorithm;

class Impl extends Algorithm {
  public function compress(string $data, int $level= -1): string { }

  /* Shortened for brevity */
}

...raises the following error: Declaration of Impl::compress(string $data, int $level = -1): string must be compatible with io\streams\compress\Algorithm::compress(string $data, $options = null): string

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For anyone calling these methods BC is ensured, see example above.


/** Decompresses bytes */
public abstract function decompress(string $bytes): string;
Expand All @@ -30,7 +30,7 @@ public abstract function decompress(string $bytes): string;
public abstract function open(InputStream $in): InputStream;

/** Opens an output stream for writing */
public abstract function create(OutputStream $out, int $level= Compression::DEFAULT): OutputStream;
public abstract function create(OutputStream $out, $options= null): OutputStream;

/** @return string */
public function hashCode() { return crc32($this->name()); }
Expand Down
8 changes: 4 additions & 4 deletions src/main/php/io/streams/compress/Brotli.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public function level(int $select): int {
}

/** Compresses data */
public function compress(string $data, int $level= Compression::DEFAULT): string {
return brotli_compress($data, $this->level($level));
public function compress(string $data, $options= null): string {
return brotli_compress($data, $this->level(Options::from($options)->level));
}

/** Decompresses bytes */
Expand All @@ -38,7 +38,7 @@ public function open(InputStream $in): InputStream {
}

/** Opens an output stream for writing */
public function create(OutputStream $out, int $level= Compression::DEFAULT): OutputStream {
return new BrotliOutputStream($out, $this->level($level));
public function create(OutputStream $out, $options= null): OutputStream {
return new BrotliOutputStream($out, $this->level(Options::from($options)->level));
}
}
8 changes: 4 additions & 4 deletions src/main/php/io/streams/compress/Bzip2.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public function level(int $select): int {
}

/** Compresses data */
public function compress(string $data, int $level= Compression::DEFAULT): string {
return bzcompress($data, $this->level($level));
public function compress(string $data, $options= null): string {
return bzcompress($data, $this->level(Options::from($options)->level));
}

/** Decompresses bytes */
Expand All @@ -43,7 +43,7 @@ public function open(InputStream $in): InputStream {
}

/** Opens an output stream for writing */
public function create(OutputStream $out, int $level= Compression::DEFAULT): OutputStream {
return new Bzip2OutputStream($out, $this->level($level));
public function create(OutputStream $out, $options= null): OutputStream {
return new Bzip2OutputStream($out, $this->level(Options::from($options)->level));
}
}
8 changes: 4 additions & 4 deletions src/main/php/io/streams/compress/Gzip.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public function level(int $select): int {
}

/** Compresses data */
public function compress(string $data, int $level= Compression::DEFAULT): string {
return gzcompress($data, $this->level($level));
public function compress(string $data, $options= null): string {
return gzcompress($data, $this->level(Options::from($options)->level));
}

/** Decompresses bytes */
Expand All @@ -44,7 +44,7 @@ public function open(InputStream $in): InputStream {
}

/** Opens an output stream for writing */
public function create(OutputStream $out, int $level= Compression::DEFAULT): OutputStream {
return new GzipOutputStream($out, $this->level($level));
public function create(OutputStream $out, $options= null): OutputStream {
return new GzipOutputStream($out, $this->level(Options::from($options)->level));
}
}
4 changes: 2 additions & 2 deletions src/main/php/io/streams/compress/None.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function extension(): string { return ''; }
public function level(int $select): int { return 0; }

/** Compresses data */
public function compress(string $data, int $level= Compression::DEFAULT): string { return $data; }
public function compress(string $data, $options= null): string { return $data; }

/** Decompresses bytes */
public function decompress(string $bytes): string { return $bytes; }
Expand All @@ -31,7 +31,7 @@ public function open(InputStream $in): InputStream {
}

/** Opens an output stream for writing */
public function create(OutputStream $out, int $level= Compression::DEFAULT): OutputStream {
public function create(OutputStream $out, $options= null): OutputStream {
return $out;
}
}
59 changes: 59 additions & 0 deletions src/main/php/io/streams/compress/Options.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php namespace io\streams\compress;

use io\streams\Compression;
use lang\Value;
use util\Comparison;

/** @test io.streams.compress.unittest.OptionsTest */
class Options implements Value {
use Comparison;

public $level, $length;

/**
* Compression options
*
* @param ?int $level
* @param ?int $length
*/
public function __construct(
$level= null,
$length= null
) {
$this->level= $level ?? Compression::DEFAULT;
$this->length= $length;
}

/** @param ?int|[:var]|self $arg */
public static function from($arg): self {
if (null === $arg) {
return new self();
} else if ($arg instanceof self) {
return $arg;
} else if (is_array($arg)) {
return new self(
$arg['level'] ?? null,
$arg['length'] ?? null
);
} else {
return new self($arg);
}
}

/** @return string */
public function toString() {
switch ($this->level) {
case Compression::FASTEST: $level= 'FASTEST'; break;
case Compression::DEFAULT: $level= 'DEFAULT'; break;
case Compression::STRONGEST: $level= 'STRONGEST'; break;
default: $level= $this->level;
}

return sprintf(
'%s(level: %s, length: %s)',
nameof($this),
$level,
null === $this->length ? 'null' : $this->length
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,32 @@ public function name(): string { return 'test'; }
public function token(): string { return 'x-test'; }
public function extension(): string { return '.test'; }
public function level(int $select): int { return $select; }
public function compress(string $data, int $level= Compression::DEFAULT): string { return $data; }
public function compress(string $data, $options= null): string { return $data; }
public function decompress(string $bytes): string { return $bytes; }
public function open(InputStream $in): InputStream { return $in; }
public function create(OutputStream $out, int $method= Compression::DEFAULT): OutputStream { return $out; }
public function create(OutputStream $out, $options= null): OutputStream { return $out; }
};
$this->additional= new class() extends Algorithm {
public function supported(): bool { return true; }
public function name(): string { return 'add'; }
public function token(): string { return 'x-add'; }
public function extension(): string { return '.add'; }
public function level(int $select): int { return $select; }
public function compress(string $data, int $level= Compression::DEFAULT): string { return $data; }
public function compress(string $data, $options= null): string { return $data; }
public function decompress(string $bytes): string { return $bytes; }
public function open(InputStream $in): InputStream { return $in; }
public function create(OutputStream $out, int $method= Compression::DEFAULT): OutputStream { return $out; }
public function create(OutputStream $out, $options= null): OutputStream { return $out; }
};
$this->unsupported= new class() extends Algorithm {
public function supported(): bool { return false; }
public function name(): string { return 'lzw'; }
public function token(): string { return 'compress'; }
public function extension(): string { return '.lz'; }
public function level(int $select): int { return $select; }
public function compress(string $data, int $level= Compression::DEFAULT): string { return $data; }
public function compress(string $data, $options= null): string { return $data; }
public function decompress(string $bytes): string { return $bytes; }
public function open(InputStream $in): InputStream { return $in; }
public function create(OutputStream $out, int $method= Compression::DEFAULT): OutputStream { return $out; }
public function create(OutputStream $out, $options= null): OutputStream { return $out; }
};
}

Expand Down
87 changes: 87 additions & 0 deletions src/test/php/io/streams/compress/unittest/OptionsTest.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php namespace io\streams\compress\unittest;

use io\streams\Compression;
use io\streams\compress\Options;
use test\{Assert, Test, Values};

class OptionsTest {
const LENGTH= 6100;

/** @return iterable */
private function maps() {
yield [[], Compression::DEFAULT, null];
yield [['unused' => -1], Compression::DEFAULT, null];
yield [['level' => Compression::FASTEST], Compression::FASTEST, null];
yield [['level' => Compression::FASTEST, 'length' => self::LENGTH], Compression::FASTEST, self::LENGTH];
}

#[Test]
public function can_create() {
new Options();
}

#[Test]
public function default_level() {
Assert::equals(Compression::DEFAULT, (new Options())->level);
}

#[Test]
public function default_length() {
Assert::null((new Options())->length);
}

#[Test, Values([Compression::FASTEST, Compression::DEFAULT, Compression::STRONGEST])]
public function level($level) {
Assert::equals($level, (new Options($level))->level);
}

#[Test]
public function length() {
Assert::equals(self::LENGTH, (new Options(null, self::LENGTH))->length);
}

#[Test]
public function from_level() {
Assert::equals(new Options(Compression::FASTEST, null), Options::from(Compression::FASTEST));
}

#[Test]
public function from_null() {
Assert::equals(new Options(Compression::DEFAULT, null), Options::from(null));
}

#[Test]
public function from_options() {
$options= new Options(Compression::FASTEST, self::LENGTH);
Assert::equals($options, Options::from($options));
}

#[Test, Values(from: 'maps')]
public function from($map, $level, $length) {
Assert::equals(new Options($level, $length), Options::from($map));
}

#[Test]
public function string_representation() {
Assert::equals(
'io.streams.compress.Options(level: DEFAULT, length: null)',
(new Options())->toString()
);
}

#[Test]
public function string_representation_with_length() {
Assert::equals(
'io.streams.compress.Options(level: DEFAULT, length: 6100)',
(new Options(null, self::LENGTH))->toString()
);
}

#[Test]
public function string_representation_with_level() {
Assert::equals(
'io.streams.compress.Options(level: 22, length: null)',
(new Options(22))->toString()
);
}
}
Loading