Full Code of zakirullin/mess for AI

master 76f79b3507be cached
28 files
92.4 KB
24.9k tokens
354 symbols
1 requests
Download .txt
Repository: zakirullin/mess
Branch: master
Commit: 76f79b3507be
Files: 28
Total size: 92.4 KB

Directory structure:
gitextract_1f2ttfmh/

├── .github/
│   └── workflows/
│       └── php.yml
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── composer.json
├── infection.json.dist
├── phpunit.xml.dist
├── psalm.xml.dist
├── src/
│   ├── Enum/
│   │   └── TypeEnum.php
│   ├── Exception/
│   │   ├── CannotModifyMessException.php
│   │   ├── MessExceptionInterface.php
│   │   ├── MissingKeyException.php
│   │   ├── UncastableValueException.php
│   │   ├── UnexpectedKeyTypeException.php
│   │   └── UnexpectedTypeException.php
│   ├── Mess.php
│   ├── MessInterface.php
│   ├── MissingMess.php
│   ├── TypedAccessor.php
│   └── functions.php
└── tests/
    └── unit/
        ├── Exception/
        │   ├── MissingKeyExceptionTest.php
        │   ├── UncastableValueExceptionTest.php
        │   ├── UnexpectedKeyTypeExceptionTest.php
        │   └── UnexpectedTypeExceptionTest.php
        ├── MessTest.php
        └── MissingMessTest.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/php.yml
================================================
name: GitHub Build

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

permissions:
  contents: read

jobs:
  build:
    strategy:
      matrix:
        php-versions: ['8.4', '8.3', '8.2', '8.1', '8.0', '7.4', '7.2']
        
    runs-on: ubuntu-24.04

    steps:

    - uses: actions/checkout@v4

    - name: setup PHP ${{ matrix.php-versions }}
      uses: shivammathur/setup-php@v2
      with:
        php-version: ${{ matrix.php-versions }}

    - name: php version check
      run: php -v

    - name: Validate composer.json 
      run: composer validate --strict
        
    - name: run composer (install dependencies)
      run: composer install --prefer-dist --no-progress

    - name: run psalm (static analysis)
      run: vendor/bin/psalm
   
    - name: run unit tests ( ${{ matrix.php-versions }} )
      run: composer test
    


================================================
FILE: .gitignore
================================================
/vendor
/build
/test-reports
composer.lock
phpunit.xml
psalm.xml
.phpunit.result.cache
.idea


================================================
FILE: .travis.yml
================================================
language: php
sudo: false

php:
  - 8.0

before_script:
  - composer self-update
  - composer install -n

script:
  - composer test
  - vendor/bin/phpunit
  - vendor/bin/psalm --shepherd


================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [0.8.4] - 2022-04-05
### Added
- php 8.1 support

## [0.8.0] - 2020-12-19
### Added
- `float` is now supported

### Changed
- trim is applied to bool so to have a consistent behaviour among all methods

## [0.7.2] - 2020-08-08
### Changed
- static methods are now functions

## [0.7.1] - 2020-08-06
### Changed
- find/get methods refactoring

## [0.7.0] - 2020-08-04
### Changed
- `find*` methods can now throw `UnexpectedValueException` & `UncastableValueException`
- renamed `Finder` to `Checker` (not to confuse with the logic in `find*` methods)

## [0.6.0] - 2020-08-03
### Added
- access to object's properties through `Mess` (useful when doing `json_decode`)
- `Throwable` to `MessExceptionInterface`

## [0.5.5] - 2020-08-02
### Added
- case insensitive 'true' & 'false' to bool casting

## [0.5.4] - 2020-08-02
### Removed
- 'true' & 'false' to bool casting

## [0.5.3] - 2020-08-02
### Removed
- 'true' & 'false' to bool casting

## [0.5.1] - 2020-08-01
### Added
- `getArrayOfStringToMixed()`
- `findArrayOfStringToMixed()`

## [0.5.0] - 2020-08-01
### Added
- It is Mess now 🍺

## [0.4.0] - 2020-08-01
### Removed
- `TypedAccessor` (deprecated, use `Mess` instead)

## [0.3.1] - 2020-08-01
### Added
- `Mess` alias (can be used instead long and boring `TypedAccessor`)
- more tests

## [0.3.0] - 2020-08-01
### Added
- `getObject()`
- `getArray()`
- `getArrayOfStringToInt()`
- `getArrayOfStringToBool()`
- `getArrayOfStringToString()`

### Fix
- static classes instead of stateless type objects
- separate finder classes
- type asserts 

## [0.2.1] - 2020-07-18
### Fix
- Psalm warnings (errorLevel="1")

## [0.2.0] - 2020-07-17
### Added
- Separate type classes
- List types

## [0.1.0] - 2020-05-21
### Added
- Initial release

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2018 Artem Zakirullin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

================================================
FILE: README.md
================================================
## Mess

