internal static string ToQueryString()

in src/Elastic.Transport/Extensions/NameValueCollectionExtensions.cs [18:68]


	internal static string ToQueryString(this NameValueCollection nv)
	{
		if (nv == null || nv.AllKeys.Length == 0) return string.Empty;

		var maxLength = 1 + nv.AllKeys.Length - 1; // account for '?', and any required '&' chars
		foreach (var key in nv.AllKeys)
		{
			var bytes = Encoding.UTF8.GetByteCount(key) + Encoding.UTF8.GetByteCount(nv[key] ?? string.Empty);
			var maxEncodedSize = bytes * 3; // worst case, assume all bytes are URL escaped to 3 chars
			maxLength += 1 + maxEncodedSize; // '=' + encoded chars
		}

		// prefer stack allocated array for short lengths
		// note: renting for larger lengths is slightly more efficient since no zeroing occurs
		char[] rentedFromPool = null;
		var buffer = maxLength > MaxCharsOnStack
			? rentedFromPool = ArrayPool<char>.Shared.Rent(maxLength)
			: stackalloc char[maxLength];

		try
		{
			var position = 0;
			buffer[position++] = '?';

			foreach (var key in nv.AllKeys)
			{
				if (position != 1)
					buffer[position++] = '&';

				var escapedKey = Uri.EscapeDataString(key);
				escapedKey.AsSpan().CopyTo(buffer.Slice(position));
				position += escapedKey.Length;

				var value = nv[key];

				if (value.IsNullOrEmpty()) continue;

				buffer[position++] = '=';
				var escapedValue = Uri.EscapeDataString(value);
				escapedValue.AsSpan().CopyTo(buffer.Slice(position));
				position += escapedValue.Length;
			}

			return buffer.Slice(0, position).ToString();
		}
		finally
		{
			if (rentedFromPool != null)
				ArrayPool<char>.Shared.Return(rentedFromPool, clearArray: false);
		}
	}