,
+) {
+ val isSupportedType = when (P::class) {
+ String::class -> true
+ Int::class -> true
+ Long::class -> true
+ Float::class -> true
+ Double::class -> true
+ Short::class -> true
+ Byte::class -> true
+ Char::class -> true
+ Boolean::class -> true
+ else -> false
+ }
+ require(isSupportedType) {
+ "Property ${property.name} of type ${P::class} is not supported as a path parameter. Must be a primitive."
+ }
+ if (typeOf().isMarkedNullable) {
+ return require(nullableElements.contains(property.name)) {
+ "Property ${property.name} of type ${P::class} is nullable, but the path parameter ${property.name} is not marked as optional."
+ }
+ }
+ return require(elements.contains(property.name)) {
+ "Property ${property.name} was not found in the path pattern."
+ }
+}
+
+public inline fun PathData.Builder.set(
+ navigationKey: T,
+ property: KProperty1,
+) {
+ val stringValue = property.get(navigationKey)?.toString() ?: return
+ set(property.name, stringValue)
+}
+
+public inline fun PathData.get(
+ property: KProperty1<*, P>,
+): P {
+ val stringValue = optional(property.name)
+ if (stringValue == null) {
+ val isNullable = typeOf().isMarkedNullable
+ if (isNullable) return null as P
+ else error("Property ${property.name} is not nullable, but no value was found")
+ }
+ return when (P::class) {
+ String::class -> stringValue as P
+ Int::class -> stringValue.toInt() as P
+ Long::class -> stringValue.toLong() as P
+ Float::class -> stringValue.toFloat() as P
+ Double::class -> stringValue.toDouble() as P
+ Short::class -> stringValue.toShort() as P
+ Byte::class -> stringValue.toByte() as P
+ Char::class -> stringValue.first() as P
+ Boolean::class -> stringValue.toBoolean() as P
+ else -> error("Type ${P::class} is not supported")
+ }
+}
+
+
+public inline fun NavigationPathBinding.Companion.createPathBinding(
+ pattern: String,
+ crossinline constructor: () -> T,
+): NavigationPathBinding {
+ val pathPattern = PathPattern.fromString(pattern)
+
+ val parameterNames = pathPattern.pathElements
+ .filterIsInstance()
+ .map { it.name }
+ .plus(pathPattern.queryElements.map { it.paramName })
+ .toSet()
+
+ require(parameterNames.size == 0) {
+ "Path pattern must not have any parameters, but found ${parameterNames.size}"
+ }
+
+ return NavigationPathBinding(
+ keyType = T::class,
+ pattern = pattern,
+ deserialize = { constructor() },
+ serialize = { }
+ )
+}
+
+public inline fun <
+ reified P1,
+ reified T : NavigationKey
+ > NavigationPathBinding.Companion.createPathBinding(
+
+ pattern: String,
+ propertyOne: KProperty1,
+ crossinline constructor: (P1) -> T,
+): NavigationPathBinding {
+ val pathPattern = PathPattern.fromString(pattern)
+
+ val parameterNames = pathPattern.pathElements
+ .filterIsInstance()
+ .map { it.name }
+ .plus(pathPattern.queryElements.map { it.paramName })
+ .toSet()
+
+ val nullableParameters = pathPattern.queryElements
+ .filterIsInstance()
+ .map { it.paramName }
+ .toSet()
+
+ require(parameterNames.size == 1) {
+ "Path pattern must have exactly one parameter, but found ${parameterNames.size}"
+ }
+
+ checkParameterIsSupported(propertyOne, parameterNames, nullableParameters)
+
+ return NavigationPathBinding(
+ keyType = T::class,
+ pattern = pathPattern,
+ deserialize = {
+ constructor(
+ it.get(propertyOne)
+ )
+ },
+ serialize = {
+ propertyOne.get(it)?.let {
+ set(propertyOne.name, it.toString())
+ }
+ }
+ )
+}
+
+public inline fun
+ NavigationPathBinding.Companion.createPathBinding(
+ pattern: String,
+ propertyOne: KProperty1,
+ propertyTwo: KProperty1,
+ crossinline constructor: (P1, P2) -> T,
+): NavigationPathBinding {
+ val pathPattern = PathPattern.fromString(pattern)
+
+ val parameterNames = pathPattern.pathElements
+ .filterIsInstance()
+ .map { it.name }
+ .plus(pathPattern.queryElements.map { it.paramName })
+ .toSet()
+
+ val nullableParameters = pathPattern.queryElements
+ .filterIsInstance()
+ .map { it.paramName }
+ .toSet()
+
+ require(parameterNames.size == 2) {
+ "Path pattern must have exactly two parameters, but found ${parameterNames.size}"
+ }
+
+ checkParameterIsSupported(propertyOne, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyTwo, parameterNames, nullableParameters)
+
+ return NavigationPathBinding(
+ keyType = T::class,
+ pattern = pathPattern,
+ deserialize = {
+ constructor(
+ it.get(propertyOne),
+ it.get(propertyTwo)
+ )
+ },
+ serialize = {
+ propertyOne.get(it)?.let {
+ set(propertyOne.name, it.toString())
+ }
+ propertyTwo.get(it)?.let {
+ set(propertyTwo.name, it.toString())
+ }
+ }
+ )
+}
+
+public inline fun
+ NavigationPathBinding.Companion.createPathBinding(
+ pattern: String,
+ propertyOne: KProperty1,
+ propertyTwo: KProperty1,
+ propertyThree: KProperty1,
+ crossinline constructor: (P1, P2, P3) -> T,
+): NavigationPathBinding {
+ val pathPattern = PathPattern.fromString(pattern)
+
+ val parameterNames = pathPattern.pathElements
+ .filterIsInstance()
+ .map { it.name }
+ .plus(pathPattern.queryElements.map { it.paramName })
+ .toSet()
+
+ val nullableParameters = pathPattern.queryElements
+ .filterIsInstance()
+ .map { it.paramName }
+ .toSet()
+
+ require(parameterNames.size == 3) {
+ "Path pattern must have exactly three parameters, but found ${parameterNames.size}"
+ }
+
+ checkParameterIsSupported(propertyOne, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyTwo, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyThree, parameterNames, nullableParameters)
+
+ return NavigationPathBinding(
+ keyType = T::class,
+ pattern = pathPattern,
+ deserialize = {
+ constructor(
+ it.get(propertyOne),
+ it.get(propertyTwo),
+ it.get(propertyThree)
+ )
+ },
+ serialize = {
+ propertyOne.get(it)?.let {
+ set(propertyOne.name, it.toString())
+ }
+ propertyTwo.get(it)?.let {
+ set(propertyTwo.name, it.toString())
+ }
+ propertyThree.get(it)?.let {
+ set(propertyThree.name, it.toString())
+ }
+ }
+ )
+}
+
+public inline fun
+ NavigationPathBinding.Companion.createPathBinding(
+ pattern: String,
+ propertyOne: KProperty1,
+ propertyTwo: KProperty1,
+ propertyThree: KProperty1,
+ propertyFour: KProperty1,
+ crossinline constructor: (P1, P2, P3, P4) -> T,
+): NavigationPathBinding {
+ val pathPattern = PathPattern.fromString(pattern)
+
+ val parameterNames = pathPattern.pathElements
+ .filterIsInstance()
+ .map { it.name }
+ .plus(pathPattern.queryElements.map { it.paramName })
+ .toSet()
+
+ val nullableParameters = pathPattern.queryElements
+ .filterIsInstance()
+ .map { it.paramName }
+ .toSet()
+
+ require(parameterNames.size == 4) {
+ "Path pattern must have exactly four parameters, but found ${parameterNames.size}"
+ }
+
+ checkParameterIsSupported(propertyOne, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyTwo, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyThree, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyFour, parameterNames, nullableParameters)
+
+ return NavigationPathBinding(
+ keyType = T::class,
+ pattern = pathPattern,
+ deserialize = {
+ constructor(
+ it.get(propertyOne),
+ it.get(propertyTwo),
+ it.get(propertyThree),
+ it.get(propertyFour)
+ )
+ },
+ serialize = {
+ propertyOne.get(it)?.let {
+ set(propertyOne.name, it.toString())
+ }
+ propertyTwo.get(it)?.let {
+ set(propertyTwo.name, it.toString())
+ }
+ propertyThree.get(it)?.let {
+ set(propertyThree.name, it.toString())
+ }
+ propertyFour.get(it)?.let {
+ set(propertyFour.name, it.toString())
+ }
+ }
+ )
+}
+
+public inline fun
+ NavigationPathBinding.Companion.createPathBinding(
+ pattern: String,
+ propertyOne: KProperty1,
+ propertyTwo: KProperty1,
+ propertyThree: KProperty1,
+ propertyFour: KProperty1,
+ propertyFive: KProperty1,
+ crossinline constructor: (P1, P2, P3, P4, P5) -> T,
+): NavigationPathBinding {
+ val pathPattern = PathPattern.fromString(pattern)
+
+ val parameterNames = pathPattern.pathElements
+ .filterIsInstance()
+ .map { it.name }
+ .plus(pathPattern.queryElements.map { it.paramName })
+ .toSet()
+
+ val nullableParameters = pathPattern.queryElements
+ .filterIsInstance()
+ .map { it.paramName }
+ .toSet()
+
+ require(parameterNames.size == 5) {
+ "Path pattern must have exactly five parameters, but found ${parameterNames.size}"
+ }
+
+ checkParameterIsSupported(propertyOne, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyTwo, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyThree, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyFour, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyFive, parameterNames, nullableParameters)
+
+ return NavigationPathBinding(
+ keyType = T::class,
+ pattern = pathPattern,
+ deserialize = {
+ constructor(
+ it.get(propertyOne),
+ it.get(propertyTwo),
+ it.get(propertyThree),
+ it.get(propertyFour),
+ it.get(propertyFive)
+ )
+ },
+ serialize = {
+ propertyOne.get(it)?.let {
+ set(propertyOne.name, it.toString())
+ }
+ propertyTwo.get(it)?.let {
+ set(propertyTwo.name, it.toString())
+ }
+ propertyThree.get(it)?.let {
+ set(propertyThree.name, it.toString())
+ }
+ propertyFour.get(it)?.let {
+ set(propertyFour.name, it.toString())
+ }
+ propertyFive.get(it)?.let {
+ set(propertyFive.name, it.toString())
+ }
+ }
+ )
+}
+
+
+public inline fun
+ NavigationPathBinding.Companion.createPathBinding(
+ pattern: String,
+ propertyOne: KProperty1,
+ propertyTwo: KProperty1,
+ propertyThree: KProperty1,
+ propertyFour: KProperty1,
+ propertyFive: KProperty1,
+ propertySix: KProperty1,
+ crossinline constructor: (P1, P2, P3, P4, P5, P6) -> T,
+): NavigationPathBinding {
+ val pathPattern = PathPattern.fromString(pattern)
+
+ val parameterNames = pathPattern.pathElements
+ .filterIsInstance()
+ .map { it.name }
+ .plus(pathPattern.queryElements.map { it.paramName })
+ .toSet()
+
+ val nullableParameters = pathPattern.queryElements
+ .filterIsInstance()
+ .map { it.paramName }
+ .toSet()
+
+ require(parameterNames.size == 6) {
+ "Path pattern must have exactly six parameters, but found ${parameterNames.size}"
+ }
+
+ checkParameterIsSupported(propertyOne, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyTwo, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyThree, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyFour, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertyFive, parameterNames, nullableParameters)
+ checkParameterIsSupported(propertySix, parameterNames, nullableParameters)
+
+ return NavigationPathBinding(
+ keyType = T::class,
+ pattern = pathPattern,
+ deserialize = {
+ constructor(
+ it.get(propertyOne),
+ it.get(propertyTwo),
+ it.get(propertyThree),
+ it.get(propertyFour),
+ it.get(propertyFive),
+ it.get(propertySix)
+ )
+ },
+ serialize = {
+ propertyOne.get(it)?.let {
+ set(propertyOne.name, it.toString())
+ }
+ propertyTwo.get(it)?.let {
+ set(propertyTwo.name, it.toString())
+ }
+ propertyThree.get(it)?.let {
+ set(propertyThree.name, it.toString())
+ }
+ propertyFour.get(it)?.let {
+ set(propertyFour.name, it.toString())
+ }
+ propertyFive.get(it)?.let {
+ set(propertyFive.name, it.toString())
+ }
+ propertySix.get(it)?.let {
+ set(propertySix.name, it.toString())
+ }
+ }
+ )
+}
+
+public inline fun
+ NavigationPathBinding.Companion.createPathBinding(
+ pattern: String,
+ propertyOne: KProperty1,
+ propertyTwo: KProperty1,
+ propertyThree: KProperty1