![GitHub Build Status](https://github.com/zakirullin/mess/actions/workflows/php.yml/badge.svg)
![Psalm coverage](https://shepherd.dev/github/zakirullin/mess/coverage.svg?)
![PHP from Packagist](https://img.shields.io/packagist/php-v/zakirullin/mess.svg?style=flat-square)
[![Latest Stable Version](https://poser.pugx.org/zakirullin/mess/v/stable.svg)](https://packagist.org/packages/zakirullin/mess)
![GitHub commits](https://img.shields.io/github/commits-since/zakirullin/mess/0.1.0.svg?style=flat-square)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)

## We face a few problems in our PHP projects

- Illogical type casting (`PHP`'s native implementation is way too "smart")
- Pointless casts like `array => float` are **allowed**
- Boilerplate code to work with arrays (check if `isset()`, throw an exception, cast the type, etc.)

Consider an example:
```php
$userId = $queryParams['userId'] ?? null;
if ($userId === null) {
    throw ...
}
$userId = (int)$userId;
```

## Way too verbose. Any ideas?

```php
$userId = (new Mess($queryParams))['userId']->getAsInt();
```

You can mess with API responses/configs/whatever:

```php
$mess = new Mess($response);
$book = new Book(
    $mess['title']->getString(),
    $mess['isBestseller']->getBool(),
    $mess['stats']['rating']->getInt(),
    $mess['tags']->getListOfString()
);
```

## Generics support (Psalm compatible)

- `getListOfString()`
- `getListOfInt()`
- `getArrayOfStringToString()`
- `getArrayOfStringToBool()`
- etc.

## Installation

```bash
$ composer require zakirullin/mess
```

## Dealing with mess

```php
$queryParams = new Mess(['isDeleted' => 'true']);
$queryParams['isDeleted']->getBool(); // UnexpectedTypeException
$queryParams['isDeleted']->getAsBool(); // true

$value = new Mess('25');
$value->getInt(); // UnexpectedTypeException
$value->getAsInt(); // 25
$value->getString(); // '25'

$value = new Mess('25a');
$value->getInt(); // UnexpectedTypeException
$value->getAsInt(); // UncastableValueException

$config = new Mess(['param' => '1']);
$config['a']['b']->getInt(); // MissingKeyException: "MissingKeyException: a.b"
$config['a']['b']->findInt(); // null
$config['param']->getInt(); // UnexpectedTypeException 
$config['param']->getAsInt(); // 1
$config['param']->findInt(); // UnexpectedTypeException
$config['param']->findAsInt(); // 1
```

As you might notice, type casting is performed while using `(find|get)As*` methods.
Having trouble grasping `get*()`/`find*()`? Check out brilliant [Ocramius's slides](https://ocramius.github.io/doctrine-best-practices/#/94).

## Type casting with Mess is rather predictable

```php
'\d+' => int // OK
'buzz12' => int // UncastableValueException
bool => int // UncastableValueException
array => int // UncastableValueException
object => int // UncastableValueException
resource => int // UncastableValueException
```

Fairly simple, isn't it? Let us **fail fast**!

### Why one needs THAT naive type casting?

Let's imagine a library that is configured this way:
```php
$config = [
    'retries' => 5, // int
    'delay' => 20, // int
]

// Initialization 
$retries = $config['retries'] ?? null;
if ($retries === null) {
    throw new MissingConfigKeyException(...);
}
...
$retries = (int)$retries;
$delay = (int)$delay;
```

Client-side code: 
```php
$config => [
    'retries' => [5, 10, 30], // (int)array => 1
    'delay' => true, // (int)bool => 1
]
```

No matter if that's a misuse, or a result of major update: The system will continue to work.
And that's the worst thing about it. It will continue to work, though, not in a way it was supposed to work.
`PHP` is trying to do its best to let it work **at least somehow**.

## The library comes in handy in a variety of scenarios 🚀

- Deserialized data
- Request `body`/`query` 
- `API` response
- Config
- etc.


================================================
FILE: composer.json
================================================
{
  "name": "zakirullin/mess",
  "type": "library",
  "description": "Convenient array-related routine & better type casting",
  "keywords": [
    "array",
    "type",
    "assert",
    "cast",
    "mess",
    "language",
    "php",
    "json"
  ],
  "homepage": "https://github.com/zakirullin/mess",
  "license": "MIT",
  "authors": [
    {
      "name": "Artem Zakirullin",
      "email": "artemzr@gmail.com"
    }
  ],
  "config": {
    "sort-packages": true,
    "allow-plugins": {
      "infection/extension-installer": true
    }
  },
  "require": {
    "php": "^7.2|^8.0"
  },
  "require-dev": {
    "composer/xdebug-handler": "^1.4|2.0",
    "infection/infection": "*",
    "phpunit/phpunit": "^8.0|^9.0",
    "symfony/string": "^5.4.43",
    "sanmai/pipeline": "5.2.1",
    "vimeo/psalm": "*"
  },
  "autoload": {
    "psr-4": {
      "Zakirullin\\Mess\\": "src/",
      "Zakirullin\\TypedAccessor\\": "src/"
    },
    "files": [
      "src/functions.php"
    ]
  },
  "scripts": {
    "test": [
      "@php vendor/bin/phpunit --stderr --coverage-text"
    ],
    "coverage": "phpunit --coverage-html=coverage"
  },
  "autoload-dev": {
    "psr-4": {
      "Zakirullin\\Mess\\Tests\\": "tests/unit/"
    }
  }
}


================================================
FILE: infection.json.dist
================================================
{
  "timeout": 10,
  "source": {
    "directories": [
      "src"
    ]
  },
  "logs": {
    "text": "build/log/infection/text.txt",
    "summary": "build/log/infection/summary.txt",
    "debug": "build/log/infection/debug.txt",
    "perMutator": "build/log/infection/per-mutator.md"
  }
}


================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
        colors="true"
        forceCoversAnnotation="true"
        defaultTestSuite="all">
    <testsuites>
        <testsuite name="all">
            <directory>tests/unit/</directory>
        </testsuite>
        <testsuite name="unit">
            <directory>tests/unit/</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">src/</directory>
            <exclude>
                <directory>src/Enum</directory>
                <directory>src/Caster</directory>
                <directory>src/Finder</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>

================================================
FILE: psalm.xml.dist
================================================
<?xml version="1.0"?>
<psalm
    errorLevel="1"
    resolveFromConfigFile="true"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="https://getpsalm.org/schema/config"
    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
    <projectFiles>
        <directory name="src" />
        <ignoreFiles>
            <directory name="vendor" />
        </ignoreFiles>

    </projectFiles>
    <issueHandlers>
        <MissingOverrideAttribute errorLevel="info"/>
        <UnusedClass errorLevel="info"/>
        <PossiblyUnusedMethod errorLevel="info"/>
    </issueHandlers>
</psalm>


================================================
FILE: src/Enum/TypeEnum.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Enum;

final class TypeEnum
{
    public const INT = 'int';
    public const FLOAT = 'float';
    public const BOOL = 'bool';
    public const STRING = 'string';
    public const OBJECT = 'object';
    public const ARRAY = 'array';

    public const LIST_OF_INT = 'list<int>';
    public const LIST_OF_FLOAT = 'list<float>';
    public const LIST_OF_STRING = 'list<string>';

    public const ARRAY_OF_STRING_TO_INT = 'array<string,int>';
    public const ARRAY_OF_STRING_TO_FLOAT = 'array<string,float>';
    public const ARRAY_OF_STRING_TO_BOOL = 'array<string,bool>';
    public const ARRAY_OF_STRING_TO_STRING = 'array<string,string>';
    public const ARRAY_OF_STRING_TO_MIXED = 'array<string,mixed>';
}

================================================
FILE: src/Exception/CannotModifyMessException.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Exception;

use RuntimeException;
use Throwable;

final class CannotModifyMessException extends RuntimeException implements MessExceptionInterface
{
    /**
     * @psalm-var list<string|int>
     *
     * @var array
     */
    private $keySequence;

    /**
     * @psalm-param list<string|int> $keySequence
     *
     * @param array          $keySequence
     * @param Throwable|null $previous
     */
    public function __construct(array $keySequence, Throwable $previous = null)
    {
        $this->keySequence = $keySequence;

        $message = "Mess cannot modify it's value";

        parent::__construct($message, 0, $previous);
    }

    /**
     * @psalm-return list<string|int>
     *
     * @return array
     */
    public function getKeySequence(): array
    {
        return $this->keySequence;
    }
}

================================================
FILE: src/Exception/MessExceptionInterface.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Exception;

use Throwable;

interface MessExceptionInterface extends Throwable
{
      /** @psalm-return list<string|int>
     *
     * @return array
     */
    public function getKeySequence(): array;
}

================================================
FILE: src/Exception/MissingKeyException.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Exception;

use RuntimeException;
use Throwable;
use function implode;

final class MissingKeyException extends RuntimeException implements MessExceptionInterface
{
      /** @psalm-var list<string|int>
     *
     * @var array
     */
    private $keySequence;

    /**
     * @psalm-param list<string|int> $keySequence
     *
     * @param array          $keySequence
     * @param Throwable|null $previous
     */
    public function __construct(array $keySequence, Throwable $previous = null)
    {
        $this->keySequence = $keySequence;

        $message = "Missing key: '{$this->getAbsoluteKey()}'";

        parent::__construct($message, 0, $previous);
    }

    /**
     * @psalm-return list<string|int>
     *
     * @return array
     */
    public function getKeySequence(): array
    {
        return $this->keySequence;
    }

    /**
     * @return string
     */
    private function getAbsoluteKey(): string
    {
        return implode('.', $this->keySequence);
    }
}

================================================
FILE: src/Exception/UncastableValueException.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Exception;

use RuntimeException;
use Throwable;
use function gettype;

final class UncastableValueException extends RuntimeException implements MessExceptionInterface
{
    /**
     * @var string
     */
    private $desiredType;

    /**
     * @var mixed
     */
    private $value;

    /**
     * @psalm-var list<string|int>
     *
     * @var array
     */
    private $keySequence;

    /**
     * @psalm-param list<string|int> $keySequence
     *
     * @param string         $desiredType
     * @param mixed          $value
     * @param array          $keySequence
     * @param Throwable|null $previous
     */
    public function __construct(string $desiredType, $value, array $keySequence, Throwable $previous = null)
    {
        $this->desiredType = $desiredType;
        $this->value = $value;
        $this->keySequence = $keySequence;

        $actualType = gettype($value);
        $message = "Cannot cast value of type '{$actualType}' to '{$desiredType}'";

        parent::__construct($message, 0, $previous);
    }

    /**
     * @return string
     */
    public function getDesiredType(): string
    {
        return $this->desiredType;
    }

    /**
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * @psalm-return list<string|int>
     *
     * @return array
     */
    public function getKeySequence(): array
    {
        return $this->keySequence;
    }
}

================================================
FILE: src/Exception/UnexpectedKeyTypeException.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Exception;

use RuntimeException;
use Throwable;
use function gettype;

final class UnexpectedKeyTypeException extends RuntimeException implements MessExceptionInterface
{
    /**
     * @var mixed
     */
    private $key;

    /**
     * @psalm-var list<string|int>
     *
     * @var array
     */
    private $keySequence;

    /**
     * @psalm-param list<string|int> $keySequence
     *
     * @param mixed          $key
     * @param array          $keySequence
     * @param Throwable|null $previous
     */
    public function __construct($key, array $keySequence, Throwable $previous = null)
    {
        $this->key = $key;
        $this->keySequence = $keySequence;

        $keyType = gettype($key);
        $message = "Unexpected key type: '{$keyType}', expected key types are: string, integer";

        parent::__construct($message, 0, $previous);
    }

    /**
     * @return mixed
     */
    public function getKey()
    {
        return $this->key;
    }

    /**
     * @psalm-return list<string|int>
     *
     * @return array
     */
    public function getKeySequence(): array
    {
        return $this->keySequence;
    }
}

================================================
FILE: src/Exception/UnexpectedTypeException.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Exception;

use RuntimeException;
use Throwable;
use function gettype;
use function implode;
use function sprintf;

final class UnexpectedTypeException extends RuntimeException implements MessExceptionInterface
{
    /**
     * @var string
     */
    private $expectedType;

    /**
     * @var mixed
     */
    private $value;

    /**
     * @psalm-var list<string|int>
     *
     * @var array
     */
    private $keySequence;

    /**
     * @psalm-param list<string|int> $keySequence
     *
     * @param string         $expectedType
     * @param mixed          $value
     * @param array          $keySequence
     * @param Throwable|null $previous
     */
    public function __construct(string $expectedType, $value, array $keySequence, Throwable $previous = null)
    {
        $this->expectedType = $expectedType;
        $this->value = $value;
        $this->keySequence = $keySequence;

        $actualType = gettype($value);
        $message = "Expected type for key '{$this->getAbsoluteKey()}' is '{$expectedType}', got '{$actualType}' instead";

        parent::__construct($message, 0, $previous);
    }

    /**
     * @return string
     */
    public function getExpectedType(): string
    {
        return $this->expectedType;
    }

    /**
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * @psalm-return list<string|int>
     *
     * @return array
     */
    public function getKeySequence(): array
    {
        return $this->keySequence;
    }

    /**
     * @return string
     */
    private function getAbsoluteKey(): string
    {
        return sprintf('[%s]', implode('.', $this->keySequence));
    }
}

================================================
FILE: src/Mess.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess;

use Zakirullin\Mess\Enum\TypeEnum;
use Zakirullin\Mess\Exception\CannotModifyMessException;
use Zakirullin\Mess\Exception\UncastableValueException;
use Zakirullin\Mess\Exception\UnexpectedKeyTypeException;
use Zakirullin\Mess\Exception\UnexpectedTypeException;
use function is_array;
use function is_bool;
use function is_int;
use function is_float;
use function is_object;
use function is_string;
use function key_exists;
use function property_exists;

/**
 * @psalm-immutable
 */
class Mess implements MessInterface
{
    /**
     * @var mixed
     */
    private $value;

    /**
     * @psalm-allow-private-mutation
     * @psalm-var list<string|int>
     *
     * @var array
     */
    private $keySequence = [];

    /**
     * @param mixed $value
     */
    public function __construct($value)
    {
        $this->value = $value;
    }

    /**
     * @return int
     */
    public function getInt(): int
    {
        $this->assertType(is_int($this->value), TypeEnum::INT);

        /**
         * @var int
         */
        return $this->value;
    }

    /**
     * @return float
     */
    public function getFloat(): float
    {
        $this->assertType(is_float($this->value), TypeEnum::FLOAT);

        /**
         * @var float
         */
        return $this->value;
    }

    /**
     * @return bool
     */
    public function getBool(): bool
    {
        $this->assertType(is_bool($this->value), TypeEnum::BOOL);

        /**
         * @var bool
         */
        return $this->value;
    }

    /**
     * @return string
     */
    public function getString(): string
    {
        $this->assertType(is_string($this->value), TypeEnum::STRING);

        /**
         * @var string
         */
        return $this->value;
    }

    /**
     * @psalm-return list<int>
     *
     * @return array
     */
    public function getListOfInt(): array
    {
        $this->assertType(isListOfType($this->value, 'is_int'), TypeEnum::LIST_OF_INT);

        /**
         * @psalm-var list<int>
         */
        return $this->value;
    }

    /**
     * @psalm-return list<float>
     *
     * @return array
     */
    public function getListOfFloat(): array
    {
        $this->assertType(isListOfType($this->value, 'is_float'), TypeEnum::FLOAT);

        /**
         * @psalm-var list<float>
         */
        return $this->value;
    }

    /**
     * @psalm-return list<string>
     *
     * @return array
     */
    public function getListOfString(): array
    {
        $this->assertType(isListOfType($this->value, 'is_string'), TypeEnum::LIST_OF_STRING);

        /**
         * @psalm-var list<string>
         */
        return $this->value;
    }

    /**
     * @psalm-return array<string, int>
     *
     * @return array
     */
    public function getArrayOfStringToInt(): array
    {
        $this->assertType(isArrayOfStringToType($this->value, 'is_int'), TypeEnum::ARRAY_OF_STRING_TO_INT);

        /**
         * @psalm-var array<string, int>
         */
        return $this->value;
    }

    /**
     * @psalm-return array<string, float>
     *
     * @return array
     */
    public function getArrayOfStringToFloat(): array
    {
        $this->assertType(isArrayOfStringToType($this->value, 'is_float'), TypeEnum::ARRAY_OF_STRING_TO_FLOAT);

        /**
         * @psalm-var array<string, float>
         */
        return $this->value;
    }

    /**
     * @psalm-return array<string, bool>
     *
     * @return array
     */
    public function getArrayOfStringToBool(): array
    {
        $this->assertType(
            isArrayOfStringToType($this->value, 'is_bool'),
            TypeEnum::ARRAY_OF_STRING_TO_BOOL
        );

        /**
         * @var array<string, bool>
         */
        return $this->value;
    }

    /**
     * @psalm-return array<string, string>
     *
     * @return array
     */
    public function getArrayOfStringToString(): array
    {
        $this->assertType(
            isArrayOfStringToType($this->value, 'is_string'),
            TypeEnum::ARRAY_OF_STRING_TO_STRING
        );

        /**
         * @psalm-var array<string, string>
         */
        return $this->value;
    }

    /**
     * @return int
     */
    public function getAsInt(): int
    {
        $int = toInt($this->value);

        $this->assertCastable($int !== null, TypeEnum::INT);

        /**
         * @var int
         */
        return $int;
    }

    /**
     * @return float
     */
    public function getAsFloat(): float
    {
        $float = toFloat($this->value);

        $this->assertCastable($float !== null, TypeEnum::FLOAT);

        /**
         * @var float
         */
        return $float;
    }

    /**
     * @return bool
     */
    public function getAsBool(): bool
    {
        $bool = toBool($this->value);

        $this->assertCastable($bool !== null, TypeEnum::BOOL);

        return $bool;
    }

    /**
     * @return string
     */
    public function getAsString(): string
    {
        $string = toString($this->value);

        $this->assertCastable($string !== null, TypeEnum::STRING);

        return $string;
    }

    /**
     * @psalm-return list<int>
     *
     * @return array
     */
    public function getAsListOfInt(): array
    {
        /**
         * @psalm-var list<int>|null
         */
        $listOfInt = toListOfType($this->value, '\Zakirullin\Mess\toInt');

        $this->assertCastable($listOfInt !== null, TypeEnum::LIST_OF_INT);

        return $listOfInt;
    }

    /**
     * @psalm-return list<float>
     *
     * @return array
     */
    public function getAsListOfFloat(): array
    {
        /**
         * @psalm-var list<float>|null
         */
        $listOfFloat = toListOfType($this->value, '\Zakirullin\Mess\toFloat');

        $this->assertCastable($listOfFloat !== null, TypeEnum::LIST_OF_FLOAT);

        return $listOfFloat;
    }

    /**
     * @psalm-return list<string>
     *
     * @return array
     */
    public function getAsListOfString(): array
    {
        /**
         * @psalm-var list<string>|null
         */
        $listOfString = toListOfType($this->value, '\Zakirullin\Mess\toString');

        $this->assertCastable($listOfString !== null, TypeEnum::LIST_OF_STRING);

        return $listOfString;
    }

    /**
     * @psalm-return array<string, int>
     *
     * @return array
     */
    public function getAsArrayOfStringToInt(): array
    {
        /**
         * @psalm-var array<string, int>|null
         */
        $arrayOfStringToInt = toArrayOfStringToType($this->value, '\Zakirullin\Mess\toInt');

        $this->assertCastable($arrayOfStringToInt !== null, TypeEnum::ARRAY_OF_STRING_TO_INT);

        return $arrayOfStringToInt;
    }

    /**
     * @psalm-return array<string, float>
     *
     * @return array
     */
    public function getAsArrayOfStringToFloat(): array
    {
        /**
         * @psalm-var array<string, float>|null
         */
        $arrayOfStringToFloat = toArrayOfStringToType($this->value, '\Zakirullin\Mess\toFloat');

        $this->assertCastable($arrayOfStringToFloat !== null, TypeEnum::ARRAY_OF_STRING_TO_FLOAT);

        return $arrayOfStringToFloat;
    }

    /**
     * @psalm-return array<string, bool>
     *
     * @return array
     */
    public function getAsArrayOfStringToBool(): array
    {
        /**
         * @psalm-var array<string, bool>|null
         */
        $arrayOfStringToBool = toArrayOfStringToType($this->value, '\Zakirullin\Mess\toBool');

        $this->assertCastable($arrayOfStringToBool !== null, TypeEnum::ARRAY_OF_STRING_TO_BOOL);

        return $arrayOfStringToBool;
    }

    /**
     * @psalm-return array<string, string>
     *
     * @return array
     */
    public function getAsArrayOfStringToString(): array
    {
        /**
         * @psalm-var array<string, string>|null
         */
        $arrayOfStringToString = toArrayOfStringToType($this->value, '\Zakirullin\Mess\toString');

        $this->assertCastable($arrayOfStringToString !== null, TypeEnum::ARRAY_OF_STRING_TO_STRING);

        return $arrayOfStringToString;
    }

    /**
     * @return int|null
     */
    public function findInt(): ?int
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getInt();
    }

    /**
     * @return float|null
     */
    public function findFloat(): ?float
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getFloat();
    }

    /**
     * @return bool|null
     */
    public function findBool(): ?bool
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getBool();
    }

    /**
     * @return string|null
     */
    public function findString(): ?string
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getString();
    }

    /**
     * @psalm-return list<int>|null
     *
     * @return int[]|null
     */
    public function findListOfInt(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getListOfInt();
    }

    /**
     * @psalm-return list<float>|null
     *
     * @return float[]|null
     */
    public function findListOfFloat(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getListOfFloat();
    }

    /**
     * @psalm-return list<string>|null
     *
     * @return array|null
     */
    public function findListOfString(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getListOfString();
    }

    /**
     * @psalm-return array<string, int>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToInt(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getArrayOfStringToInt();
    }

    /**
     * @psalm-return array<string, float>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToFloat(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getArrayOfStringToFloat();
    }

    /**
     * @psalm-return array<string, bool>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToBool(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getArrayOfStringToBool();
    }

    /**
     * @psalm-return array<string, string>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToString(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getArrayOfStringToString();
    }

    /**
     * @return int|null
     */
    public function findAsInt(): ?int
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsInt();
    }

    /**
     * @return float|null
     */
    public function findAsFloat(): ?float
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsFloat();
    }

    /**
     * @return bool|null
     */
    public function findAsBool(): ?bool
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsBool();
    }

    /**
     * @return string|null
     */
    public function findAsString(): ?string
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsString();
    }

    /**
     * @psalm-return list<int>|null
     *
     * @return int[]|null
     */
    public function findAsListOfInt(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsListOfInt();
    }

    /**
     * @return float[]|null
     */
    public function findAsListOfFloat(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsListOfFloat();
    }

    /**
     * @psalm-return list<string>|null
     *
     * @return string[]|null
     */
    public function findAsListOfString(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsListOfString();
    }

    /**
     * @psalm-return array<string, int>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToInt(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsArrayOfStringToInt();
    }

    /**
     * @psalm-return array<string, float>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToFloat(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsArrayOfStringToFloat();
    }

    /**
     * @psalm-return array<string, bool>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToBool(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsArrayOfStringToBool();
    }

    /**
     * @psalm-return array<string, string>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToString(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getAsArrayOfStringToString();
    }

    /**
     * @return mixed
     */
    public function getMixed()
    {
        return $this->value;
    }

    /**
     * @return object
     */
    public function getObject(): object
    {
        $this->assertType(is_object($this->value), TypeEnum::OBJECT);

        /**
         * @var object
         */
        return $this->value;
    }

    /**
     * @return array
     */
    public function getArray(): array
    {
        $this->assertType(is_array($this->value), TypeEnum::ARRAY);

        /**
         * @var array
         */
        return $this->value;
    }

    /**
     * @psalm-return array<string, mixed>
     *
     * @return array
     */
    public function getArrayOfStringToMixed(): array
    {
        $this->assertType(isArrayOfStringToMixed($this->value), TypeEnum::ARRAY_OF_STRING_TO_MIXED);

        /**
         * @psalm-var array<string,mixed>
         */
        return $this->value;
    }

    /**
     * @return mixed
     */
    public function findMixed()
    {
        return $this->value;
    }

    /**
     * @return object|null
     */
    public function findObject(): ?object
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getObject();
    }

    /**
     * @return array|null
     */
    public function findArray(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getArray();
    }

    /**
     * @psalm-return array<string, mixed>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToMixed(): ?array
    {
        if ($this->value === null) {
            return null;
        }

        return $this->getArrayOfStringToMixed();
    }

    /**
     * @param string|int $offset
     * @return MessInterface
     */
    public function offsetGet($offset): MessInterface
    {
        /**
         * @psalm-suppress DocblockTypeContradiction
         */
        if (!is_string($offset) && !is_int($offset)) {
            throw new UnexpectedKeyTypeException($offset, $this->keySequence);
        }

        $clonedKeySequence = $this->keySequence;
        $clonedKeySequence[] = $offset;

        if (!$this->offsetExists($offset)) {
            return new MissingMess($clonedKeySequence);
        }

        return (new self($this->getByOffset($offset)))->setKeySequence($clonedKeySequence);
    }

    /**
     * @param string|int $offset
     * @return bool
     */
    public function offsetExists($offset): bool
    {
        if (is_array($this->value)) {
            return key_exists($offset, $this->value);
        }

        if (is_object($this->value) && is_string($offset)) {
            return property_exists($this->value, $offset);
        }

        return false;
    }

    /**
     * @param mixed $offset
     * @param mixed $value
     */
    public function offsetSet($offset, $value): void
    {
        throw new CannotModifyMessException($this->keySequence);
    }

    /**
     * @param mixed $offset
     */
    public function offsetUnset($offset): void
    {
        throw new CannotModifyMessException($this->keySequence);
    }

    /**
     * @psalm-param list<string|int> $keySequence
     *
     * @param array $keySequence
     * @return Mess
     */
    private function setKeySequence(array $keySequence): self
    {
        $this->keySequence = $keySequence;

        return $this;
    }

    /**
     * @param bool   $isExpected
     * @param string $expectedType
     */
    private function assertType(bool $isExpected, string $expectedType): void
    {
        if (!$isExpected) {
            throw new UnexpectedTypeException($expectedType, $this->value, $this->keySequence);
        }
    }

    /**
     * @param bool   $isCastable
     * @param string $desiredType
     */
    private function assertCastable(bool $isCastable, string $desiredType): void
    {
        if (!$isCastable) {
            throw new UncastableValueException($desiredType, $this->value, $this->keySequence);
        }
    }

    /**
     * @param string|int $offset
     * @return mixed
     */
    private function getByOffset($offset)
    {
        /**
         * @var object|array $this ->value
         */
        if (is_object($this->value) && is_string($offset)) {
            return $this->value->$offset;
        }

        /**
         * @var array $this->value
         */
        return $this->value[$offset];
    }
}


