Skip to content

Commit

Permalink
Merge pull request #2 from sj-i/string-pass-by-ref
Browse files Browse the repository at this point in the history
support conversion to strings passed by ref
  • Loading branch information
sj-i committed Aug 28, 2021
2 parents 39caea6 + a917013 commit 7f1ef2a
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 27 deletions.
75 changes: 48 additions & 27 deletions src/TypedCDataWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,33 +55,45 @@ public function createWrapper(callable $callable): \Closure
return $typed_c_data_array->toCData($toCData);
};
} elseif ($parameter->isPassedByReference()) {
$input_converters[] = function (CData $cdata): CData {
/** @var \FFI\CDataArray $cdata */
return $cdata[0];
};
$outout_converters[] =
/**
* @param mixed $value
* @param \FFI\CDataArray $toCData
* @return mixed
*/
function ($value, CData $toCData) {
/** @psalm-suppress MixedAssignment */
return $toCData[0] = $value;
$type = $parameter->getType();
if ($type instanceof \ReflectionNamedType and $type->getName() === 'string') {
$input_converters[] = function (CData $cdata): string {
return \FFI::string($cdata);
};
$outout_converters[] =
function (string $value, CData $toCData): CData {
\FFI::memcpy($toCData, $value, strlen($value));
return $toCData;
};
} else {
$input_converters[] = function (CData $cdata): CData {
/** @var \FFI\CDataArray $cdata */
return $cdata[0];
};
$outout_converters[] =
/**
* @param mixed $value
* @param \FFI\CDataArray $toCData
* @return mixed
*/
function ($value, CData $toCData) {
/** @psalm-suppress MixedAssignment */
return $toCData[0] = $value;
};
}
} else {
$input_converters[] =
/**
* @param mixed $data
* @return mixed
*/
* @param mixed $data
* @return mixed
*/
fn ($data) => $data;
$outout_converters[] =
/**
* @param mixed $_1
* @param mixed $_2
* @return mixed
*/
* @param mixed $_1
* @param mixed $_2
* @return mixed
*/
fn ($_1, $_2) => $_1;
}
}
Expand All @@ -91,20 +103,29 @@ function ($value, CData $toCData) {
function (...$args) use ($input_converters, $outout_converters, $callable) {
$new_args = [];
foreach ($input_converters as $key => $converter) {
if (is_null($args[$key])) {
$new_args[$key] = $args[$key];
continue;
}
/**
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
*/
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
*/
$new_args[$key] = $converter($args[$key]);
}
/** @psalm-suppress MixedAssignment */
$result = $callable(...$new_args);
foreach ($outout_converters as $key => $converter) {
if (is_null($new_args[$key])) {
$args[$key] = $new_args[$key];
continue;
}
assert(!is_null($args[$key]));
/**
* @psalm-suppress PossiblyInvalidArgument
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
*/
* @psalm-suppress PossiblyInvalidArgument
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
*/
$args[$key] = $converter($new_args[$key], $args[$key]);
}
if ($result instanceof TypedCDataInterface) {
Expand Down
15 changes: 15 additions & 0 deletions tests/TypedCDataWrapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ public function testMethod(TestType1 $test_type_1): void
$this->assertSame(123, $test_type_cdata->int_field);
}

public function testCreateWrapperNullableStringPassByRef()
{
$test_class = new class () {
public function testMethod(?string &$test): void
{
$test = 'test';
}
};
$wrapper_creator = new TypedCDataWrapper();
$wrapper = $wrapper_creator->createWrapper([$test_class, 'testMethod']);
$buffer = \FFI::new('char[100]');
$wrapper($buffer);
$this->assertSame('test', \FFI::string($buffer));
}

public function testCreateWrapperTypedCDataArray()
{
$test_class = new class ($this) {
Expand Down

0 comments on commit 7f1ef2a

Please sign in to comment.