public static function appendFromString(FieldsBuilderInterface $builder, $input, $start = 0, $end = null)
	{
		if ($end === null) {
			$end = strlen($input);
		}

		while ($start < $end) {
			$start = self::ltrim($input, $start, $end);

			if ($start >= $end) {
				return $builder;
			}

			$p = self::pos($input, $start, $end, ".{,");

			if ($p === $end) {
				$p = self::rtrim($input, $start, $p);
				$builder = $builder->appendField(substr($input, $start, $p - $start));

				$start = $end;

			} else {
				$fieldName = substr($input, $start, self::rtrim($input, $start, $p) - $start);

				switch ($input[$p]) {
					case ".":
						for ($q = self::pos($input, $p, $end, "{,"); $q < $end && $input[$q] === "{"; ++$q) {
							$q = self::findBalancedRightBrace($input, $q, $end);
						}
						$builder = $builder->appendFields(
							$fieldName,
							self::appendFromString($builder->builder($fieldName), $input, $p + 1, $q)
						);

						$start = $q + 1;
						break;

					case "{":
						$balancedRightBrace = self::findBalancedRightBrace($input, $p, $end);
						if ($balancedRightBrace + 1 < $end && $input[$balancedRightBrace + 1] !== ",") {
							throw new \InvalidArgumentException(
								"Invalid fields string '{$input}' - expected ',' at position " . ($balancedRightBrace + 1) . "."
							);
						}
						$builder = $builder->appendFields(
							$fieldName,
							self::appendFromString($builder->builder($fieldName), $input, $p + 1, $balancedRightBrace)
						);
						$start = $balancedRightBrace + 2;
						break;

					case ",":
						$builder = $builder->appendField($fieldName);
						$start = $p + 1;
						break;

					default:
						throw new \LogicException("Unhandled char '{$input[$p]}'.");
				}
			}
		}

		return $builder;
	}