================================================
FILE: src/MessInterface.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess;

use ArrayAccess;

/**
 * @psalm-suppress MissingTemplateParam
 */
interface MessInterface extends ArrayAccess
{
    /**
     * @return int
     */
    public function getInt(): int;

    /**
     * @return float
     */
    public function getFloat(): float;

    /**
     * @return bool
     */
    public function getBool(): bool;

    /**
     * @return string
     */
    public function getString(): string;

    /**
     * @psalm-return list<int>
     *
     * @return int[]
     */
    public function getListOfInt(): array;

    /**
     * @psalm-return list<float>
     *
     * @return float[]
     */
    public function getListOfFloat(): array;

    /**
     * @psalm-return list<string>
     *
     * @return string[]
     */
    public function getListOfString(): array;

    /**
     * @psalm-return array<string, int>
     *
     * @return array
     */
    public function getArrayOfStringToInt(): array;

    /**
     * @psalm-return array<string, float>
     *
     * @return array
     */
    public function getArrayOfStringToFloat(): array;

    /**
     * @psalm-return array<string, bool>
     *
     * @return array
     */
    public function getArrayOfStringToBool(): array;

    /**
     * @psalm-return array<string, string>
     *
     * @return array
     */
    public function getArrayOfStringToString(): array;

    /**
     * @return int
     */
    public function getAsInt(): int;

    /**
     * @return float
     */
    public function getAsFloat(): float;

    /**
     * @return bool
     */
    public function getAsBool(): bool;

    /**
     * @return string
     */
    public function getAsString(): string;

    /**
     * @psalm-return list<int>
     *
     * @return array
     */
    public function getAsListOfInt(): array;

    /**
     * @psalm-return list<float>
     *
     * @return array
     */
    public function getAsListOfFloat(): array;

    /**
     * @psalm-return list<string>
     *
     * @return array
     */
    public function getAsListOfString(): array;

    /**
     * @psalm-return array<string, int>
     *
     * @return array
     */
    public function getAsArrayOfStringToInt(): array;

    /**
     * @psalm-return array<string, float>
     *
     * @return array
     */
    public function getAsArrayOfStringToFloat(): array;

    /**
     * @psalm-return array<string, bool>
     *
     * @return array
     */
    public function getAsArrayOfStringToBool(): array;

    /**
     * @psalm-return array<string, string>
     *
     * @return array
     */
    public function getAsArrayOfStringToString(): array;

    /**
     * @return int|null
     */
    public function findInt(): ?int;

    /**
     * @return float|null
     */
    public function findFloat(): ?float;

    /**
     * @return bool|null
     */
    public function findBool(): ?bool;

    /**
     * @return string|null
     */
    public function findString(): ?string;

    /**
     * @psalm-return list<int>|null
     *
     * @return int[]|null
     */
    public function findListOfInt(): ?array;

    /**
     * @psalm-return list<float>|null
     *
     * @return float[]|null
     */
    public function findListOfFloat(): ?array;

    /**
     * @psalm-return list<string>|null
     *
     * @return string[]|null
     */
    public function findListOfString(): ?array;

    /**
     * @psalm-return array<string, int>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToInt(): ?array;

    /**
     * @psalm-return array<string, float>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToFloat(): ?array;

    /**
     * @psalm-return array<string, bool>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToBool(): ?array;

    /**
     * @psalm-return array<string, string>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToString(): ?array;

    /**
     * @return int|null
     */
    public function findAsInt(): ?int;

    /**
     * @return float|null
     */
    public function findAsFloat(): ?float;

    /**
     * @return bool|null
     */
    public function findAsBool(): ?bool;

    /**
     * @return string|null
     */
    public function findAsString(): ?string;

    /**
     * @psalm-return list<int>|null
     *
     * @return int[]|null
     */
    public function findAsListOfInt(): ?array;

    /**
     * list<float>|null
     *
     * @return float[]|null
     */
    public function findAsListOfFloat(): ?array;

    /**
     * @psalm-return list<string>|null
     *
     * @return string[]|null
     */
    public function findAsListOfString(): ?array;

    /**
     * @psalm-return array<string, int>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToInt(): ?array;

    /**
     * @psalm-return array<string, float>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToFloat(): ?array;

    /**
     * @psalm-return array<string, bool>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToBool(): ?array;

    /**
     * @psalm-return array<string, string>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToString(): ?array;

    /**
     * @return mixed
     */
    public function getMixed();

    /**
     * @return object
     */
    public function getObject(): object;

    /**
     * @return array
     */
    public function getArray(): array;

    /**
     * @psalm-return array<string, mixed>
     *
     * @return array
     */
    public function getArrayOfStringToMixed(): array;

    /**
     * @return mixed
     */
    public function findMixed();

    /**
     * @return object|null
     */
    public function findObject(): ?object;

    /**
     * @return array|null
     */
    public function findArray(): ?array;

    /**
     * @psalm-return array<string, mixed>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToMixed(): ?array;

    /**
     * @param string|int $offset
     * @return MessInterface
     */
    public function offsetGet($offset): MessInterface;
}


================================================
FILE: src/MissingMess.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess;

use Zakirullin\Mess\Exception\CannotModifyMessException;
use Zakirullin\Mess\Exception\MissingKeyException;
use Zakirullin\Mess\Exception\UnexpectedKeyTypeException;
use function is_int;
use function is_string;

/**
 * @psalm-immutable
 */
final class MissingMess implements MessInterface
{
    /**
     * @psalm-readonly
     * @psalm-var list<string|int>
     *
     * @var array
     */
    private $keySequence;

    /**
     * @psalm-param list<string|int> $keySequence
     *
     * @param array $keySequence
     */
    public function __construct(array $keySequence)
    {
        $this->keySequence = $keySequence;
    }

