<?php
 namespace MongoDB;
 use Exception;
 use MongoDB\BSON\Serializable;
 use MongoDB\Driver\Manager;
 use MongoDB\Driver\ReadPreference;
 use MongoDB\Driver\Server;
 use MongoDB\Driver\Session;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Exception\RuntimeException;
 use MongoDB\Operation\WithTransaction;
 use ReflectionClass;
 use ReflectionException;
 use function end;
 use function get_object_vars;
 use function in_array;
 use function is_array;
 use function is_object;
 use function is_string;
 use function key;
 use function MongoDB\BSON\fromPHP;
 use function MongoDB\BSON\toPHP;
 use function reset;
 use function substr;
 function apply_type_map_to_document($document, array $typeMap) {
 if (! is_array($document) && ! is_object($document)) {
 throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
 }
 return toPHP(fromPHP($document), $typeMap);
 }
 function generate_index_name($document) {
 if ($document instanceof Serializable) {
 $document = $document->bsonSerialize();
 }
 if (is_object($document)) {
 $document = get_object_vars($document);
 }
 if (! is_array($document)) {
 throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
 }
 $name = '';
 foreach ($document as $field => $type) {
 $name .= ($name != '' ? '_' : '') . $field . '_' . $type;
 }
 return $name;
 }
 function is_first_key_operator($document) {
 if ($document instanceof Serializable) {
 $document = $document->bsonSerialize();
 }
 if (is_object($document)) {
 $document = get_object_vars($document);
 }
 if (! is_array($document)) {
 throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
 }
 reset($document);
 $firstKey = (string) key($document);
 return isset($firstKey[0]) && $firstKey[0] === '$';
 }
 function is_pipeline($pipeline) {
 if (! is_array($pipeline)) {
 return false;
 }
 if ($pipeline === []) {
 return false;
 }
 $expectedKey = 0;
 foreach ($pipeline as $key => $stage) {
 if (! is_array($stage) && ! is_object($stage)) {
 return false;
 }
 if ($expectedKey !== $key) {
 return false;
 }
 $expectedKey++;
 $stage = (array) $stage;
 reset($stage);
 $key = key($stage);
 if (! isset($key[0]) || $key[0] !== '$') {
 return false;
 }
 }
 return true;
 }
 function is_in_transaction(array $options) {
 if (isset($options['session']) && $options['session'] instanceof Session && $options['session']->isInTransaction()) {
 return true;
 }
 return false;
 }
 function is_last_pipeline_operator_write(array $pipeline) {
 $lastOp = end($pipeline);
 if ($lastOp === false) {
 return false;
 }
 $lastOp = (array) $lastOp;
 return in_array(key($lastOp), ['$out', '$merge'], true);
 }
 function is_mapreduce_output_inline($out) {
 if (! is_array($out) && ! is_object($out)) {
 return false;
 }
 if ($out instanceof Serializable) {
 $out = $out->bsonSerialize();
 }
 if (is_object($out)) {
 $out = get_object_vars($out);
 }
 if (! is_array($out)) {
 throw InvalidArgumentException::invalidType('$out', $out, 'array or object');
 }
 reset($out);
 return key($out) === 'inline';
 }
 function server_supports_feature(Server $server, $feature) {
 $info = $server->getInfo();
 $maxWireVersion = isset($info['maxWireVersion']) ? (integer) $info['maxWireVersion'] : 0;
 $minWireVersion = isset($info['minWireVersion']) ? (integer) $info['minWireVersion'] : 0;
 return $minWireVersion <= $feature && $maxWireVersion >= $feature;
 }
 function is_string_array($input) {
 if (! is_array($input)) {
 return false;
 }
 foreach ($input as $item) {
 if (! is_string($item)) {
 return false;
 }
 }
 return true;
 }
 function recursive_copy($element) {
 if (is_array($element)) {
 foreach ($element as $key => $value) {
 $element[$key] = recursive_copy($value);
 }
 return $element;
 }
 if (! is_object($element)) {
 return $element;
 }
 if (! (new ReflectionClass($element))->isCloneable()) {
 return $element;
 }
 return clone $element;
 }
 function create_field_path_type_map(array $typeMap, $fieldPath) {
 if (isset($typeMap['fieldPaths']) && is_array($typeMap['fieldPaths'])) {
 $fieldPaths = $typeMap['fieldPaths'];
 $typeMap['fieldPaths'] = [];
 foreach ($fieldPaths as $existingFieldPath => $type) {
 $typeMap['fieldPaths'][$fieldPath . '.' . $existingFieldPath] = $type;
 }
 }
 if (isset($typeMap['root'])) {
 $typeMap['fieldPaths'][$fieldPath] = $typeMap['root'];
 }
 if (substr($fieldPath, -2, 2) === '.$') {
 $typeMap['fieldPaths'][substr($fieldPath, 0, -2)] = 'array';
 }
 $typeMap['root'] = 'object';
 return $typeMap;
 }
 function with_transaction(Session $session, callable $callback, array $transactionOptions = []) {
 $operation = new WithTransaction($callback, $transactionOptions);
 $operation->execute($session);
 }
 function extract_session_from_options(array $options) {
 if (! isset($options['session']) || ! $options['session'] instanceof Session) {
 return null;
 }
 return $options['session'];
 }
 function extract_read_preference_from_options(array $options) {
 if (! isset($options['readPreference']) || ! $options['readPreference'] instanceof ReadPreference) {
 return null;
 }
 return $options['readPreference'];
 }
 function select_server(Manager $manager, array $options) {
 $session = extract_session_from_options($options);
 if ($session instanceof Session && $session->getServer() !== null) {
 return $session->getServer();
 }
 $readPreference = extract_read_preference_from_options($options);
 if (! $readPreference instanceof ReadPreference) {
 $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
 }
 return $manager->selectServer($readPreference);
 }
 