public function transfer($fromObjectOrArray, &$toObjectOrArray, $mapper = null, $fromSubset = '', $toSubset = '')
	{
		$result = [];
		$data = null;

		//Extract data array
		switch (true)
		{
			case is_object($fromObjectOrArray):
				$fromMetadata = $this->metadataReader->getMetadata(get_class($fromObjectOrArray), $fromSubset);
				$fromHydrator = $this->getHydrator($fromMetadata);
				$data = $fromHydrator->extract($fromObjectOrArray);
				break;
			case is_array($fromObjectOrArray):
				$data = &$fromObjectOrArray;
				break;
			default:
				throw new \InvalidArgumentException('Data transfer is possible only from object or array.');
		}

		//Map data array
		if (is_callable($mapper) || ($mapper instanceof Mapper\MapperInterface))
		{
			$data = $mapper($data);
			if (!is_array($data))
			{
				throw new \LogicException(
					sprintf('Invalid mapping: expecting array result, not %s.', gettype($data))
				);
			}
		}

		//Validate and hydrate data array
		switch (true)
		{
			case is_object($toObjectOrArray):
				$toMetadata = $this->metadataReader->getMetadata(get_class($toObjectOrArray), $toSubset);
				$toHydrator = $this->getHydrator($toMetadata);
				$validator = $this->getValidator($toMetadata);

				$result = $validator->validate(self::arrayTransfer($toHydrator->extract($toObjectOrArray), $data));
				if (empty($result))
				{
					$toObjectOrArray = $toHydrator->hydrate($data, $toObjectOrArray);
				}
				break;
			case is_array($toObjectOrArray):
				$toObjectOrArray = self::arrayTransfer($toObjectOrArray, $data);
				break;
			default:
				throw new \InvalidArgumentException('Data transfer is possible only to object or array.');
		}

		return $result;
	}