    /**
     * @return int
     */
    public function getInt(): int
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return float
     */
    public function getFloat(): float
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return bool
     */
    public function getBool(): bool
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return string
     */
    public function getString(): string
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return list<int>
     *
     * @return int[]
     */
    public function getListOfInt(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return list<float>
     *
     * @return float[]
     */
    public function getListOfFloat(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return list<string>
     *
     * @return string[]
     */
    public function getListOfString(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string, int>
     *
     * @return array
     */
    public function getArrayOfStringToInt(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string,float>
     *
     * @return array
     */
    public function getArrayOfStringToFloat(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string, bool>
     *
     * @return array
     */
    public function getArrayOfStringToBool(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string, string>
     *
     * @return array
     */
    public function getArrayOfStringToString(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return int
     */
    public function getAsInt(): int
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return float
     */
    public function getAsFloat(): float
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return bool
     */
    public function getAsBool(): bool
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return string
     */
    public function getAsString(): string
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return list<int>
     *
     * @return int[]
     */
    public function getAsListOfInt(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return list<float>
     *
     * @return float[]
     */
    public function getAsListOfFloat(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return list<string>
     *
     * @return string[]
     */
    public function getAsListOfString(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string, int>
     *
     * @return array
     */
    public function getAsArrayOfStringToInt(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string, float>
     *
     * @return array
     */
    public function getAsArrayOfStringToFloat(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string, bool>
     *
     * @return array
     */
    public function getAsArrayOfStringToBool(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string, string>
     *
     * @return array
     */
    public function getAsArrayOfStringToString(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return int|null
     */
    public function findInt(): ?int
    {
        return null;
    }

    /**
     * @return float|null
     */
    public function findFloat(): ?float
    {
        return null;
    }

    /**
     * @return bool|null
     */
    public function findBool(): ?bool
    {
        return null;
    }

    /**
     * @return string|null
     */
    public function findString(): ?string
    {
        return null;
    }

    /**
     * @psalm-return list<int>
     *
     * @return int[]|null
     */
    public function findListOfInt(): ?array
    {
        return null;
    }

    /**
     * @psalm-return list<float>
     *
     * @return float[]|null
     */
    public function findListOfFloat(): ?array
    {
        return null;
    }

    /**
     * @psalm-return list<string>
     *
     * @return string[]|null
     */
    public function findListOfString(): ?array
    {
        return null;
    }

    /**
     * @psalm-return array<string, int>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToInt(): ?array
    {
        return null;
    }

    /**
     * @psalm-return array<string, bool>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToBool(): ?array
    {
        return null;
    }

    /**
     * @psalm-return array<string, string>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToString(): ?array
    {
        return null;
    }

    /**
     * @return int|null
     */
    public function findAsInt(): ?int
    {
        return null;
    }

    /**
     * @return float|null
     */
    public function findAsFloat(): ?float
    {
        return null;
    }

    /**
     * @return bool|null
     */
    public function findAsBool(): ?bool
    {
        return null;
    }

    /**
     * @return string|null
     */
    public function findAsString(): ?string
    {
        return null;
    }

    /**
     * @psalm-return list<int>|null
     *
     * @return int[]|null
     */
    public function findAsListOfInt(): ?array
    {
        return null;
    }

    /**
     * @psalm-return list<float>|null
     *
     * @return float[]|null
     */
    public function findAsListOfFloat(): ?array
    {
        return null;
    }

    /**
     * @psalm-return list<string>|null
     *
     * @return string[]|null
     */
    public function findAsListOfString(): ?array
    {
        return null;
    }

    /**
     * @psalm-return array<string, int>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToInt(): ?array
    {
        return null;
    }

    /**
     * @psalm-return array<string, float>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToFloat(): ?array
    {
        return null;
    }

    /**
     * @pslam-pure
     * @psalm-return array<string,float>|null
     * @return array|null
     */
    public function findAsArrayOfStringToFloat(): ?array
    {
        return null;
    }

    /**
     * @psalm-return array<string, bool>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToBool(): ?array
    {
        return null;
    }

    /**
     * @psalm-return array<string, string>|null
     *
     * @return array|null
     */
    public function findAsArrayOfStringToString(): ?array
    {
        return null;
    }

    /**
     * @return mixed
     */
    public function getMixed()
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return object
     */
    public function getObject(): object
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return array
     */
    public function getArray(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @psalm-return array<string, mixed>
     *
     * @return array
     */
    public function getArrayOfStringToMixed(): array
    {
        throw new MissingKeyException($this->keySequence);
    }

    /**
     * @return mixed
     */
    public function findMixed()
    {
        return null;
    }

    /**
     * @return object|null
     */
    public function findObject(): ?object
    {
        return null;
    }

    /**
     * @return array|null
     */
    public function findArray(): ?array
    {
        return null;
    }

    /**
     * @psalm-return array<string, mixed>|null
     *
     * @return array|null
     */
    public function findArrayOfStringToMixed(): ?array
    {
        return null;
    }

    /**
     * @param mixed $offset
     *
     * @return bool
     */
    public function offsetExists($offset): bool
    {
        return false;
    }

    /**
     * @param int|string $offset
     */
    public function offsetGet($offset): MessInterface
    {
        /**
         * @psalm-suppress DocblockTypeContradiction
         */
        if (!is_string($offset) && !is_int($offset)) {
            throw new UnexpectedKeyTypeException($offset, $this->keySequence);
        }

        $clonedKeySequence = $this->keySequence;
        $clonedKeySequence[] = $offset;

        return new self($clonedKeySequence);
    }

    /**
     * @param mixed $offset
     * @param mixed $value
     */
    public function offsetSet($offset, $value): void
    {
        throw new CannotModifyMessException($this->keySequence);
    }

    /**
     * @param mixed $offset
     */
    public function offsetUnset($offset): void
    {
        throw new CannotModifyMessException($this->keySequence);
    }
}


================================================
FILE: src/TypedAccessor.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\TypedAccessor;

use Zakirullin\Mess\Mess;

/**
 * @deprecated will be removed in 1.0, use Mess instead
 * @psalm-immutable
 */
final class TypedAccessor extends Mess
{
}

================================================
FILE: src/functions.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess
{
    use function array_keys;
    use function count;
    use function filter_var;
    use function is_array;
    use function is_bool;
    use function is_int;
    use function is_string;
    use function range;
    use function strtolower;
    use function trim;
    use const FILTER_VALIDATE_INT;

    /**
     * @psalm-pure
     *
     * @param mixed $value
     * @return int|null
     */
    function toInt($value): ?int
    {
        if (is_bool($value)) {
            return null;
        }

        $intValue = filter_var($value, FILTER_VALIDATE_INT);
        if ($intValue === false) {
            return null;
        }

        return $intValue;
    }

    /**
     * @psalm-pure
     *
     * @param mixed $value
     * @return float|null
     */
    function toFloat($value): ?float
    {
        if (is_bool($value)) {
            return null;
        }

        $floatValue = filter_var($value, FILTER_VALIDATE_FLOAT);
        if ($floatValue === false) {
            return null;
        }

        return $floatValue;
    }

    /**
     * @psalm-pure
     *
     * @param mixed $value
     * @return bool|null
     */
    function toBool($value): ?bool
    {
        if (is_bool($value)) {
            return $value;
        }

        $intValue = toInt($value);
        if ($intValue === 1) {
            return true;
        }
        if ($intValue === 0) {
            return false;
        }

        if (is_string($value)) {
            $stringValue = trim(strtolower($value));
            if ($stringValue === 'true') {
                return true;
            }

            if ($stringValue === 'false') {
                return false;
            }
        }

        return null;
    }

    /**
     * @psalm-pure
     *
     * @param mixed $value
     * @return string|null
     */
    function toString($value): ?string
    {
        if (is_string($value)) {
            return $value;
        }

        if (is_int($value)) {
            return (string) $value;
        }

        return null;
    }

    /**
     * @psalm-pure
     * @psalm-return list
     *
     * @param mixed    $value
     * @param callable $caster
     * @return array|null
     */
    function toListOfType($value, callable $caster): ?array
    {
        if (!isListOfMixed($value)) {
            return null;
        }

        $listOfCasted = [];
        /**
         * @psalm-suppress ImpureMethodCall
         * @psalm-suppress MixedAssignment
         */
        foreach ($value as $val) {
            /**
             * @psalm-suppress ImpureFunctionCall
             */
            $castedValue = $caster($val);
            if ($castedValue === null) {
                return null;
            }

            $listOfCasted[] = $castedValue;
        }

        return $listOfCasted;
    }

    /**
     * @psalm-pure
     * @psalm-return array<string,mixed>|null
     *
     * @param mixed    $value
     * @param pure-callable $caster
     * @return array|null
     */
    function toArrayOfStringToType($value, callable $caster): ?array
    {
        if (!isArrayOfStringToMixed($value)) {
            return null;
        }

        $arrayOfStringToCasted = [];
        /**
         * @var array $value
         * @var string $key
         * @var mixed  $val
         */
        foreach ($value as $key => $val) {
            /**
             * @var mixed
             */
            $castedValue = $caster($val);
            if ($castedValue === null) {
                return null;
            }

            /**
             * @var mixed
             */
            $arrayOfStringToCasted[$key] = $castedValue;
        }

        return $arrayOfStringToCasted;
    }

    /**
     * @psalm-pure
     *
     * @param mixed $value
     * @return bool
     */
    function isListOfMixed($value): bool
    {
        if (!is_array($value)) {
            return false;
        }

        if ($value === []) {
            return true;
        }

        /**
         * @psalm-var list
         */
        $keys = array_keys($value);

        return $keys === range(0, count($value) - 1);
    }

    /**
     * @psalm-pure
     *
     * @param mixed    $value
     * @param pure-callable $typeChecker
     * @return bool
     */
    function isListOfType($value, callable $typeChecker): bool
    {
        if (!isListOfMixed($value)) {
            return false;
        }

        /**
         * @psalm-var list $value
         * @var mixed $val
         */
        foreach ($value as $val) {
            if (!$typeChecker($val)) {
                return false;
            }
        }

        return true;
    }

    /**
     * @psalm-pure
     *
     * @param mixed $value
     * @return bool
     */
    function isArrayOfStringToMixed($value): bool
    {
        if (!is_array($value)) {
            return false;
        }

        foreach (array_keys($value) as $key) {
            if (!is_string($key)) {
                return false;
            }
        }

        return true;
    }

    /**
     * @psalm-pure
     *
     * @param mixed    $value
     * @param pure-callable $isType
     * @return bool
     */
    function isArrayOfStringToType($value, callable $isType)
    {
        if (!isArrayOfStringToMixed($value)) {
            return false;
        }

        /**
         * @psalm-var array<string,mixed> $value
         * @var mixed $val
         */
        foreach ($value as $val) {
            if (!$isType($val)) {
                return false;
            }
        }

        return true;
    }
}


================================================
FILE: tests/unit/Exception/MissingKeyExceptionTest.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Tests\Exception;

use PHPUnit\Framework\TestCase;
use Zakirullin\Mess\Exception\MissingKeyException;

/**
 * @covers \Zakirullin\Mess\Exception\MissingKeyException
 */
class MissingKeyExceptionTest extends TestCase
{

    public function testGetKeySequence_ConstructedWithKeySequence_ReturnsSameKeySequence()
    {
        $e = new MissingKeyException(['a', 'b', 'c']);

        $this->assertSame(['a', 'b', 'c'], $e->getKeySequence());
    }
}

================================================
FILE: tests/unit/Exception/UncastableValueExceptionTest.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Tests\Exception;

use PHPUnit\Framework\TestCase;
use Zakirullin\Mess\Exception\UncastableValueException;

/**
 * @covers \Zakirullin\Mess\Exception\UncastableValueException
 */
class UncastableValueExceptionTest extends TestCase
{
    public function testGetInputType_InputType_ReturnsSameInputType()
    {
        $e = new UncastableValueException('desired', '', []);

        $this->assertSame('desired', $e->getDesiredType());
    }

    public function testGetOutputType_OutputType_ReturnsSameOutputType()
    {
        $e = new UncastableValueException('', 'value', []);

        $this->assertSame('value', $e->getValue());
    }
}

================================================
FILE: tests/unit/Exception/UnexpectedKeyTypeExceptionTest.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Tests\Exception;

use PHPUnit\Framework\TestCase;
use Zakirullin\Mess\Exception\UnexpectedKeyTypeException;

class UnexpectedKeyTypeExceptionTest extends TestCase
{
    public function testGetKey_Key_ReturnsSameKey()
    {
        $e = new UnexpectedKeyTypeException('key', []);

        $this->assertSame('key', $e->getKey());
    }
}

================================================
FILE: tests/unit/Exception/UnexpectedTypeExceptionTest.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Tests\Exception;

use PHPUnit\Framework\TestCase;
use Zakirullin\Mess\Exception\UnexpectedTypeException;

/**
 * @covers \Zakirullin\Mess\Exception\UnexpectedTypeException
 */
class UnexpectedTypeExceptionTest extends TestCase
{
    public function testGetExpectedType_ExpectedType_ReturnsSameExpectedType()
    {
        $e = new UnexpectedTypeException('expected', '', []);

        $this->assertSame('expected', $e->getExpectedType());
    }

    public function testGetActualType_ActualType_ReturnsSameActualType()
    {
        $e = new UnexpectedTypeException('', 'value', []);

        $this->assertSame('value', $e->getValue());
    }
}

================================================
FILE: tests/unit/MessTest.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Tests;

use PHPUnit\Framework\TestCase;
use Zakirullin\Mess\Exception\CannotModifyMessException;
use Zakirullin\Mess\Exception\UncastableValueException;
use Zakirullin\Mess\Exception\UnexpectedKeyTypeException;
use Zakirullin\Mess\Exception\UnexpectedTypeException;
use Zakirullin\Mess\MissingMess;
use Zakirullin\Mess\Mess;
use stdClass;

/**
 * @covers \Zakirullin\Mess\Mess
 */
class MessTest extends TestCase
{
    public function testGetInt_Int_ReturnsSameInt()
    {
        $actualValue = (new Mess(1))->getInt();

        $this->assertSame(1, $actualValue);
    }

    public function testGetInt_String_ThrowsUnexpectedTypeException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess('crusoe'))->getInt();
    }

    public function testGetFloat_FloatValue_ReturnsSameFloatValue()
    {
        $actualValue = (new Mess(1.5))->getFloat();

        $this->assertSame(1.5, $actualValue);
    }

    public function testGetBool_Bool_ReturnsSameBoolValue()
    {
        $actualValue = (new Mess(true))->getBool();

        $this->assertSame(true, $actualValue);
    }

    public function testGetBool_String_ThrowsUnexpectedTypeException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess('true'))->getBool();
    }

    public function testGetString_String_ReturnsSameString()
    {
        $actualValue = (new Mess('crusoe'))->getString();

        $this->assertSame('crusoe', $actualValue);
    }

    public function testGetString_Int_ThrowsUnexpectedTypeException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess(1))->getString();
    }

    public function testGetListOfInt_ListOfInt_ReturnsSameListOfInt()
    {
        $actualValue = (new Mess([1, 5, 10]))->getListOfInt();

        $this->assertSame([1, 5, 10], $actualValue);
    }

    /**
     * @dataProvider providerNotAListOfInt
     */
    public function testGetListOfInt_NotAListOfIntGiven_ThrowsUnexpectedTypeException($notAListOfInt)
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess($notAListOfInt))->getListOfInt();
    }

    public function providerNotAListOfInt()
    {
        return  [
            'associative array' => [[1, 2 => 3]],
            'array of mixed' => [[1, 'a']],
            'int' => [1],
        ];
    }

    public function testGetListOfFloat_ListOfFloat_ReturnsSameListOfFloat()
    {
        $actualValue = (new Mess([1.2, 0.5]))->getListOfFloat();

        $this->assertSame([1.2, 0.5], $actualValue);
    }

    /**
     * @dataProvider providerNotAListOfFloat
     */
    public function testGetListOfFloat_NotAListOfFloatGiven_ThrowsUnexpectedTypeException($notAListOfFloat)
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess($notAListOfFloat))->getListOfFloat();
    }

    public function providerNotAListOfFloat()
    {
        return  [
            'associative array' => [[1.5, 2 => 3.5]],
            'array of mixed' => [[1.5, 'a']],
            'float' => [1.5],
        ];
    }

    public function testGetListOfString_ListOfString_ReturnsSameListOfString()
    {
        $actualValue = (new Mess(['a', 'b']))->getListOfString();

        $this->assertSame(['a', 'b'], $actualValue);
    }

    /**
     * @dataProvider providerNotAListOfString
     */
    public function testGetListOfString_GivenNotAListOfString_ThrowsUnexpectedTypeException($notAListOfString)
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess($notAListOfString))->getListOfString();
    }

    public function providerNotAListOfString()
    {
        return  [
            'associative array' => [['s', 2 => 's']],
            'array of mixed' => [['s', 1]],
            'string' => ['s'],
        ];
    }

    public function testGetArrayOfStringToInt_ArrayOfStringToInt_ReturnsSameValue()
    {
        $actualValue = (new Mess(['a' => 1, 'b' => 2]))->getArrayOfStringToInt();

        $this->assertSame(['a' => 1, 'b' => 2], $actualValue);
    }

    public function testGetArrayOfStringToFloat_ArrayOfStringToFloat_ReturnsSameValue()
    {
        $actualValue = (new Mess(['a' => 1.5, 'b' => 2.5]))->getArrayOfStringToFloat();

        $this->assertSame(['a' => 1.5, 'b' => 2.5], $actualValue);
    }

    public function testGetArrayOfStringToBool_ArrayOfStringToBool_ReturnsSameValue()
    {
        $actualValue = (new Mess(['a' => true, 'b' => false]))->getAsArrayOfStringToBool();

        $this->assertSame(['a' => true, 'b' => false], $actualValue);
    }

    public function testGetArrayOfStringToString_ArrayOfStringToString_ReturnsSameValue()
    {
        $actualValue = (new Mess(['a' => 'A', 'b' => 'B']))->getAsArrayOfStringToString();

        $this->assertSame(['a' => 'A', 'b' => 'B'], $actualValue);
    }

    /**
     * @dataProvider providerCanCastToIntValues
     */
    public function testGetAsInt_GivenCastableValue_ReturnsMatchingCastedValue($value, int $castedValue)
    {
        $actualValue = (new Mess($value))->getAsInt();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * Can cast to int
     */
    public function providerCanCastToIntValues()
    {
        return [
            'int' => [1, 1],
            'int in float' => [1.0, 1],
            'positive int in string' => ['1', 1],
            'signed positive int in string' => ['+1', 1],
            'negative int in string' => ['-1', -1],
            'positive zero' => ['+0', 0],
            'negative zero' => ['-0', 0],
            'int in string with trailing spaces' => [' 1 ', 1],
        ];
    }

    /**
     * @dataProvider providerCannotCastToIntValues
     */
    public function testGetAsInt_GivenUncastableValue_ThrowsUncastableValueException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->getAsInt();
    }

    /**
     * Cannot cast to int
     */
    public function providerCannotCastToIntValues()
    {
        return [
            'object' => [(object) []],
            'array' => [[]],
            'function' => [
                function () {
                },
            ],
            'boolean' => [true],
            'float' => [1.1],
            'float in string' => ['1.1'],
            'malformed int string' => ['1 25'],
            'leading zeroes' => ['001'],
        ];
    }

    /**
     * @dataProvider providerCanCastToFloatValues
     */
    public function testGetAsFloat_GivenCastableValue_ReturnsMatchingCastedValue($value, float $castedValue)
    {
        $actualValue = (new Mess($value))->getAsFloat();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * Can cast to int
     */
    public function providerCanCastToFloatValues()
    {
        return [
            'float' => [1.5, 1.5],
            'float in positive int' => [1, 1.0],
            'float in negative int' => [-1, -1.0],
            'positive int in string' => ['1', 1.0],
            'signed positive int in string' => ['+1', 1.0],
            'negative int in string' => ['-1', -1],
            'positive float in string' => ['1.5', 1.5],
            'signed positive float in string' => ['+1.5', 1.5],
            'negative float in string' => ['-1.5', -1.5],
            'positive exponent' => ['1.5E2', 150.0],
            'zero exponent' => ['1.5E0', 1.5],
            'negative exponent' => ['1E-2', 0.01],
            'positive zero' => ['+0', 0],
            'negative zero' => ['-0', 0],
            'short float in string' => ['.5', 0.5],
            'float in string with trailing spaces' => [' 1.5 ', 1.5],
            'leading zeroes' => ['001', 1.0],
        ];
    }

    /**
     * @dataProvider providerCannotCastToFloatValues
     */
    public function testGetAsFloat_GivenUncastableValue_ThrowsUncastableValueException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->getAsFloat();
    }

    /**
     * Cannot cast to int
     */
    public function providerCannotCastToFloatValues()
    {
        return [
            'object' => [(object) []],
            'array' => [[]],
            'function' => [
                function () {
                },
            ],
            'boolean' => [true],
            'malformed float string' => ['1 25'],
            'malformed exponent' => ['1E'],
        ];
    }

    /**
     * @dataProvider providerCanCastToBoolValues
     */
    public function testGetAsBool_GivenCastableValue_ReturnsMatchingCastedValue($value, bool $castedValue)
    {
        $actualValue = (new Mess($value))->getAsBool();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * Can cast to bool
     */
    public function providerCanCastToBoolValues()
    {
        return [
            'bool true' => [true, true],
            'bool false' => [false, false],
            '0' => [0, false],
            '1' => [1, true],
            '0 in string' => ['0', false],
            '1 in string' => ['1', true],
            'true in string' => ['true', true],
            'false in string' => ['false', false],
            'bool in string with trailing spaces' => [' false ', false],
        ];
    }

    /**
     * @dataProvider providerCannotCastToBoolValues
     */
    public function testGetAsBool_GivenUncastableValue_ThrowsUncastableValueException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->getAsBool();
    }

    /**
     * Cannot cast to bool
     */
    public function providerCannotCastToBoolValues()
    {
        return [
            'object' => [(object) []],
            'array' => [[]],
            'function' => [
                function () {
                },
            ],
            'float' => [1.1],
            'float in string' => ['1.1'],
        ];
    }

    /**
     * @dataProvider providerCanCastToStringValues
     */
    public function testGetAsString_GivenCastableValue_ReturnsMatchingCastedValue($value, string $castedValue)
    {
        $actualValue = (new Mess($value))->getAsString();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * Can cast to string
     */
    public function providerCanCastToStringValues()
    {
        return [
            'string' => ['crusoe', 'crusoe'],
            'int' => [1, '1'],
        ];
    }

    /**
     * @dataProvider providerCannotCastToStringValues
     */
    public function testGetAsString_GiveUncastableValue_ThrowsUncastableValueException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->getAsString();
    }

    /**
     * Cannot cast to string
     */
    public function providerCannotCastToStringValues()
    {
        return [
            'object' => [(object) []],
            'array' => [[]],
            'function' => [
                function () {
                },
            ],
            'boolean' => [true],
        ];
    }

    /**
     * @dataProvider providerCanCastToListOfIntValues
     */
    public function testGetAsListOfInt_GivenCastableValue_ReturnsMatchingCastedValue($value, array $castedValue)
    {
        $actualValue = (new Mess($value))->getAsListOfInt();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * Can cast to list of int
     */
    public function providerCanCastToListOfIntValues()
    {
        return [
            'empty list' => [[], []],
            'list of int' => [[1], [1]],
            'list of castable to int' => [['1'], [1]],
        ];
    }

    /**
     * @dataProvider providerCannotCastToListOfIntValues
     */
    public function testGetAsListOfInt_GivenUncastableValue_ThrowsUuncastableValueException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->getAsListOfInt();
    }

    /**
     * Cannot cast to list of int
     */
    public function providerCannotCastToListOfIntValues()
    {
        return [
            'not array' => [1],
            'associative array' => [[1, 2 => 3]],
            'list of uncastable values' => [['a']],
        ];
    }

    /**
     * @dataProvider providerCanCastToListOfFloatValues
     */
    public function testGetAsListOfFloat_GivenCastableValue_ReturnsMatchingCastedValue($value, array $castedValue)
    {
        $actualValue = (new Mess($value))->getAsListOfFloat();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * Can cast to list of float
     */
    public function providerCanCastToListOfFloatValues()
    {
        return [
            'empty list' => [[], []],
            'list of float' => [[1.5], [1.5]],
            'list of castable to float' => [['1.5'], [1.5]],
        ];
    }

    /**
     * @dataProvider providerCannotCastToListOfFloatValues
     */
    public function testGetAsListOfFloat_GivenUncastableValue_ThrowsUuncastableValueException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->getAsListOfFloat();
    }

    /**
     * Cannot cast to list of float
     */
    public function providerCannotCastToListOfFloatValues()
    {
        return [
            'not array' => [1.5],
            'associative array' => [[1.5, 2 => 3.5]],
            'list of uncastable values' => [['a']],
        ];
    }

    /**
     * @dataProvider providerCanCastToListOfStringValues
     */
    public function testGetAsListOfString_GivenCastableValue_ReturnsMatchingCastedValue($value, array $castedValue)
    {
        $actualValue = (new Mess($value))->getAsListOfString();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * Can cast to list of string
     */
    public function providerCanCastToListOfStringValues()
    {
        return [
            'empty list' => [[], []],
            'list of string' => [['crusoe'], ['crusoe']],
            'list of castable to strign' => [[1], ['1']],
        ];
    }

    /**
     * @dataProvider providerCannotCastToListOfStringValues
     */
    public function testGetAsListOfString_GivenUncastableValue_ThrowsUncastableValueException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->getAsListOfString();
    }

    /**
     * Cannot cast to list<string>
     */
    public function providerCannotCastToListOfStringValues()
    {
        return [
            'not array' => [1],
            'associative array' => [['a', 2 => 'b']],
            'list of uncastable values' => [[true]],
        ];
    }

    /**
     * @dataProvider providerCanCastToArrayOfStringToIntValues
     */
    public function testGetAsArrayOfStringToInt_GivenCastableValue_ReturnsMatchingCastedValue($value, array $castedValue)
    {
        $actualValue = (new Mess($value))->getAsArrayOfStringToInt();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * Can cast to array<string,int>
     */
    public function providerCanCastToArrayOfStringToIntValues()
    {
        return [
            'empty array' => [[], []],
            'array<string,int>' => [['a' => 1], ['a' => 1]],
            'array<string,castable>' => [['a' => '1'], ['a' => 1]],
        ];
    }

    /**
     * @dataProvider providerCannotCastToArrayOfStringToIntValues
     */
    public function testGetAsArrayOfStringToInt_GivenUncastableValue_ThrowsUncastableValueException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->getAsArrayOfStringToInt();
    }

    /**
     * Cannot cast to list<string>
     */
    public function providerCannotCastToArrayOfStringToIntValues()
    {
        return [
            'not array' => [1],
            'array<mixed,int>' => [[1 => 1, 'a' => 'b']],
            'array<string,uncastable>' => [[true]],
        ];
    }

    public function testFindInt_IntValue_ReturnsSameIntValue()
    {
        $actualValue = (new Mess(1))->findInt();

        $this->assertSame(1, $actualValue);
    }

    public function testFindInt_StringValue_ThrowsException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess('crusoe'))->findInt();
    }

    public function testFindInt_Null_ReturnsNull()
    {
        $actualValue = (new Mess(null))->findInt();

        $this->assertNull($actualValue);
    }

    public function testFindFloat_FloatValue_ReturnsSameFloatValue()
    {
        $actualValue = (new Mess(1.5))->findFloat();

        $this->assertSame(1.5, $actualValue);
    }

    public function testFindFloat_StringValue_ThrowsException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess('crusoe'))->findFloat();
    }

    public function testFindFloat_Null_ReturnsNull()
    {
        $actualValue = (new Mess(null))->findFloat();

        $this->assertNull($actualValue);
    }

    public function testFindBool_BoolValue_ReturnsSameBoolValue()
    {
        $actualValue = (new Mess(true))->findBool();

        $this->assertSame(true, $actualValue);
    }

    public function testFindBool_StringValue_ThrowsException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess('crusoe'))->findBool();
    }

    public function testFindBool_Null_ReturnsNull()
    {
        $actualValue = (new Mess(null))->findBool();

        $this->assertNull($actualValue);
    }

    public function testFindString_StringValue_ReturnsSameStringValue()
    {
        $actualValue = (new Mess('crusoe'))->findString();

        $this->assertSame('crusoe', $actualValue);
    }

    public function testFindString_GivenUncastableValue_ThrowsException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess(1))->findString();
    }

    public function testFindString_Null_ReturnsSameNull()
    {
        $actualValue = (new Mess(null))->findString();

        $this->assertNull($actualValue);
    }

    public function testFindListOfInt_ListOfInt_ReturnsSameListOfInt()
    {
        $actualValue = (new Mess([1, 5, 10]))->findListOfInt();

        $this->assertSame([1, 5, 10], $actualValue);
    }

    /**
     * @dataProvider providerNotAListOfInt
     */
    public function testFindListOfInt_GivenNotAListOfInt_ThrowsException($notAListOfInt)
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess($notAListOfInt))->findListOfInt();
    }

    public function testFindListOfInt_Null_ReturnsNull()
    {
        $actualValue = (new Mess(null))->findListOfInt();

        $this->assertNull($actualValue);
    }

    public function testFindListOfFloat_ListOfFloat_ReturnsSameListOfFloat()
    {
        $actualValue = (new Mess([1.5, 0.1]))->findListOfFloat();

        $this->assertSame([1.5, 0.1], $actualValue);
    }

    /**
     * @dataProvider providerNotAListOfInt
     */
    public function testFindListOfFloat_GivenNotAListOfFloat_ThrowsException($notAlistOfInt)
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess($notAlistOfInt))->findListOfFloat();
    }

    public function testFindListOfString_ListOfStringValue_ReturnsSameListOfStringValue()
    {
        $actualValue = (new Mess(['a', 'b']))->findListOfString();

        $this->assertSame(['a', 'b'], $actualValue);
    }

    /**
     * @dataProvider providerNotAListOfString
     */
    public function testFindListOfString_GivenNotAListOfInt_ThrowsException($notAListOfInt)
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess($notAListOfInt))->findListOfString();
    }

    public function testFindListOfString_Null_ReturnsNull()
    {
        $actualValue = (new Mess(null))->findListOfString();

        $this->assertNull($actualValue);
    }

    /**
     * @dataProvider providerCanCastToIntValues
     */
    public function testFindAsInt_GivenCastableValue_ReturnsMatchingCastedValue($value, int $castedValue)
    {
        $actualValue = (new Mess($value))->findAsInt();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * @dataProvider providerCannotCastToIntValues
     */
    public function testFindAsInt_GivenUncastableValue_ThrowsException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->findAsInt();
    }

    /**
     * @dataProvider providerCannotCastToFloatValues
     */
    public function testFindAsFloat_GivenUncastableValue_ThrowsException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->findAsFloat();
    }

    /**
     * @dataProvider providerCanCastToBoolValues
     */
    public function testFindAsBool_GivenCastableValue_ReturnsMatchingCastedValue($value, bool $castedValue)
    {
        $actualValue = (new Mess($value))->findAsBool();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * @dataProvider providerCannotCastToBoolValues
     */
    public function testFindAsBool_GivenUncastableValue_ThrowsException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->findAsBool();
    }

    /**
     * @dataProvider providerCanCastToStringValues
     */
    public function testFindAsString_GivenCastableValue_ReturnsMatchingCastedValue($value, string $castedValue)
    {
        $actualValue = (new Mess($value))->findAsString();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * @dataProvider providerCannotCastToStringValues
     */
    public function testFindAsString_GivenUncastableValue_ThrowsException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->findAsString();
    }

    /**
     * @dataProvider providerCanCastToListOfIntValues
     */
    public function testFindAsListOfInt_GivenCastableValue_ReturnsMatchingCastedValue($value, array $castedValue)
    {
        $actualValue = (new Mess($value))->findAsListOfInt();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * @dataProvider providerCannotCastToListOfIntValues
     */
    public function testFindAsListOfInt_GivenUncastableValue_ThrowsException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->findAsListOfInt();
    }

    /**
     * @dataProvider providerCanCastToListOfFloatValues
     */
    public function testFindAsListOfFloat_GivenCastableValue_ReturnsMatchingCastedValue($value, array $castedValue)
    {
        $actualValue = (new Mess($value))->findAsListOfFloat();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * @dataProvider providerCannotCastToListOfFloatValues
     */
    public function testFindAsListOfFloat_GivenUncastableValue_ThrowsException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->findAsListOfFloat();
    }

    /**
     * @dataProvider providerCanCastToListOfStringValues
     */
    public function testFindAsListOfString_GivenCastableValue_ReturnsMatchingCastedValue($value, array $castedValue)
    {
        $actualValue = (new Mess($value))->findAsListOfString();

        $this->assertSame($castedValue, $actualValue);
    }

    /**
     * @dataProvider providerCannotCastToListOfStringValues
     */
    public function testFindAsListOfString_GivenUncastableValue_ThrowsException($value)
    {
        $this->expectException(UncastableValueException::class);

        (new Mess($value))->findAsListOfString();
    }

    public function testGetMixed_AnyValue_ReturnsSameValue()
    {
        $actualValue = (new Mess('1'))->getMixed();

        $this->assertSame('1', $actualValue);
    }

    public function testGetObject_Object_ReturnsSameObject()
    {
        $object = new stdClass();
        $actualValue = (new Mess($object))->getObject();

        $this->assertSame($object, $actualValue);
    }

    public function testGetObject_Int_ThrowsUnexpectedTypeException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess(1))->getObject();
    }

    public function testGetArray_Array_ReturnsSameArray()
    {
        $actualValue = (new Mess([1]))->getArray();

        $this->assertSame([1], $actualValue);
    }

    public function testGetArray_Int_ThrowsUnexpectedTypeException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess(1))->getArray();
    }

    public function testFindMixed_AnyValue_ReturnsSameValue()
    {
        $actualValue = (new Mess('1'))->findMixed();

        $this->assertSame('1', $actualValue);
    }

    public function testFindObject_Object_ReturnsSameObject()
    {
        $object = new stdClass();
        $actualValue = (new Mess($object))->findObject();

        $this->assertSame($object, $actualValue);
    }

    public function testFindObject_Array_ThrowsException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess([]))->findObject();
    }

    public function testFindObject_Null_ReturnsNull()
    {
        $actualValue = (new Mess(null))->findObject();

        $this->assertNull($actualValue);
    }

    public function testFindArray_Array_ReturnsSameArray()
    {
        $actualValue = (new Mess([1]))->findArray();

        $this->assertSame([1], $actualValue);
    }

    public function testFindArray_Int_ThrowsException()
    {
        $this->expectException(UnexpectedTypeException::class);

        (new Mess(1))->findArray();
    }

    public function testFindArray_Null_ReturnsNull()
    {
        $actualValue = (new Mess(null))->findArray();

        $this->assertNull($actualValue);
    }

    public function testOffsetExists_ArrayWithExistingOffset_ReturnsTrue()
    {
        $accessor = new Mess([1]);

        $this->assertTrue(isset($accessor[0]));
    }

    public function testOffsetExists_ArrayWithNonExistingOffset_ReturnsFalse()
    {
        $accessor = new Mess([]);

        $this->assertFalse(isset($accessor[0]));
    }

    public function testOffsetExists_NonArray_ReturnsFalse()
    {
        $accessor = new Mess(1);

        $this->assertFalse(isset($accessor[0]));
    }

    public function testOffsetGet_ArrayWithExistingOffset_ReturnsTypedValueAccessor()
    {
        $accessor = new Mess([1]);

        $this->assertInstanceOf(Mess::class, $accessor[0]);
    }

    public function testOffsetGet_InnerArrayWithExistingOffset_ReturnsTypedValueAccessor()
    {
        $accessor = new Mess([0 => [0 => 1]]);

        $this->assertInstanceOf(Mess::class, $accessor[0][0]);
    }

    public function testOffsetGet_ArrayWithNonExistingOffset_ReturnsMissingValueAccessor()
    {
        $accessor = new Mess([1]);

        $this->assertInstanceOf(MissingMess::class, $accessor[1]);
    }

    public function testOffsetGet_InnerArrayWithNonExistingOffset_ReturnsMissingValueAccessor()
    {
        $accessor = new Mess([0 => [0 => 1]]);

        $this->assertInstanceOf(MissingMess::class, $accessor[0][1]);
    }

    public function testOffsetGet_String_ReturnsValueByKey()
    {
        $accessor = new Mess(['key' => 1]);

        $this->assertSame(1, $accessor['key']->getInt());
    }

    public function testOffsetGet_Int_ReturnsValueByKey()
    {
        $accessor = new Mess([0 => 1]);

        $this->assertSame(1, $accessor[0]->getInt());
    }

    public function testOffsetGet_Bool_ThrowsUnexpectedKeyTypeException()
    {
        $accessor = new Mess([0 => 1]);

        $this->expectException(UnexpectedKeyTypeException::class);

        $accessor[false];
    }

    public function testOffsetSet_Offset_ThrowsCannotModifyAccessorException()
    {
        $this->expectException(CannotModifyMessException::class);

        $accessor = new Mess([1]);
        $accessor[0] = 1;
    }

    public function testOffsetUnset_Offset_ThrowsCannotModifyAccessorException()
    {
        $this->expectException(CannotModifyMessException::class);

        $accessor = new Mess([1]);
        unset($accessor[0]);
    }
}

================================================
FILE: tests/unit/MissingMessTest.php
================================================
<?php
declare(strict_types=1);

namespace Zakirullin\Mess\Tests;

use PHPUnit\Framework\TestCase;
use Zakirullin\Mess\MissingMess;
use Zakirullin\Mess\Mess;
use Zakirullin\Mess\Exception\CannotModifyMessException;
use Zakirullin\Mess\Exception\MissingKeyException;

/**
 * @covers \Zakirullin\Mess\MissingMess
 */
class MissingMessTest extends TestCase
{
    public function testGetInt_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getInt();
    }

    public function testGetFloat_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getFloat();
    }


    public function testGetBool_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getBool();
    }

    public function testGetString_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getString();
    }

    public function testGetAsInt_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getInt();
    }

    public function testGetAsFloat_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getFloat();
    }

    public function testGetAsBool_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getBool();
    }

    public function testGetAsString_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getString();
    }

    public function testFindInt_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findInt());
    }

    public function testFindFloat_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findFloat());
    }

    public function testFindBool_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findBool());
    }

    public function testFindString_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findString());
    }

    public function testFindAsInt_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findInt());
    }

    public function testFindAsFloat_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findFloat());
    }

    public function testFindAsBool_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findBool());
    }

    public function testFindAsString_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findString());
    }

    public function testGetMixed_CorrectAccessor_ThrowsMissingKeyException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(MissingKeyException::class);

        $accessor->getMixed();
    }

    public function testFindMixed_CorrectAccessor_ReturnsNull()
    {
        $accessor = new MissingMess([]);

        $this->assertNull($accessor->findMixed());
    }

    public function testOffsetExists_CorrectAccessor_ReturnsFalse()
    {
        $accessor = new MissingMess([]);

        $this->assertFalse($accessor->offsetExists(0));
    }

    public function testOffsetGet_CorrectAccessor_ReturnsMissingValueAccessor()
    {
        $accessor = new Mess([]);

        $this->assertInstanceOf(MissingMess::class, $accessor[0]);
    }

    public function testOffsetGet_CorrectAccessorWithFluentAccess_ThrowsMissingKeyException()
    {
        $accessor = new Mess([]);
        try {
            $accessor['a']['b']['c']->getInt();
        } catch (MissingKeyException $e) {
            $this->assertSame(['a', 'b', 'c'], $e->getKeySequence());
            return;
        }

        $this->fail();
    }

    public function testOffsetSet_CorrectAccessor_ThrowsCannotModifyAccessorException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(CannotModifyMessException::class);

        $accessor[0] = 1;
    }

    public function testOffsetUnset_CorrectAccessor_ThrowsCannotModifyAccessorException()
    {
        $accessor = new MissingMess([]);

        $this->expectException(CannotModifyMessException::class);

        unset($accessor[0]);
    }
}
Download .txt
gitextract_1f2ttfmh/

├── .github/
│   └── workflows/
│       └── php.yml
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── composer.json
├── infection.json.dist
├── phpunit.xml.dist
├── psalm.xml.dist
├── src/
│   ├── Enum/
│   │   └── TypeEnum.php
│   ├── Exception/
│   │   ├── CannotModifyMessException.php
│   │   ├── MessExceptionInterface.php
│   │   ├── MissingKeyException.php
│   │   ├── UncastableValueException.php
│   │   ├── UnexpectedKeyTypeException.php
│   │   └── UnexpectedTypeException.php
│   ├── Mess.php
│   ├── MessInterface.php
│   ├── MissingMess.php
│   ├── TypedAccessor.php
│   └── functions.php
└── tests/
    └── unit/
        ├── Exception/
        │   ├── MissingKeyExceptionTest.php
        │   ├── UncastableValueExceptionTest.php
        │   ├── UnexpectedKeyTypeExceptionTest.php
        │   └── UnexpectedTypeExceptionTest.php
        ├── MessTest.php
        └── MissingMessTest.php
Download .txt
SYMBOL INDEX (354 symbols across 18 files)

FILE: src/Enum/TypeEnum.php
  class TypeEnum (line 6) | final class TypeEnum

FILE: src/Exception/CannotModifyMessException.php
  class CannotModifyMessException (line 9) | final class CannotModifyMessException extends RuntimeException implement...
    method __construct (line 24) | public function __construct(array $keySequence, Throwable $previous = ...
    method getKeySequence (line 38) | public function getKeySequence(): array

FILE: src/Exception/MessExceptionInterface.php
  type MessExceptionInterface (line 8) | interface MessExceptionInterface extends Throwable
    method getKeySequence (line 14) | public function getKeySequence(): array;

FILE: src/Exception/MissingKeyException.php
  class MissingKeyException (line 10) | final class MissingKeyException extends RuntimeException implements Mess...
    method __construct (line 24) | public function __construct(array $keySequence, Throwable $previous = ...
    method getKeySequence (line 38) | public function getKeySequence(): array
    method getAbsoluteKey (line 46) | private function getAbsoluteKey(): string

FILE: src/Exception/UncastableValueException.php
  class UncastableValueException (line 10) | final class UncastableValueException extends RuntimeException implements...
    method __construct (line 37) | public function __construct(string $desiredType, $value, array $keySeq...
    method getDesiredType (line 52) | public function getDesiredType(): string
    method getValue (line 60) | public function getValue()
    method getKeySequence (line 70) | public function getKeySequence(): array

FILE: src/Exception/UnexpectedKeyTypeException.php
  class UnexpectedKeyTypeException (line 10) | final class UnexpectedKeyTypeException extends RuntimeException implemen...
    method __construct (line 31) | public function __construct($key, array $keySequence, Throwable $previ...
    method getKey (line 45) | public function getKey()
    method getKeySequence (line 55) | public function getKeySequence(): array

FILE: src/Exception/UnexpectedTypeException.php
  class UnexpectedTypeException (line 12) | final class UnexpectedTypeException extends RuntimeException implements ...
    method __construct (line 39) | public function __construct(string $expectedType, $value, array $keySe...
    method getExpectedType (line 54) | public function getExpectedType(): string
    method getValue (line 62) | public function getValue()
    method getKeySequence (line 72) | public function getKeySequence(): array
    method getAbsoluteKey (line 80) | private function getAbsoluteKey(): string

FILE: src/Mess.php
  class Mess (line 23) | class Mess implements MessInterface
    method __construct (line 41) | public function __construct($value)
    method getInt (line 49) | public function getInt(): int
    method getFloat (line 62) | public function getFloat(): float
    method getBool (line 75) | public function getBool(): bool
    method getString (line 88) | public function getString(): string
    method getListOfInt (line 103) | public function getListOfInt(): array
    method getListOfFloat (line 118) | public function getListOfFloat(): array
    method getListOfString (line 133) | public function getListOfString(): array
    method getArrayOfStringToInt (line 148) | public function getArrayOfStringToInt(): array
    method getArrayOfStringToFloat (line 163) | public function getArrayOfStringToFloat(): array
    method getArrayOfStringToBool (line 178) | public function getArrayOfStringToBool(): array
    method getArrayOfStringToString (line 196) | public function getArrayOfStringToString(): array
    method getAsInt (line 212) | public function getAsInt(): int
    method getAsFloat (line 227) | public function getAsFloat(): float
    method getAsBool (line 242) | public function getAsBool(): bool
    method getAsString (line 254) | public function getAsString(): string
    method getAsListOfInt (line 268) | public function getAsListOfInt(): array
    method getAsListOfFloat (line 285) | public function getAsListOfFloat(): array
    method getAsListOfString (line 302) | public function getAsListOfString(): array
    method getAsArrayOfStringToInt (line 319) | public function getAsArrayOfStringToInt(): array
    method getAsArrayOfStringToFloat (line 336) | public function getAsArrayOfStringToFloat(): array
    method getAsArrayOfStringToBool (line 353) | public function getAsArrayOfStringToBool(): array
    method getAsArrayOfStringToString (line 370) | public function getAsArrayOfStringToString(): array
    method findInt (line 385) | public function findInt(): ?int
    method findFloat (line 397) | public function findFloat(): ?float
    method findBool (line 409) | public function findBool(): ?bool
    method findString (line 421) | public function findString(): ?string
    method findListOfInt (line 435) | public function findListOfInt(): ?array
    method findListOfFloat (line 449) | public function findListOfFloat(): ?array
    method findListOfString (line 463) | public function findListOfString(): ?array
    method findArrayOfStringToInt (line 477) | public function findArrayOfStringToInt(): ?array
    method findArrayOfStringToFloat (line 491) | public function findArrayOfStringToFloat(): ?array
    method findArrayOfStringToBool (line 505) | public function findArrayOfStringToBool(): ?array
    method findArrayOfStringToString (line 519) | public function findArrayOfStringToString(): ?array
    method findAsInt (line 531) | public function findAsInt(): ?int
    method findAsFloat (line 543) | public function findAsFloat(): ?float
    method findAsBool (line 555) | public function findAsBool(): ?bool
    method findAsString (line 567) | public function findAsString(): ?string
    method findAsListOfInt (line 581) | public function findAsListOfInt(): ?array
    method findAsListOfFloat (line 593) | public function findAsListOfFloat(): ?array
    method findAsListOfString (line 607) | public function findAsListOfString(): ?array
    method findAsArrayOfStringToInt (line 621) | public function findAsArrayOfStringToInt(): ?array
    method findAsArrayOfStringToFloat (line 635) | public function findAsArrayOfStringToFloat(): ?array
    method findAsArrayOfStringToBool (line 649) | public function findAsArrayOfStringToBool(): ?array
    method findAsArrayOfStringToString (line 663) | public function findAsArrayOfStringToString(): ?array
    method getMixed (line 675) | public function getMixed()
    method getObject (line 683) | public function getObject(): object
    method getArray (line 696) | public function getArray(): array
    method getArrayOfStringToMixed (line 711) | public function getArrayOfStringToMixed(): array
    method findMixed (line 724) | public function findMixed()
    method findObject (line 732) | public function findObject(): ?object
    method findArray (line 744) | public function findArray(): ?array
    method findArrayOfStringToMixed (line 758) | public function findArrayOfStringToMixed(): ?array
    method offsetGet (line 771) | public function offsetGet($offset): MessInterface
    method offsetExists (line 794) | public function offsetExists($offset): bool
    method offsetSet (line 811) | public function offsetSet($offset, $value): void
    method offsetUnset (line 819) | public function offsetUnset($offset): void
    method setKeySequence (line 830) | private function setKeySequence(array $keySequence): self
    method assertType (line 841) | private function assertType(bool $isExpected, string $expectedType): void
    method assertCastable (line 852) | private function assertCastable(bool $isCastable, string $desiredType)...
    method getByOffset (line 863) | private function getByOffset($offset)

FILE: src/MessInterface.php
  type MessInterface (line 11) | interface MessInterface extends ArrayAccess
    method getInt (line 16) | public function getInt(): int;
    method getFloat (line 21) | public function getFloat(): float;
    method getBool (line 26) | public function getBool(): bool;
    method getString (line 31) | public function getString(): string;
    method getListOfInt (line 38) | public function getListOfInt(): array;
    method getListOfFloat (line 45) | public function getListOfFloat(): array;
    method getListOfString (line 52) | public function getListOfString(): array;
    method getArrayOfStringToInt (line 59) | public function getArrayOfStringToInt(): array;
    method getArrayOfStringToFloat (line 66) | public function getArrayOfStringToFloat(): array;
    method getArrayOfStringToBool (line 73) | public function getArrayOfStringToBool(): array;
    method getArrayOfStringToString (line 80) | public function getArrayOfStringToString(): array;
    method getAsInt (line 85) | public function getAsInt(): int;
    method getAsFloat (line 90) | public function getAsFloat(): float;
    method getAsBool (line 95) | public function getAsBool(): bool;
    method getAsString (line 100) | public function getAsString(): string;
    method getAsListOfInt (line 107) | public function getAsListOfInt(): array;
    method getAsListOfFloat (line 114) | public function getAsListOfFloat(): array;
    method getAsListOfString (line 121) | public function getAsListOfString(): array;
    method getAsArrayOfStringToInt (line 128) | public function getAsArrayOfStringToInt(): array;
    method getAsArrayOfStringToFloat (line 135) | public function getAsArrayOfStringToFloat(): array;
    method getAsArrayOfStringToBool (line 142) | public function getAsArrayOfStringToBool(): array;
    method getAsArrayOfStringToString (line 149) | public function getAsArrayOfStringToString(): array;
    method findInt (line 154) | public function findInt(): ?int;
    method findFloat (line 159) | public function findFloat(): ?float;
    method findBool (line 164) | public function findBool(): ?bool;
    method findString (line 169) | public function findString(): ?string;
    method findListOfInt (line 176) | public function findListOfInt(): ?array;
    method findListOfFloat (line 183) | public function findListOfFloat(): ?array;
    method findListOfString (line 190) | public function findListOfString(): ?array;
    method findArrayOfStringToInt (line 197) | public function findArrayOfStringToInt(): ?array;
    method findArrayOfStringToFloat (line 204) | public function findArrayOfStringToFloat(): ?array;
    method findArrayOfStringToBool (line 211) | public function findArrayOfStringToBool(): ?array;
    method findArrayOfStringToString (line 218) | public function findArrayOfStringToString(): ?array;
    method findAsInt (line 223) | public function findAsInt(): ?int;
    method findAsFloat (line 228) | public function findAsFloat(): ?float;
    method findAsBool (line 233) | public function findAsBool(): ?bool;
    method findAsString (line 238) | public function findAsString(): ?string;
    method findAsListOfInt (line 245) | public function findAsListOfInt(): ?array;
    method findAsListOfFloat (line 252) | public function findAsListOfFloat(): ?array;
    method findAsListOfString (line 259) | public function findAsListOfString(): ?array;
    method findAsArrayOfStringToInt (line 266) | public function findAsArrayOfStringToInt(): ?array;
    method findAsArrayOfStringToFloat (line 273) | public function findAsArrayOfStringToFloat(): ?array;
    method findAsArrayOfStringToBool (line 280) | public function findAsArrayOfStringToBool(): ?array;
    method findAsArrayOfStringToString (line 287) | public function findAsArrayOfStringToString(): ?array;
    method getMixed (line 292) | public function getMixed();
    method getObject (line 297) | public function getObject(): object;
    method getArray (line 302) | public function getArray(): array;
    method getArrayOfStringToMixed (line 309) | public function getArrayOfStringToMixed(): array;
    method findMixed (line 314) | public function findMixed();
    method findObject (line 319) | public function findObject(): ?object;
    method findArray (line 324) | public function findArray(): ?array;
    method findArrayOfStringToMixed (line 331) | public function findArrayOfStringToMixed(): ?array;
    method offsetGet (line 337) | public function offsetGet($offset): MessInterface;

FILE: src/MissingMess.php
  class MissingMess (line 15) | final class MissingMess implements MessInterface
    method __construct (line 30) | public function __construct(array $keySequence)
    method getInt (line 38) | public function getInt(): int
    method getFloat (line 46) | public function getFloat(): float
    method getBool (line 54) | public function getBool(): bool
    method getString (line 62) | public function getString(): string
    method getListOfInt (line 72) | public function getListOfInt(): array
    method getListOfFloat (line 82) | public function getListOfFloat(): array
    method getListOfString (line 92) | public function getListOfString(): array
    method getArrayOfStringToInt (line 102) | public function getArrayOfStringToInt(): array
    method getArrayOfStringToFloat (line 112) | public function getArrayOfStringToFloat(): array
    method getArrayOfStringToBool (line 122) | public function getArrayOfStringToBool(): array
    method getArrayOfStringToString (line 132) | public function getArrayOfStringToString(): array
    method getAsInt (line 140) | public function getAsInt(): int
    method getAsFloat (line 148) | public function getAsFloat(): float
    method getAsBool (line 156) | public function getAsBool(): bool
    method getAsString (line 164) | public function getAsString(): string
    method getAsListOfInt (line 174) | public function getAsListOfInt(): array
    method getAsListOfFloat (line 184) | public function getAsListOfFloat(): array
    method getAsListOfString (line 194) | public function getAsListOfString(): array
    method getAsArrayOfStringToInt (line 204) | public function getAsArrayOfStringToInt(): array
    method getAsArrayOfStringToFloat (line 214) | public function getAsArrayOfStringToFloat(): array
    method getAsArrayOfStringToBool (line 224) | public function getAsArrayOfStringToBool(): array
    method getAsArrayOfStringToString (line 234) | public function getAsArrayOfStringToString(): array
    method findInt (line 242) | public function findInt(): ?int
    method findFloat (line 250) | public function findFloat(): ?float
    method findBool (line 258) | public function findBool(): ?bool
    method findString (line 266) | public function findString(): ?string
    method findListOfInt (line 276) | public function findListOfInt(): ?array
    method findListOfFloat (line 286) | public function findListOfFloat(): ?array
    method findListOfString (line 296) | public function findListOfString(): ?array
    method findArrayOfStringToInt (line 306) | public function findArrayOfStringToInt(): ?array
    method findArrayOfStringToBool (line 316) | public function findArrayOfStringToBool(): ?array
    method findArrayOfStringToString (line 326) | public function findArrayOfStringToString(): ?array
    method findAsInt (line 334) | public function findAsInt(): ?int
    method findAsFloat (line 342) | public function findAsFloat(): ?float
    method findAsBool (line 350) | public function findAsBool(): ?bool
    method findAsString (line 358) | public function findAsString(): ?string
    method findAsListOfInt (line 368) | public function findAsListOfInt(): ?array
    method findAsListOfFloat (line 378) | public function findAsListOfFloat(): ?array
    method findAsListOfString (line 388) | public function findAsListOfString(): ?array
    method findAsArrayOfStringToInt (line 398) | public function findAsArrayOfStringToInt(): ?array
    method findArrayOfStringToFloat (line 408) | public function findArrayOfStringToFloat(): ?array
    method findAsArrayOfStringToFloat (line 418) | public function findAsArrayOfStringToFloat(): ?array
    method findAsArrayOfStringToBool (line 428) | public function findAsArrayOfStringToBool(): ?array
    method findAsArrayOfStringToString (line 438) | public function findAsArrayOfStringToString(): ?array
    method getMixed (line 446) | public function getMixed()
    method getObject (line 454) | public function getObject(): object
    method getArray (line 462) | public function getArray(): array
    method getArrayOfStringToMixed (line 472) | public function getArrayOfStringToMixed(): array
    method findMixed (line 480) | public function findMixed()
    method findObject (line 488) | public function findObject(): ?object
    method findArray (line 496) | public function findArray(): ?array
    method findArrayOfStringToMixed (line 506) | public function findArrayOfStringToMixed(): ?array
    method offsetExists (line 516) | public function offsetExists($offset): bool
    method offsetGet (line 524) | public function offsetGet($offset): MessInterface
    method offsetSet (line 543) | public function offsetSet($offset, $value): void
    method offsetUnset (line 551) | public function offsetUnset($offset): void

FILE: src/TypedAccessor.php
  class TypedAccessor (line 12) | final class TypedAccessor extends Mess

FILE: src/functions.php
  function toInt (line 24) | function toInt($value): ?int
  function toFloat (line 44) | function toFloat($value): ?float
  function toBool (line 64) | function toBool($value): ?bool
  function toString (line 98) | function toString($value): ?string
  function toListOfType (line 119) | function toListOfType($value, callable $caster): ?array
  function toArrayOfStringToType (line 153) | function toArrayOfStringToType($value, callable $caster): ?array
  function isListOfMixed (line 189) | function isListOfMixed($value): bool
  function isListOfType (line 214) | function isListOfType($value, callable $typeChecker): bool
  function isArrayOfStringToMixed (line 239) | function isArrayOfStringToMixed($value): bool
  function isArrayOfStringToType (line 261) | function isArrayOfStringToType($value, callable $isType)

FILE: tests/unit/Exception/MissingKeyExceptionTest.php
  class MissingKeyExceptionTest (line 12) | class MissingKeyExceptionTest extends TestCase
    method testGetKeySequence_ConstructedWithKeySequence_ReturnsSameKeySequence (line 15) | public function testGetKeySequence_ConstructedWithKeySequence_ReturnsS...

FILE: tests/unit/Exception/UncastableValueExceptionTest.php
  class UncastableValueExceptionTest (line 12) | class UncastableValueExceptionTest extends TestCase
    method testGetInputType_InputType_ReturnsSameInputType (line 14) | public function testGetInputType_InputType_ReturnsSameInputType()
    method testGetOutputType_OutputType_ReturnsSameOutputType (line 21) | public function testGetOutputType_OutputType_ReturnsSameOutputType()

FILE: tests/unit/Exception/UnexpectedKeyTypeExceptionTest.php
  class UnexpectedKeyTypeExceptionTest (line 9) | class UnexpectedKeyTypeExceptionTest extends TestCase
    method testGetKey_Key_ReturnsSameKey (line 11) | public function testGetKey_Key_ReturnsSameKey()

FILE: tests/unit/Exception/UnexpectedTypeExceptionTest.php
  class UnexpectedTypeExceptionTest (line 12) | class UnexpectedTypeExceptionTest extends TestCase
    method testGetExpectedType_ExpectedType_ReturnsSameExpectedType (line 14) | public function testGetExpectedType_ExpectedType_ReturnsSameExpectedTy...
    method testGetActualType_ActualType_ReturnsSameActualType (line 21) | public function testGetActualType_ActualType_ReturnsSameActualType()

FILE: tests/unit/MessTest.php
  class MessTest (line 18) | class MessTest extends TestCase
    method testGetInt_Int_ReturnsSameInt (line 20) | public function testGetInt_Int_ReturnsSameInt()
    method testGetInt_String_ThrowsUnexpectedTypeException (line 27) | public function testGetInt_String_ThrowsUnexpectedTypeException()
    method testGetFloat_FloatValue_ReturnsSameFloatValue (line 34) | public function testGetFloat_FloatValue_ReturnsSameFloatValue()
    method testGetBool_Bool_ReturnsSameBoolValue (line 41) | public function testGetBool_Bool_ReturnsSameBoolValue()
    method testGetBool_String_ThrowsUnexpectedTypeException (line 48) | public function testGetBool_String_ThrowsUnexpectedTypeException()
    method testGetString_String_ReturnsSameString (line 55) | public function testGetString_String_ReturnsSameString()
    method testGetString_Int_ThrowsUnexpectedTypeException (line 62) | public function testGetString_Int_ThrowsUnexpectedTypeException()
    method testGetListOfInt_ListOfInt_ReturnsSameListOfInt (line 69) | public function testGetListOfInt_ListOfInt_ReturnsSameListOfInt()
    method testGetListOfInt_NotAListOfIntGiven_ThrowsUnexpectedTypeException (line 79) | public function testGetListOfInt_NotAListOfIntGiven_ThrowsUnexpectedTy...
    method providerNotAListOfInt (line 86) | public function providerNotAListOfInt()
    method testGetListOfFloat_ListOfFloat_ReturnsSameListOfFloat (line 95) | public function testGetListOfFloat_ListOfFloat_ReturnsSameListOfFloat()
    method testGetListOfFloat_NotAListOfFloatGiven_ThrowsUnexpectedTypeException (line 105) | public function testGetListOfFloat_NotAListOfFloatGiven_ThrowsUnexpect...
    method providerNotAListOfFloat (line 112) | public function providerNotAListOfFloat()
    method testGetListOfString_ListOfString_ReturnsSameListOfString (line 121) | public function testGetListOfString_ListOfString_ReturnsSameListOfStri...
    method testGetListOfString_GivenNotAListOfString_ThrowsUnexpectedTypeException (line 131) | public function testGetListOfString_GivenNotAListOfString_ThrowsUnexpe...
    method providerNotAListOfString (line 138) | public function providerNotAListOfString()
    method testGetArrayOfStringToInt_ArrayOfStringToInt_ReturnsSameValue (line 147) | public function testGetArrayOfStringToInt_ArrayOfStringToInt_ReturnsSa...
    method testGetArrayOfStringToFloat_ArrayOfStringToFloat_ReturnsSameValue (line 154) | public function testGetArrayOfStringToFloat_ArrayOfStringToFloat_Retur...
    method testGetArrayOfStringToBool_ArrayOfStringToBool_ReturnsSameValue (line 161) | public function testGetArrayOfStringToBool_ArrayOfStringToBool_Returns...
    method testGetArrayOfStringToString_ArrayOfStringToString_ReturnsSameValue (line 168) | public function testGetArrayOfStringToString_ArrayOfStringToString_Ret...
    method testGetAsInt_GivenCastableValue_ReturnsMatchingCastedValue (line 178) | public function testGetAsInt_GivenCastableValue_ReturnsMatchingCastedV...
    method providerCanCastToIntValues (line 188) | public function providerCanCastToIntValues()
    method testGetAsInt_GivenUncastableValue_ThrowsUncastableValueException (line 205) | public function testGetAsInt_GivenUncastableValue_ThrowsUncastableValu...
    method providerCannotCastToIntValues (line 215) | public function providerCannotCastToIntValues()
    method testGetAsFloat_GivenCastableValue_ReturnsMatchingCastedValue (line 235) | public function testGetAsFloat_GivenCastableValue_ReturnsMatchingCaste...
    method providerCanCastToFloatValues (line 245) | public function providerCanCastToFloatValues()
    method testGetAsFloat_GivenUncastableValue_ThrowsUncastableValueException (line 271) | public function testGetAsFloat_GivenUncastableValue_ThrowsUncastableVa...
    method providerCannotCastToFloatValues (line 281) | public function providerCannotCastToFloatValues()
    method testGetAsBool_GivenCastableValue_ReturnsMatchingCastedValue (line 299) | public function testGetAsBool_GivenCastableValue_ReturnsMatchingCasted...
    method providerCanCastToBoolValues (line 309) | public function providerCanCastToBoolValues()
    method testGetAsBool_GivenUncastableValue_ThrowsUncastableValueException (line 327) | public function testGetAsBool_GivenUncastableValue_ThrowsUncastableVal...
    method providerCannotCastToBoolValues (line 337) | public function providerCannotCastToBoolValues()
    method testGetAsString_GivenCastableValue_ReturnsMatchingCastedValue (line 354) | public function testGetAsString_GivenCastableValue_ReturnsMatchingCast...
    method providerCanCastToStringValues (line 364) | public function providerCanCastToStringValues()
    method testGetAsString_GiveUncastableValue_ThrowsUncastableValueException (line 375) | public function testGetAsString_GiveUncastableValue_ThrowsUncastableVa...
    method providerCannotCastToStringValues (line 385) | public function providerCannotCastToStringValues()
    method testGetAsListOfInt_GivenCastableValue_ReturnsMatchingCastedValue (line 401) | public function testGetAsListOfInt_GivenCastableValue_ReturnsMatchingC...
    method providerCanCastToListOfIntValues (line 411) | public function providerCanCastToListOfIntValues()
    method testGetAsListOfInt_GivenUncastableValue_ThrowsUuncastableValueException (line 423) | public function testGetAsListOfInt_GivenUncastableValue_ThrowsUuncasta...
    method providerCannotCastToListOfIntValues (line 433) | public function providerCannotCastToListOfIntValues()
    method testGetAsListOfFloat_GivenCastableValue_ReturnsMatchingCastedValue (line 445) | public function testGetAsListOfFloat_GivenCastableValue_ReturnsMatchin...
    method providerCanCastToListOfFloatValues (line 455) | public function providerCanCastToListOfFloatValues()
    method testGetAsListOfFloat_GivenUncastableValue_ThrowsUuncastableValueException (line 467) | public function testGetAsListOfFloat_GivenUncastableValue_ThrowsUuncas...
    method providerCannotCastToListOfFloatValues (line 477) | public function providerCannotCastToListOfFloatValues()
    method testGetAsListOfString_GivenCastableValue_ReturnsMatchingCastedValue (line 489) | public function testGetAsListOfString_GivenCastableValue_ReturnsMatchi...
    method providerCanCastToListOfStringValues (line 499) | public function providerCanCastToListOfStringValues()
    method testGetAsListOfString_GivenUncastableValue_ThrowsUncastableValueException (line 511) | public function testGetAsListOfString_GivenUncastableValue_ThrowsUncas...
    method providerCannotCastToListOfStringValues (line 521) | public function providerCannotCastToListOfStringValues()
    method testGetAsArrayOfStringToInt_GivenCastableValue_ReturnsMatchingCastedValue (line 533) | public function testGetAsArrayOfStringToInt_GivenCastableValue_Returns...
    method providerCanCastToArrayOfStringToIntValues (line 543) | public function providerCanCastToArrayOfStringToIntValues()
    method testGetAsArrayOfStringToInt_GivenUncastableValue_ThrowsUncastableValueException (line 555) | public function testGetAsArrayOfStringToInt_GivenUncastableValue_Throw...
    method providerCannotCastToArrayOfStringToIntValues (line 565) | public function providerCannotCastToArrayOfStringToIntValues()
    method testFindInt_IntValue_ReturnsSameIntValue (line 574) | public function testFindInt_IntValue_ReturnsSameIntValue()
    method testFindInt_StringValue_ThrowsException (line 581) | public function testFindInt_StringValue_ThrowsException()
    method testFindInt_Null_ReturnsNull (line 588) | public function testFindInt_Null_ReturnsNull()
    method testFindFloat_FloatValue_ReturnsSameFloatValue (line 595) | public function testFindFloat_FloatValue_ReturnsSameFloatValue()
    method testFindFloat_StringValue_ThrowsException (line 602) | public function testFindFloat_StringValue_ThrowsException()
    method testFindFloat_Null_ReturnsNull (line 609) | public function testFindFloat_Null_ReturnsNull()
    method testFindBool_BoolValue_ReturnsSameBoolValue (line 616) | public function testFindBool_BoolValue_ReturnsSameBoolValue()
    method testFindBool_StringValue_ThrowsException (line 623) | public function testFindBool_StringValue_ThrowsException()
    method testFindBool_Null_ReturnsNull (line 630) | public function testFindBool_Null_ReturnsNull()
    method testFindString_StringValue_ReturnsSameStringValue (line 637) | public function testFindString_StringValue_ReturnsSameStringValue()
    method testFindString_GivenUncastableValue_ThrowsException (line 644) | public function testFindString_GivenUncastableValue_ThrowsException()
    method testFindString_Null_ReturnsSameNull (line 651) | public function testFindString_Null_ReturnsSameNull()
    method testFindListOfInt_ListOfInt_ReturnsSameListOfInt (line 658) | public function testFindListOfInt_ListOfInt_ReturnsSameListOfInt()
    method testFindListOfInt_GivenNotAListOfInt_ThrowsException (line 668) | public function testFindListOfInt_GivenNotAListOfInt_ThrowsException($...
    method testFindListOfInt_Null_ReturnsNull (line 675) | public function testFindListOfInt_Null_ReturnsNull()
    method testFindListOfFloat_ListOfFloat_ReturnsSameListOfFloat (line 682) | public function testFindListOfFloat_ListOfFloat_ReturnsSameListOfFloat()
    method testFindListOfFloat_GivenNotAListOfFloat_ThrowsException (line 692) | public function testFindListOfFloat_GivenNotAListOfFloat_ThrowsExcepti...
    method testFindListOfString_ListOfStringValue_ReturnsSameListOfStringValue (line 699) | public function testFindListOfString_ListOfStringValue_ReturnsSameList...
    method testFindListOfString_GivenNotAListOfInt_ThrowsException (line 709) | public function testFindListOfString_GivenNotAListOfInt_ThrowsExceptio...
    method testFindListOfString_Null_ReturnsNull (line 716) | public function testFindListOfString_Null_ReturnsNull()
    method testFindAsInt_GivenCastableValue_ReturnsMatchingCastedValue (line 726) | public function testFindAsInt_GivenCastableValue_ReturnsMatchingCasted...
    method testFindAsInt_GivenUncastableValue_ThrowsException (line 736) | public function testFindAsInt_GivenUncastableValue_ThrowsException($va...
    method testFindAsFloat_GivenUncastableValue_ThrowsException (line 746) | public function testFindAsFloat_GivenUncastableValue_ThrowsException($...
    method testFindAsBool_GivenCastableValue_ReturnsMatchingCastedValue (line 756) | public function testFindAsBool_GivenCastableValue_ReturnsMatchingCaste...
    method testFindAsBool_GivenUncastableValue_ThrowsException (line 766) | public function testFindAsBool_GivenUncastableValue_ThrowsException($v...
    method testFindAsString_GivenCastableValue_ReturnsMatchingCastedValue (line 776) | public function testFindAsString_GivenCastableValue_ReturnsMatchingCas...
    method testFindAsString_GivenUncastableValue_ThrowsException (line 786) | public function testFindAsString_GivenUncastableValue_ThrowsException(...
    method testFindAsListOfInt_GivenCastableValue_ReturnsMatchingCastedValue (line 796) | public function testFindAsListOfInt_GivenCastableValue_ReturnsMatching...
    method testFindAsListOfInt_GivenUncastableValue_ThrowsException (line 806) | public function testFindAsListOfInt_GivenUncastableValue_ThrowsExcepti...
    method testFindAsListOfFloat_GivenCastableValue_ReturnsMatchingCastedValue (line 816) | public function testFindAsListOfFloat_GivenCastableValue_ReturnsMatchi...
    method testFindAsListOfFloat_GivenUncastableValue_ThrowsException (line 826) | public function testFindAsListOfFloat_GivenUncastableValue_ThrowsExcep...
    method testFindAsListOfString_GivenCastableValue_ReturnsMatchingCastedValue (line 836) | public function testFindAsListOfString_GivenCastableValue_ReturnsMatch...
    method testFindAsListOfString_GivenUncastableValue_ThrowsException (line 846) | public function testFindAsListOfString_GivenUncastableValue_ThrowsExce...
    method testGetMixed_AnyValue_ReturnsSameValue (line 853) | public function testGetMixed_AnyValue_ReturnsSameValue()
    method testGetObject_Object_ReturnsSameObject (line 860) | public function testGetObject_Object_ReturnsSameObject()
    method testGetObject_Int_ThrowsUnexpectedTypeException (line 868) | public function testGetObject_Int_ThrowsUnexpectedTypeException()
    method testGetArray_Array_ReturnsSameArray (line 875) | public function testGetArray_Array_ReturnsSameArray()
    method testGetArray_Int_ThrowsUnexpectedTypeException (line 882) | public function testGetArray_Int_ThrowsUnexpectedTypeException()
    method testFindMixed_AnyValue_ReturnsSameValue (line 889) | public function testFindMixed_AnyValue_ReturnsSameValue()
    method testFindObject_Object_ReturnsSameObject (line 896) | public function testFindObject_Object_ReturnsSameObject()
    method testFindObject_Array_ThrowsException (line 904) | public function testFindObject_Array_ThrowsException()
    method testFindObject_Null_ReturnsNull (line 911) | public function testFindObject_Null_ReturnsNull()
    method testFindArray_Array_ReturnsSameArray (line 918) | public function testFindArray_Array_ReturnsSameArray()
    method testFindArray_Int_ThrowsException (line 925) | public function testFindArray_Int_ThrowsException()
    method testFindArray_Null_ReturnsNull (line 932) | public function testFindArray_Null_ReturnsNull()
    method testOffsetExists_ArrayWithExistingOffset_ReturnsTrue (line 939) | public function testOffsetExists_ArrayWithExistingOffset_ReturnsTrue()
    method testOffsetExists_ArrayWithNonExistingOffset_ReturnsFalse (line 946) | public function testOffsetExists_ArrayWithNonExistingOffset_ReturnsFal...
    method testOffsetExists_NonArray_ReturnsFalse (line 953) | public function testOffsetExists_NonArray_ReturnsFalse()
    method testOffsetGet_ArrayWithExistingOffset_ReturnsTypedValueAccessor (line 960) | public function testOffsetGet_ArrayWithExistingOffset_ReturnsTypedValu...
    method testOffsetGet_InnerArrayWithExistingOffset_ReturnsTypedValueAccessor (line 967) | public function testOffsetGet_InnerArrayWithExistingOffset_ReturnsType...
    method testOffsetGet_ArrayWithNonExistingOffset_ReturnsMissingValueAccessor (line 974) | public function testOffsetGet_ArrayWithNonExistingOffset_ReturnsMissin...
    method testOffsetGet_InnerArrayWithNonExistingOffset_ReturnsMissingValueAccessor (line 981) | public function testOffsetGet_InnerArrayWithNonExistingOffset_ReturnsM...
    method testOffsetGet_String_ReturnsValueByKey (line 988) | public function testOffsetGet_String_ReturnsValueByKey()
    method testOffsetGet_Int_ReturnsValueByKey (line 995) | public function testOffsetGet_Int_ReturnsValueByKey()
    method testOffsetGet_Bool_ThrowsUnexpectedKeyTypeException (line 1002) | public function testOffsetGet_Bool_ThrowsUnexpectedKeyTypeException()
    method testOffsetSet_Offset_ThrowsCannotModifyAccessorException (line 1011) | public function testOffsetSet_Offset_ThrowsCannotModifyAccessorExcepti...
    method testOffsetUnset_Offset_ThrowsCannotModifyAccessorException (line 1019) | public function testOffsetUnset_Offset_ThrowsCannotModifyAccessorExcep...

FILE: tests/unit/MissingMessTest.php
  class MissingMessTest (line 15) | class MissingMessTest extends TestCase
    method testGetInt_CorrectAccessor_ThrowsMissingKeyException (line 17) | public function testGetInt_CorrectAccessor_ThrowsMissingKeyException()
    method testGetFloat_CorrectAccessor_ThrowsMissingKeyException (line 26) | public function testGetFloat_CorrectAccessor_ThrowsMissingKeyException()
    method testGetBool_CorrectAccessor_ThrowsMissingKeyException (line 36) | public function testGetBool_CorrectAccessor_ThrowsMissingKeyException()
    method testGetString_CorrectAccessor_ThrowsMissingKeyException (line 45) | public function testGetString_CorrectAccessor_ThrowsMissingKeyException()
    method testGetAsInt_CorrectAccessor_ThrowsMissingKeyException (line 54) | public function testGetAsInt_CorrectAccessor_ThrowsMissingKeyException()
    method testGetAsFloat_CorrectAccessor_ThrowsMissingKeyException (line 63) | public function testGetAsFloat_CorrectAccessor_ThrowsMissingKeyExcepti...
    method testGetAsBool_CorrectAccessor_ThrowsMissingKeyException (line 72) | public function testGetAsBool_CorrectAccessor_ThrowsMissingKeyException()
    method testGetAsString_CorrectAccessor_ThrowsMissingKeyException (line 81) | public function testGetAsString_CorrectAccessor_ThrowsMissingKeyExcept...
    method testFindInt_CorrectAccessor_ReturnsNull (line 90) | public function testFindInt_CorrectAccessor_ReturnsNull()
    method testFindFloat_CorrectAccessor_ReturnsNull (line 97) | public function testFindFloat_CorrectAccessor_ReturnsNull()
    method testFindBool_CorrectAccessor_ReturnsNull (line 104) | public function testFindBool_CorrectAccessor_ReturnsNull()
    method testFindString_CorrectAccessor_ReturnsNull (line 111) | public function testFindString_CorrectAccessor_ReturnsNull()
    method testFindAsInt_CorrectAccessor_ReturnsNull (line 118) | public function testFindAsInt_CorrectAccessor_ReturnsNull()
    method testFindAsFloat_CorrectAccessor_ReturnsNull (line 125) | public function testFindAsFloat_CorrectAccessor_ReturnsNull()
    method testFindAsBool_CorrectAccessor_ReturnsNull (line 132) | public function testFindAsBool_CorrectAccessor_ReturnsNull()
    method testFindAsString_CorrectAccessor_ReturnsNull (line 139) | public function testFindAsString_CorrectAccessor_ReturnsNull()
    method testGetMixed_CorrectAccessor_ThrowsMissingKeyException (line 146) | public function testGetMixed_CorrectAccessor_ThrowsMissingKeyException()
    method testFindMixed_CorrectAccessor_ReturnsNull (line 155) | public function testFindMixed_CorrectAccessor_ReturnsNull()
    method testOffsetExists_CorrectAccessor_ReturnsFalse (line 162) | public function testOffsetExists_CorrectAccessor_ReturnsFalse()
    method testOffsetGet_CorrectAccessor_ReturnsMissingValueAccessor (line 169) | public function testOffsetGet_CorrectAccessor_ReturnsMissingValueAcces...
    method testOffsetGet_CorrectAccessorWithFluentAccess_ThrowsMissingKeyException (line 176) | public function testOffsetGet_CorrectAccessorWithFluentAccess_ThrowsMi...
    method testOffsetSet_CorrectAccessor_ThrowsCannotModifyAccessorException (line 189) | public function testOffsetSet_CorrectAccessor_ThrowsCannotModifyAccess...
    method testOffsetUnset_CorrectAccessor_ThrowsCannotModifyAccessorException (line 198) | public function testOffsetUnset_CorrectAccessor_ThrowsCannotModifyAcce...
Condensed preview — 28 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (101K chars).
[
  {
    "path": ".github/workflows/php.yml",
    "chars": 875,
    "preview": "name: GitHub Build\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\npermissions:\n  co"
  },
  {
    "path": ".gitignore",
    "chars": 93,
    "preview": "/vendor\n/build\n/test-reports\ncomposer.lock\nphpunit.xml\npsalm.xml\n.phpunit.result.cache\n.idea\n"
  },
  {
    "path": ".travis.yml",
    "chars": 187,
    "preview": "language: php\nsudo: false\n\nphp:\n  - 8.0\n\nbefore_script:\n  - composer self-update\n  - composer install -n\n\nscript:\n  - co"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 1993,
    "preview": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changel"
  },
  {
    "path": "LICENSE",
    "chars": 1082,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2018 Artem Zakirullin\n\nPermission is hereby granted, free of charge, to any person "
  },
  {
    "path": "README.md",
    "chars": 3873,
    "preview": "## Mess\n\n![GitHub Build Status](https://github.com/zakirullin/mess/actions/workflows/php.yml/badge.svg)\n![Psalm coverage"
  },
  {
    "path": "composer.json",
    "chars": 1222,
    "preview": "{\n  \"name\": \"zakirullin/mess\",\n  \"type\": \"library\",\n  \"description\": \"Convenient array-related routine & better type cas"
  },
  {
    "path": "infection.json.dist",
    "chars": 290,
    "preview": "{\n  \"timeout\": 10,\n  \"source\": {\n    \"directories\": [\n      \"src\"\n    ]\n  },\n  \"logs\": {\n    \"text\": \"build/log/infectio"
  },
  {
    "path": "phpunit.xml.dist",
    "chars": 740,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit\n        colors=\"true\"\n        forceCoversAnnotation=\"true\"\n        defau"
  },
  {
    "path": "psalm.xml.dist",
    "chars": 631,
    "preview": "<?xml version=\"1.0\"?>\n<psalm\n    errorLevel=\"1\"\n    resolveFromConfigFile=\"true\"\n    xmlns:xsi=\"http://www.w3.org/2001/X"
  },
  {
    "path": "src/Enum/TypeEnum.php",
    "chars": 766,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Enum;\n\nfinal class TypeEnum\n{\n    public const INT = 'int';\n  "
  },
  {
    "path": "src/Exception/CannotModifyMessException.php",
    "chars": 881,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Exception;\n\nuse RuntimeException;\nuse Throwable;\n\nfinal class "
  },
  {
    "path": "src/Exception/MessExceptionInterface.php",
    "chars": 262,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Exception;\n\nuse Throwable;\n\ninterface MessExceptionInterface e"
  },
  {
    "path": "src/Exception/MissingKeyException.php",
    "chars": 1049,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Exception;\n\nuse RuntimeException;\nuse Throwable;\nuse function "
  },
  {
    "path": "src/Exception/UncastableValueException.php",
    "chars": 1512,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Exception;\n\nuse RuntimeException;\nuse Throwable;\nuse function "
  },
  {
    "path": "src/Exception/UnexpectedKeyTypeException.php",
    "chars": 1209,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Exception;\n\nuse RuntimeException;\nuse Throwable;\nuse function "
  },
  {
    "path": "src/Exception/UnexpectedTypeException.php",
    "chars": 1763,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Exception;\n\nuse RuntimeException;\nuse Throwable;\nuse function "
  },
  {
    "path": "src/Mess.php",
    "chars": 18063,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess;\n\nuse Zakirullin\\Mess\\Enum\\TypeEnum;\nuse Zakirullin\\Mess\\Excep"
  },
  {
    "path": "src/MessInterface.php",
    "chars": 6255,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess;\n\nuse ArrayAccess;\n\n/**\n * @psalm-suppress MissingTemplatePara"
  },
  {
    "path": "src/MissingMess.php",
    "chars": 10304,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess;\n\nuse Zakirullin\\Mess\\Exception\\CannotModifyMessException;\nuse"
  },
  {
    "path": "src/TypedAccessor.php",
    "chars": 222,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\TypedAccessor;\n\nuse Zakirullin\\Mess\\Mess;\n\n/**\n * @deprecated will "
  },
  {
    "path": "src/functions.php",
    "chars": 5598,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\n{\n    use function array_keys;\n    use function count;\n    use"
  },
  {
    "path": "tests/unit/Exception/MissingKeyExceptionTest.php",
    "chars": 502,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Zakirull"
  },
  {
    "path": "tests/unit/Exception/UncastableValueExceptionTest.php",
    "chars": 695,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Zakirull"
  },
  {
    "path": "tests/unit/Exception/UnexpectedKeyTypeExceptionTest.php",
    "chars": 393,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Zakirull"
  },
  {
    "path": "tests/unit/Exception/UnexpectedTypeExceptionTest.php",
    "chars": 702,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Tests\\Exception;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Zakirull"
  },
  {
    "path": "tests/unit/MessTest.php",
    "chars": 28297,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Tests;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Zakirullin\\Mess\\Ex"
  },
  {
    "path": "tests/unit/MissingMessTest.php",
    "chars": 5123,
    "preview": "<?php\ndeclare(strict_types=1);\n\nnamespace Zakirullin\\Mess\\Tests;\n\nuse PHPUnit\\Framework\\TestCase;\nuse Zakirullin\\Mess\\Mi"
  }
]

About this extraction

This page contains the full source code of the zakirullin/mess GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 28 files (92.4 KB), approximately 24.9k tokens, and a symbol index with 354 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!